diff options
author | Michael Goddard <michael.goddard@nokia.com> | 2011-06-29 13:38:46 +1000 |
---|---|---|
committer | Michael Goddard <michael.goddard@nokia.com> | 2011-06-29 13:38:46 +1000 |
commit | 2a34e88c1e1ced28e75c487cd13402e1c9cf9fa3 (patch) | |
tree | e6c1b770c5c47212792a1f9344fa034ea3e54c44 /src/plugins/symbian | |
download | qtmultimedia-2a34e88c1e1ced28e75c487cd13402e1c9cf9fa3.tar.gz |
Initial copy of QtMultimediaKit.
Comes from original repo, with SHA1:
2c82d5611655e5967f5c5095af50c0991c4378b2
Diffstat (limited to 'src/plugins/symbian')
166 files changed, 38121 insertions, 0 deletions
diff --git a/src/plugins/symbian/ecam/camera_s60.pri b/src/plugins/symbian/ecam/camera_s60.pri new file mode 100644 index 000000000..beb44db8d --- /dev/null +++ b/src/plugins/symbian/ecam/camera_s60.pri @@ -0,0 +1,157 @@ +INCLUDEPATH += $$PWD + +include (../videooutput/videooutput.pri) + +# Camera Service +DEFINES += QMEDIA_SYMBIAN_CAMERA + +# S60 3.1 platform +contains(S60_VERSION, 3.1) { + DEFINES += S60_31_PLATFORM + DEFINES *= S60_3X_PLATFORM +} + +# S60 3.2 platform +contains(S60_VERSION, 3.2) { + DEFINES += S60_32_PLATFORM + DEFINES *= S60_3X_PLATFORM +} + +# S60 5.0 platform +!contains(DEFINES, S60_31_PLATFORM) { + !contains(DEFINES, S60_32_PLATFORM) { + !contains(DEFINES, SYMBIAN_3_PLATFORM) { + DEFINES += S60_50_PLATFORM + } + } +} + +# Symbian 3 platform +contains(DEFINES, VIDEOOUTPUT_GRAPHICS_SURFACES) { + DEFINES += SYMBIAN_3_PLATFORM +} + +# AutoFocusing (CamAutoFocus) from ForumNokia example +contains(symbian_camera_camautofocus_enabled, yes) { + exists($${EPOCROOT}epoc32\\include\\CCamAutoFocus.h) { + message ("CameraBE: Using S60 3.1 autofocusing") + MMP_RULES += \ + "$${LITERAL_HASH}ifdef WINSCW" \ + "LIBRARY camautofocus.lib" \ + "$${LITERAL_HASH}else" \ + "STATICLIBRARY camautofocus_s.lib" \ + "$${LITERAL_HASH}endif // WINS" \ + "MACRO S60_CAM_AUTOFOCUS_SUPPORT" + } +} + +# ECam AdvancedSettings +contains(symbian_camera_ecamadvsettings_enabled, yes) { + exists($${EPOCROOT}epoc32\\include\\ecamadvancedsettings.h) { + MMP_RULES += \ + "$${LITERAL_HASH}ifndef WINSCW" \ + "LIBRARY ecamadvsettings.lib" \ + "MACRO USE_S60_32_ECAM_ADVANCED_SETTINGS_HEADER" \ + "$${LITERAL_HASH}endif" + message("CameraBE: Using from S60 3.2 CCameraAdvancedSettings header") + } + exists($${EPOCROOT}epoc32\\include\\ecamadvsettings.h) { + symbian:LIBS += -lecamadvsettings + DEFINES += USE_S60_50_ECAM_ADVANCED_SETTINGS_HEADER + message("CameraBE: Using CCameraAdvancedSettings header from S60 5.0 or later") + } +} + +# DevVideo API Check (Requires both, DevVideoPlay and DevVideoRecord plugins): +# DevVideoConstants has been problematic since not being included in SDK plugins +# For S60 5.0 this has changed with plugin extension 1.1 +# But for S60 3.2 this is still a problem +contains(symbian_camera_devvideorecord_enabled, yes) { + exists($${EPOCROOT}epoc32\\include\\mmf\\devvideo\\devvideorecord.h) { + exists($${EPOCROOT}epoc32\\include\\mmf\\devvideo\\devvideobase.h) { + exists($${EPOCROOT}epoc32\\include\\mmf\\devvideo\\devvideoconstants.h) { + symbian:LIBS += -ldevvideo + DEFINES += S60_DEVVIDEO_RECORDING_SUPPORTED + message("CameraBE: Devvideo API supported") + } + } + } +} + +# ECam Snapshot API: +contains(symbian_camera_snapshot_enabled, yes) { + exists($${EPOCROOT}epoc32\\include\\platform\\ecam\\camerasnapshot.h) { + DEFINES += ECAM_PREVIEW_API + message("CameraBE: Using CCameraSnapshot API") + symbian:LIBS += -lecamsnapshot + } else { + message("CameraBE: Using custom snapshot proving methods") + } +} else { + message("CameraBE: Using custom snapshot proving methods") +} + +# Libraries: +symbian:LIBS += -lfbscli \ + -lmediaclientvideo \ + -lecam \ + -lbafl \ + -lPlatformEnv \ + -lcharconv \ + -lconvnames \ + -lgb2312_shared \ + -ljisx0201 \ + -ljisx0208 \ + -lmmfcontrollerframework \ + -lfbscli \ + -lefsrv \ + -lcone \ + -lws32 \ + -limageconversion + +# Source: +HEADERS += $$PWD/s60cameraconstants.h \ + $$PWD/s60cameralockscontrol.h \ + $$PWD/s60camerafocuscontrol.h \ + $$PWD/s60cameraexposurecontrol.h \ + $$PWD/s60cameraflashcontrol.h \ + $$PWD/s60cameracontrol.h \ + $$PWD/s60mediarecordercontrol.h \ + $$PWD/s60videocapturesession.h \ + $$PWD/s60imagecapturesession.h \ + $$PWD/s60mediacontainercontrol.h \ + $$PWD/s60videoencodercontrol.h \ + $$PWD/s60audioencodercontrol.h \ + $$PWD/s60cameraservice.h \ + $$PWD/s60cameraimageprocessingcontrol.h \ + $$PWD/s60cameraimagecapturecontrol.h \ + $$PWD/s60videodevicecontrol.h \ + $$PWD/s60imageencodercontrol.h \ + $$PWD/s60camerasettings.h \ + $$PWD/s60cameraengine.h \ + $$PWD/s60cameraviewfinderengine.h \ + $$PWD/s60cameraengineobserver.h \ + $$PWD/s60videorenderercontrol.h + +SOURCES += $$PWD/s60cameralockscontrol.cpp \ + $$PWD/s60camerafocuscontrol.cpp \ + $$PWD/s60cameraexposurecontrol.cpp \ + $$PWD/s60cameraflashcontrol.cpp \ + $$PWD/s60cameracontrol.cpp \ + $$PWD/s60mediarecordercontrol.cpp \ + $$PWD/s60videocapturesession.cpp \ + $$PWD/s60imagecapturesession.cpp \ + $$PWD/s60mediacontainercontrol.cpp \ + $$PWD/s60videoencodercontrol.cpp \ + $$PWD/s60audioencodercontrol.cpp \ + $$PWD/s60cameraservice.cpp \ + $$PWD/s60cameraimageprocessingcontrol.cpp \ + $$PWD/s60cameraimagecapturecontrol.cpp \ + $$PWD/s60videodevicecontrol.cpp \ + $$PWD/s60imageencodercontrol.cpp \ + $$PWD/s60camerasettings.cpp \ + $$PWD/s60cameraengine.cpp \ + $$PWD/s60cameraviewfinderengine.cpp \ + $$PWD/s60videorenderercontrol.cpp + +# End of file diff --git a/src/plugins/symbian/ecam/ecam.pro b/src/plugins/symbian/ecam/ecam.pro new file mode 100644 index 000000000..31f30b61c --- /dev/null +++ b/src/plugins/symbian/ecam/ecam.pro @@ -0,0 +1,40 @@ +###################################################################### +# +# Mobility API project - Symbian Camera backend +# +###################################################################### + +TEMPLATE = lib +CONFIG += plugin + +TARGET = $$qtLibraryTarget(qtmultimediakit_ecamengine) +PLUGIN_TYPE = mediaservice +include (../../../../common.pri) + +CONFIG += mobility +MOBILITY += multimedia + +# Include here so that all defines are added here also +include(camera_s60.pri) + +DEPENDPATH += . + +INCLUDEPATH += . \ + $${SOURCE_DIR}/include \ + $${SOURCE_DIR}/src/multimedia \ + $${SOURCE_DIR}/src/multimedia/audio \ + $${SOURCE_DIR}/src/multimedia/video \ + $${SOURCE_DIR} + +HEADERS += s60cameraserviceplugin.h +SOURCES += s60cameraserviceplugin.cpp + +load(data_caging_paths) +TARGET.EPOCALLOWDLLDATA = 1 +TARGET.UID3 = 0x2002BFC2 +TARGET.CAPABILITY = ALL -TCB + +# Make a sis package from plugin + api + stub (plugin) +pluginDep.sources = $${TARGET}.dll +pluginDep.path = $${QT_PLUGINS_BASE_DIR}/$${PLUGIN_TYPE} +DEPLOYMENT += pluginDep diff --git a/src/plugins/symbian/ecam/s60audioencodercontrol.cpp b/src/plugins/symbian/ecam/s60audioencodercontrol.cpp new file mode 100644 index 000000000..bd8f0147d --- /dev/null +++ b/src/plugins/symbian/ecam/s60audioencodercontrol.cpp @@ -0,0 +1,159 @@ +/**************************************************************************** +** +** 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 "s60audioencodercontrol.h" +#include "s60videocapturesession.h" + +S60AudioEncoderControl::S60AudioEncoderControl(QObject *parent) : + QAudioEncoderControl(parent) +{ +} + +S60AudioEncoderControl::S60AudioEncoderControl(S60VideoCaptureSession *session, QObject *parent) : + QAudioEncoderControl(parent) +{ + m_session = session; +} + +S60AudioEncoderControl::~S60AudioEncoderControl() +{ +} + +QStringList S60AudioEncoderControl::supportedAudioCodecs() const +{ + return m_session->supportedAudioCaptureCodecs(); +} + +QString S60AudioEncoderControl::codecDescription(const QString &codecName) const +{ + // According to ForumNokia MMF camcorder plugin supports AAC, AMR and QCELP + // QCELP is speech codec and can be discarded + if (qstrcmp(codecName.toLocal8Bit().constData(), "audio/aac") == 0) + return QLatin1String("Advanced Audio Coding"); + else if (qstrcmp(codecName.toLocal8Bit().constData(), "audio/amr") == 0) + return QLatin1String("Adaptive Multi-Rate Audio Codec"); + + return QString(); +} + +QStringList S60AudioEncoderControl::supportedEncodingOptions(const QString &codec) const +{ + // Possible settings: EncodingMode, Codec, BitRate, ChannelCount, SampleRate, Quality + // Possible (codec specific) Options: None + Q_UNUSED(codec); + return QStringList(); +} + +QVariant S60AudioEncoderControl::encodingOption(const QString &codec, const QString &name) const +{ + // Possible settings: EncodingMode, Codec, BitRate, ChannelCount, SampleRate, Quality + // Possible (codec specific) Options: None + Q_UNUSED(codec); + Q_UNUSED(name); + return QVariant(); +} + +void S60AudioEncoderControl::setEncodingOption( + const QString &codec, const QString &name, const QVariant &value) +{ + m_session->setError(KErrNotSupported, tr("Audio encoding option is not supported")); + + // The audio settings can currently be set only using setAudioSettings() function + Q_UNUSED(value) + Q_UNUSED(codec) + Q_UNUSED(name) +} + +QList<int> S60AudioEncoderControl::supportedSampleRates( + const QAudioEncoderSettings &settings, bool *continuous) const +{ + return m_session->supportedSampleRates(settings, continuous); +} + +QAudioEncoderSettings S60AudioEncoderControl::audioSettings() const +{ + QAudioEncoderSettings settings; + m_session->audioEncoderSettings(settings); + + return settings; +} + +void S60AudioEncoderControl::setAudioSettings(const QAudioEncoderSettings &settings) +{ + // Notify that settings have been implicitly set and there's no need to + // initialize them in case camera is changed + m_session->notifySettingsSet(); + + // Quality defines SampleRate/BitRate combination if either or both are missing + if (settings.codec().isEmpty()) { // Empty settings + m_session->setAudioCaptureQuality(settings.quality(), S60VideoCaptureSession::EOnlyAudioQuality); + + } else if (settings.bitRate() == -1 && settings.sampleRate() != -1) { // Only SampleRate set + m_session->setAudioCaptureCodec(settings.codec()); + m_session->setAudioChannelCount(settings.channelCount()); + m_session->setAudioSampleRate(settings.sampleRate()); + m_session->setAudioEncodingMode(settings.encodingMode()); + m_session->setAudioCaptureQuality(settings.quality(), S60VideoCaptureSession::EAudioQualityAndSampleRate); + + } else if (settings.bitRate() != -1 && settings.sampleRate() == -1) { // Only BitRate set + m_session->setAudioCaptureCodec(settings.codec()); + m_session->setAudioChannelCount(settings.channelCount()); + m_session->setAudioBitRate(settings.bitRate()); + m_session->setAudioEncodingMode(settings.encodingMode()); + m_session->setAudioCaptureQuality(settings.quality(), S60VideoCaptureSession::EAudioQualityAndBitRate); + + } else if (settings.bitRate() == -1 && settings.sampleRate() == -1) { // No BitRate or SampleRate set + m_session->setAudioCaptureCodec(settings.codec()); + m_session->setAudioChannelCount(settings.channelCount()); + m_session->setAudioEncodingMode(settings.encodingMode()); + m_session->setAudioCaptureQuality(settings.quality(), S60VideoCaptureSession::EOnlyAudioQuality); + + } else { // Both SampleRate and BitRate set + m_session->setAudioCaptureCodec(settings.codec()); + m_session->setAudioChannelCount(settings.channelCount()); + m_session->setAudioSampleRate(settings.sampleRate()); + m_session->setAudioBitRate(settings.bitRate()); + m_session->setAudioEncodingMode(settings.encodingMode()); + m_session->setAudioCaptureQuality(settings.quality(), S60VideoCaptureSession::ENoAudioQuality); + } +} + +// End of file diff --git a/src/plugins/symbian/ecam/s60audioencodercontrol.h b/src/plugins/symbian/ecam/s60audioencodercontrol.h new file mode 100644 index 000000000..db6ada5d1 --- /dev/null +++ b/src/plugins/symbian/ecam/s60audioencodercontrol.h @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef S60AUDIOENCODERCONTROL_H +#define S60AUDIOENCODERCONTROL_H + +#include <QtCore/qstringlist.h> +#include <QtCore/qmap.h> + +#include <qaudioencodercontrol.h> + +QT_USE_NAMESPACE + +class S60VideoCaptureSession; + +/* + * Control for audio settings when recording video using QMediaRecorder. + */ +class S60AudioEncoderControl : public QAudioEncoderControl +{ + Q_OBJECT + +public: // Constructor & Destructor + + S60AudioEncoderControl(QObject *parent = 0); + S60AudioEncoderControl(S60VideoCaptureSession *session, QObject *parent = 0); + virtual ~S60AudioEncoderControl(); + +public: // QAudioEncoderControl + + // Audio Codec + QStringList supportedAudioCodecs() const; + QString codecDescription(const QString &codecName) const; + + // Sample Rate + QList<int> supportedSampleRates(const QAudioEncoderSettings &settings, bool *continuous = 0) const; + + // Audio Settings + QAudioEncoderSettings audioSettings() const; + void setAudioSettings(const QAudioEncoderSettings &settings); + + // Encoding Option + QStringList supportedEncodingOptions(const QString &codec) const; + QVariant encodingOption(const QString &codec, const QString &name) const; + void setEncodingOption(const QString &codec, const QString &name, const QVariant &value); + +private: // Data + + S60VideoCaptureSession* m_session; +}; + +#endif // S60AUDIOENCODERCONTROL_H diff --git a/src/plugins/symbian/ecam/s60cameraconstants.h b/src/plugins/symbian/ecam/s60cameraconstants.h new file mode 100644 index 000000000..4b415c3e8 --- /dev/null +++ b/src/plugins/symbian/ecam/s60cameraconstants.h @@ -0,0 +1,257 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef S60CAMERACONSTANTS_H +#define S60CAMERACONSTANTS_H + +//============================================================================= + +// GENERAL SETTINGS + +#define KDefaultCameraDevice 0 +#define KECamCameraPriority 0 +#define KInactivityTimerTimeout 30000 // msec +#define KSymbianFineResolutionFactor 100.0 +#define KDefaultOpticalZoom 1.0 +#define KDefaultDigitalZoom 1.0 +#define KSmoothZoomStep 1 +#define KDefaultFocusMode QCameraFocus::AutoFocus + +#define KDefaultViewfinderSize QSize(320,240) +#define KDefaultSizePreview_Normal TSize(640,480) +#define KDefaultSizePreview_Wide TSize(640,360) +#define KDefaultSizePreview_CIF TSize(352,288) +#define KDefaultSizePreview_PAL TSize(640,512) +#define KDefaultSizePreview_NTSC TSize(640,426) +#define KDefaultFormatPreview CCamera::EFormatFbsBitmapColor16MU +#define KViewfinderFrameRate 30 +#define KMaxVFErrorsSignalled 3 + +//============================================================================= + +// IMAGE SETTINGS + +#define KDefaultImagePath QLatin1String("c:\\Data\\Images") +#define KDefaultImageFileName QLatin1String("image.jpg") +#define KDefaultImageCodec QLatin1String("image/jpeg") +#define KDefaultImageFormatPrimaryCam CCamera::EFormatExif +#ifdef SYMBIAN_3_PLATFORM +#define KDefaultImageFormatSecondaryCam CCamera::EFormatExif +#define KDefaultImageResolution QSize(3264, 2448) +#else // Pre-Symbian3 Platforms +#define KDefaultImageFormatSecondaryCam CCamera::EFormatFbsBitmapColor64K +#define KDefaultImageResolution QSize(2048, 1536) +#endif // SYMBIAN_3_PLATFORM +#define KSymbianImageQualityCoefficient 25 +// This must be divisible by 4 and creater or equal to 8 +#define KSnapshotDownScaleFactor 8 +#define KSnapshotMinWidth 640 +#define KSnapshotMinHeight 360 +#define KJpegQualityVeryLow 40 +#define KJpegQualityLow 50 +#define KJpegQualityNormal 75 +#define KJpegQualityHigh 85 +#define KJpegQualityVeryHigh 95 +#define KDefaultImageQuality KJpegQualityHigh + +//============================================================================= + +// VIDEO SETTINGS + +// ================ +// General settings +// ================ + +// Dummy file name to execute CVideoRecorderUtility::OpenFileL() without +// knowing the actual outputLocation. This is needed to be able to query/set +// supported video settings. +_LIT(KDummyVideoFile, "c:\\data\\temp"); + +// Default container MIME type +#define KMimeTypeDefaultContainer QLatin1String("video/mp4") +#define KDefaultVideoPath QLatin1String("c:\\Data\\Videos") +#define KDefaultVideoFileName QLatin1String("video.mp4") +#define KDurationChangedInterval 1000 // 1 second + +// ============== +// Audio Settings +// ============== + +// Default audio codec MIME type +#define KMimeTypeDefaultAudioCodec QLatin1String("audio/aac") + +// Default audio settings for video recording +#define KDefaultChannelCount -1 // Not Supported on Symbian +#define KDefaultBitRate 32000 // 32kbps +#define KDefaultSampleRate -1 // Not Supported on Symbian + +// ============== +// Video Settings +// ============== + +// Default video codec MIME type +#ifdef SYMBIAN_3_PLATFORM + // H.264: BaselineProfile Level 3.1, Max resolution: 1280x720 + #define KMimeTypeDefaultVideoCodec QLatin1String("video/H264; profile-level-id=42801F") +#else + // MPEG-4: Simple Profile, Level 4, Max resolution: 640x480 + #define KMimeTypeDefaultVideoCodec QLatin1String("video/mp4v-es; profile-level-id=4") +#endif + +// Maximum resolutions for encoder MIME Types +// H.263 +#define KResH263 QSize(176,144); +#define KResH263_Profile0 QSize(176,144); +#define KResH263_Profile0_Level10 QSize(176,144); +#define KResH263_Profile0_Level20 QSize(352,288); +#define KResH263_Profile0_Level30 QSize(352,288); +#define KResH263_Profile0_Level40 QSize(352,288); +#define KResH263_Profile0_Level45 QSize(176,144); +#define KResH263_Profile0_Level50 QSize(352,288); +#define KResH263_Profile3 QSize(176,144); +// MPEG-4 +#define KResMPEG4 QSize(176,144); +#define KResMPEG4_PLID_1 QSize(176,144); +#define KResMPEG4_PLID_2 QSize(352,288); +#define KResMPEG4_PLID_3 QSize(352,288); +#define KResMPEG4_PLID_4 QSize(640,480); +#define KResMPEG4_PLID_5 QSize(720,576); +#define KResMPEG4_PLID_6 QSize(1280,720); +#define KResMPEG4_PLID_8 QSize(176,144); +#define KResMPEG4_PLID_9 QSize(176,144); +// H.264 (Baseline Profile, same resolutions apply to Main and High Profile) +#define KResH264 QSize(176,144); +#define KResH264_PLID_42800A QSize(176,144); +#define KResH264_PLID_42900B QSize(176,144); +#define KResH264_PLID_42800B QSize(352,288); +#define KResH264_PLID_42800C QSize(352,288); +#define KResH264_PLID_42800D QSize(352,288); +#define KResH264_PLID_428014 QSize(352,288); +#define KResH264_PLID_428015 QSize(352,288); +#define KResH264_PLID_428016 QSize(640,480); +#define KResH264_PLID_42801E QSize(640,480); +#define KResH264_PLID_42801F QSize(1280,720); +#define KResH264_PLID_428020 QSize(1280,720); +#define KResH264_PLID_428028 QSize(1920,1080); + +// Maximum framerates for encoder MIME Types +// H.263 +#define KFrR_H263 qreal(15); +#define KFrR_H263_Profile0 qreal(15); +#define KFrR_H263_Profile0_Level10 qreal(15); +#define KFrR_H263_Profile0_Level20 qreal(15); +#define KFrR_H263_Profile0_Level30 qreal(30); +#define KFrR_H263_Profile0_Level40 qreal(30); +#define KFrR_H263_Profile0_Level45 qreal(15); +#define KFrR_H263_Profile0_Level50 qreal(15); +#define KFrR_H263_Profile3 qreal(15); +// MPEG-4 +#define KFrR_MPEG4 qreal(15); +#define KFrR_MPEG4_PLID_1 qreal(15); +#define KFrR_MPEG4_PLID_2 qreal(15); +#define KFrR_MPEG4_PLID_3 qreal(30); +// This is a workaround for a known platform bug +#if (defined(S60_31_PLATFORM) | defined(S60_32_PLATFORM)) +#define KFrR_MPEG4_PLID_4 qreal(15); +#else // All other platforms +#define KFrR_MPEG4_PLID_4 qreal(30); +#endif // S60 3.1 or 3.2 +#define KFrR_MPEG4_PLID_5 qreal(30); +#define KFrR_MPEG4_PLID_6 qreal(30); +#define KFrR_MPEG4_PLID_8 qreal(15); +#define KFrR_MPEG4_PLID_9 qreal(15); +// H.264 (Baseline Profile, same framerates apply to Main and High Profile) +#define KFrR_H264 qreal(15); +#define KFrR_H264_PLID_42800A qreal(15); +#define KFrR_H264_PLID_42900B qreal(15); +#define KFrR_H264_PLID_42800B qreal(7.5); +#define KFrR_H264_PLID_42800C qreal(15); +#define KFrR_H264_PLID_42800D qreal(30); +#define KFrR_H264_PLID_428014 qreal(30); +#define KFrR_H264_PLID_428015 qreal(50); +#define KFrR_H264_PLID_428016 qreal(16.9); +#define KFrR_H264_PLID_42801E qreal(33.8); +#define KFrR_H264_PLID_42801F qreal(30); +#define KFrR_H264_PLID_428020 qreal(60); +#define KFrR_H264_PLID_428028 qreal(30); + +// Maximum bitrates for encoder MIME Types +// H.263 +#define KBiR_H263 int(64000); +#define KBiR_H263_Profile0 int(64000); +#define KBiR_H263_Profile0_Level10 int(64000); +#define KBiR_H263_Profile0_Level20 int(128000); +#define KBiR_H263_Profile0_Level30 int(384000); +#define KBiR_H263_Profile0_Level40 int(2048000); +#define KBiR_H263_Profile0_Level45 int(128000); +#define KBiR_H263_Profile0_Level50 int(4096000); +#define KBiR_H263_Profile3 int(64000); +// MPEG-4 +#define KBiR_MPEG4 int(64000); +#define KBiR_MPEG4_PLID_1 int(64000); +#define KBiR_MPEG4_PLID_2 int(128000); +#define KBiR_MPEG4_PLID_3 int(384000); +// This is a workaround for a known platform bug +#if (defined(S60_31_PLATFORM) | defined(S60_32_PLATFORM)) +#define KBiR_MPEG4_PLID_4 int(2000000); +#else // All other platforms +#define KBiR_MPEG4_PLID_4 int(4000000); +#endif // S60 3.1 or 3.2 +#define KBiR_MPEG4_PLID_5 int(8000000); +#define KBiR_MPEG4_PLID_6 int(12000000); +#define KBiR_MPEG4_PLID_8 int(64000); +#define KBiR_MPEG4_PLID_9 int(128000); +// H.264 (Baseline Profile, same bitrates apply to Main and High Profile) +#define KBiR_H264 int(64000); +#define KBiR_H264_PLID_42800A int(64000); +#define KBiR_H264_PLID_42900B int(128000); +#define KBiR_H264_PLID_42800B int(192000); +#define KBiR_H264_PLID_42800C int(384000); +#define KBiR_H264_PLID_42800D int(768000); +#define KBiR_H264_PLID_428014 int(2000000); +#define KBiR_H264_PLID_428015 int(4000000); +#define KBiR_H264_PLID_428016 int(4000000); +#define KBiR_H264_PLID_42801E int(10000000); +#define KBiR_H264_PLID_42801F int(14000000); +#define KBiR_H264_PLID_428020 int(20000000); +#define KBiR_H264_PLID_428028 int(20000000); + +#endif // S60CAMERACONSTANTS_H diff --git a/src/plugins/symbian/ecam/s60cameracontrol.cpp b/src/plugins/symbian/ecam/s60cameracontrol.cpp new file mode 100644 index 000000000..64a3ff37e --- /dev/null +++ b/src/plugins/symbian/ecam/s60cameracontrol.cpp @@ -0,0 +1,983 @@ +/**************************************************************************** +** +** 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 <QTimer> + +#include "s60cameraservice.h" +#include "s60cameraengine.h" +#include "s60cameracontrol.h" +#include "s60imagecapturesession.h" +#include "s60videowidgetcontrol.h" +#include "s60cameraviewfinderengine.h" +#include "s60cameraconstants.h" + +S60CameraControl::S60CameraControl(QObject *parent) : + QCameraControl(parent) +{ +} + +S60CameraControl::S60CameraControl(S60VideoCaptureSession *videosession, + S60ImageCaptureSession *imagesession, + QObject *parent): + QCameraControl(parent), + m_cameraEngine(0), + m_viewfinderEngine(0), + m_imageSession(0), + m_videoSession(0), + m_advancedSettings(0), + m_videoOutput(0), + m_inactivityTimer(0), + m_captureMode(QCamera::CaptureStillImage), // Default CaptureMode + m_requestedCaptureMode(QCamera::CaptureStillImage), + m_settingCaptureModeInternally(false), + m_internalState(QCamera::UnloadedStatus), // Default Status + m_requestedState(QCamera::UnloadedState), // Default State + m_deviceIndex(KDefaultCameraDevice), + m_error(KErrNone), + m_changeCaptureModeWhenReady(false), + m_rotateCameraWhenReady(false), + m_videoCaptureState(S60VideoCaptureSession::ENotInitialized) +{ + m_videoSession = videosession; + m_imageSession = imagesession; + + m_inactivityTimer = new QTimer; + if (m_inactivityTimer) + m_inactivityTimer->setSingleShot(true); + + TRAPD(err, m_cameraEngine = CCameraEngine::NewL(m_deviceIndex, KECamCameraPriority, this)); + if (err) { + m_error = err; + if (err == KErrPermissionDenied) + qWarning("Failed to create camera. Possibly missing capabilities."); + else + qWarning("Failed to create camera."); + return; + } + + m_viewfinderEngine = new S60CameraViewfinderEngine(this, m_cameraEngine, this); + if (m_viewfinderEngine == 0) { + m_error = KErrNoMemory; + qWarning("Failed to create viewfinder engine."); + return; + } + + // Connect signals + connect(m_inactivityTimer, SIGNAL(timeout()), this, SLOT(toStandByStatus())); + connect(this, SIGNAL(statusChanged(QCamera::Status)), + m_imageSession, SLOT(cameraStatusChanged(QCamera::Status))); + connect(this, SIGNAL(statusChanged(QCamera::Status)), + m_videoSession, SLOT(cameraStatusChanged(QCamera::Status))); + connect(m_videoSession, SIGNAL(stateChanged(S60VideoCaptureSession::TVideoCaptureState)), + this, SLOT(videoStateChanged(S60VideoCaptureSession::TVideoCaptureState))); + connect(m_imageSession, SIGNAL(advancedSettingChanged()), this, SLOT(advancedSettingsCreated())); + connect(this, SIGNAL(cameraReadyChanged(bool)), m_imageSession, SIGNAL(readyForCaptureChanged(bool))); + connect(m_viewfinderEngine, SIGNAL(error(int, const QString&)), this, SIGNAL(error(int,const QString&))); + connect(m_imageSession, SIGNAL(cameraError(int, const QString&)), this, SIGNAL(error(int, const QString&))); + connect(m_imageSession, SIGNAL(captureSizeChanged(const QSize&)), + m_viewfinderEngine, SLOT(handleContentAspectRatioChange(const QSize&))); + connect(m_videoSession, SIGNAL(captureSizeChanged(const QSize&)), + m_viewfinderEngine, SLOT(handleContentAspectRatioChange(const QSize&))); + + setCameraHandles(); +} + +S60CameraControl::~S60CameraControl() +{ + unloadCamera(); + + if (m_viewfinderEngine) { + delete m_viewfinderEngine; + m_viewfinderEngine = 0; + } + + // Make sure AdvancedSettings are destructed + m_imageSession->deleteAdvancedSettings(); + + if (m_cameraEngine) { + delete m_cameraEngine; + m_cameraEngine = 0; + } + + if (m_inactivityTimer) { + delete m_inactivityTimer; + m_inactivityTimer = 0; + } +} + +void S60CameraControl::setState(QCamera::State state) +{ + if (m_error) { // Most probably failure in contructor + setError(m_error, tr("Unexpected camera error.")); + return; + } + + if (m_requestedState == state) + return; + + if (m_inactivityTimer->isActive()) + m_inactivityTimer->stop(); + + // Save the target state + m_requestedState = state; + emit stateChanged(m_requestedState); + + switch (state) { + case QCamera::UnloadedState: // To UnloadedState - Release resources + switch (m_internalState) { + case QCamera::UnloadedStatus: + // Do nothing + break; + case QCamera::LoadingStatus: + case QCamera::StartingStatus: + // Release resources when ready (setting state handles this) + return; + case QCamera::LoadedStatus: + case QCamera::StandbyStatus: + // Unload + unloadCamera(); + break; + case QCamera::ActiveStatus: + // Stop and Unload + stopCamera(); + unloadCamera(); + break; + + default: + // Unrecognized internal state (Status) + setError(KErrGeneral, tr("Unexpected camera error.")); + return; + } + break; + + case QCamera::LoadedState: // To LoadedState - Reserve resources OR Stop ViewFinder and Cancel Capture + switch (m_internalState) { + case QCamera::UnloadedStatus: + case QCamera::StandbyStatus: + // Load + loadCamera(); + break; + case QCamera::LoadingStatus: + // Discard, already moving to LoadedStatus + return; + case QCamera::StartingStatus: + // Stop when ready (setting state handles this) + return; + case QCamera::LoadedStatus: + m_inactivityTimer->start(KInactivityTimerTimeout); + break; + case QCamera::ActiveStatus: + // Stop + stopCamera(); + break; + + default: + // Unregocnized internal state (Status) + setError(KErrGeneral, tr("Unexpected camera error.")); + return; + } + break; + + case QCamera::ActiveState: // To ActiveState - (Reserve Resources and) Start ViewFinder + switch (m_internalState) { + case QCamera::UnloadedStatus: + case QCamera::StandbyStatus: + // Load and Start (setting state handles starting) + loadCamera(); + break; + case QCamera::LoadingStatus: + // Start when loaded (setting state handles this) + break; + case QCamera::StartingStatus: + // Discard, already moving to ActiveStatus + return; + case QCamera::LoadedStatus: + // Start + startCamera(); + break; + case QCamera::ActiveStatus: + // Do nothing + break; + + default: + // Unregocnized internal state (Status) + setError(KErrGeneral, tr("Unexpected camera error.")); + return; + } + break; + + default: + setError(KErrNotSupported, tr("Requested state is not supported.")); + return; + } +} + +QCamera::State S60CameraControl::state() const +{ + return m_requestedState; +} + +QCamera::Status S60CameraControl::status() const +{ + return m_internalState; +} + +QCamera::CaptureMode S60CameraControl::captureMode() const +{ + return m_captureMode; +} + +void S60CameraControl::setCaptureMode(QCamera::CaptureMode mode) +{ + if (m_error) { // Most probably failure in contructor + setError(m_error, tr("Unexpected camera error.")); + return; + } + + if (m_captureMode == mode) + return; + + // Setting CaptureMode Internally or Externally (Client) + if (!m_settingCaptureModeInternally) { + // Save the requested mode + m_requestedCaptureMode = mode; + + // CaptureMode change pending (backend busy), wait + if (m_changeCaptureModeWhenReady) + return; + } else { + m_changeCaptureModeWhenReady = false; // Reset + } + m_settingCaptureModeInternally = false; // Reset + + if (!isCaptureModeSupported(mode)) { + setError(KErrNotSupported, tr("Requested capture mode is not supported.")); + return; + } + + if (m_inactivityTimer->isActive()) + m_inactivityTimer->stop(); + + switch (m_internalState) { + case QCamera::UnloadedStatus: + case QCamera::LoadedStatus: + case QCamera::StandbyStatus: + switch (mode) { + case QCamera::CaptureStillImage: + m_videoSession->releaseVideoRecording(); + m_captureMode = QCamera::CaptureStillImage; + if (m_internalState == QCamera::LoadedStatus) + m_inactivityTimer->start(KInactivityTimerTimeout); + else if (m_internalState == QCamera::StandbyStatus) + loadCamera(); + break; + case QCamera::CaptureVideo: + m_imageSession->releaseImageCapture(); + m_captureMode = QCamera::CaptureVideo; + if (m_internalState == QCamera::LoadedStatus) { + // Revet InternalState as we need to wait for the video + // side initialization to complete + m_internalState = QCamera::LoadingStatus; + emit statusChanged(m_internalState); + int prepareSuccess = m_videoSession->initializeVideoRecording(); + setError(prepareSuccess, tr("Loading video capture failed.")); + } else if (m_internalState == QCamera::StandbyStatus) + loadCamera(); + break; + } + break; + case QCamera::LoadingStatus: + case QCamera::StartingStatus: + m_changeCaptureModeWhenReady = true; + return; + case QCamera::ActiveStatus: + // Stop, Change Mode and Start again + stopCamera(); + switch (mode) { + case QCamera::CaptureStillImage: + m_videoSession->releaseVideoRecording(); + m_captureMode = QCamera::CaptureStillImage; + startCamera(); + break; + case QCamera::CaptureVideo: + m_imageSession->releaseImageCapture(); + m_captureMode = QCamera::CaptureVideo; + // Revet InternalState as we need to wait for the video + // side initialization to complete + m_internalState = QCamera::LoadingStatus; + emit statusChanged(m_internalState); + int prepareSuccess = m_videoSession->initializeVideoRecording(); + setError(prepareSuccess, tr("Loading video recorder failed.")); + break; + } + break; + + default: + // Unregocnized internal state (Status) + setError(KErrNotSupported, tr("Requested capture mode is not supported.")); + break; + } + + emit captureModeChanged(mode); +} + +bool S60CameraControl::isCaptureModeSupported(QCamera::CaptureMode mode) const +{ + switch (mode) { + case QCamera::CaptureStillImage: + return true; + case QCamera::CaptureVideo: + return true; + + default: + return false; + } +} + +bool S60CameraControl::canChangeProperty(QCameraControl::PropertyChangeType changeType, QCamera::Status status) const +{ + Q_UNUSED(status); + + bool returnValue = false; + + switch (changeType) { + case QCameraControl::CaptureMode: + case QCameraControl::VideoEncodingSettings: + case QCameraControl::ImageEncodingSettings: + returnValue = true; + break; + + case QCameraControl::Viewfinder: + returnValue = false; + break; + + default: + // Safer to revert state before the unknown operation + returnValue = false; + break; + } + + return returnValue; +} + +void S60CameraControl::setVideoOutput(QObject *output, + S60CameraViewfinderEngine::ViewfinderOutputType type) +{ + if (!m_viewfinderEngine) { + setError(KErrGeneral, tr("Failed to set viewfinder")); + return; + } + + switch (type) { + case S60CameraViewfinderEngine::OutputTypeVideoWidget: + m_viewfinderEngine->setVideoWidgetControl(output); + break; + case S60CameraViewfinderEngine::OutputTypeRenderer: + m_viewfinderEngine->setVideoRendererControl(output); + break; + case S60CameraViewfinderEngine::OutputTypeVideoWindow: + m_viewfinderEngine->setVideoWindowControl(output); + break; + + default: + break; + } +} + +void S60CameraControl::releaseVideoOutput(const S60CameraViewfinderEngine::ViewfinderOutputType type) +{ + m_viewfinderEngine->releaseControl(type); +} + +void S60CameraControl::loadCamera() +{ + if (m_internalState < QCamera::LoadingStatus) { + m_internalState = QCamera::LoadingStatus; + emit statusChanged(m_internalState); + } else if (m_internalState == QCamera::LoadedStatus + || m_internalState >= QCamera::StartingStatus) { + // Nothing to load (already loaded) + return; + } + // Status = Loading or Standby + + m_cameraEngine->ReserveAndPowerOn(); + + // Completion notified in MceoCameraReady() +} + +void S60CameraControl::unloadCamera() +{ + if (m_internalState > QCamera::LoadingStatus) { + m_internalState = QCamera::LoadingStatus; + emit statusChanged(m_internalState); + } else if (m_internalState < QCamera::LoadingStatus) { + // Nothing to unload + return; + } + // Status = Loading + + if (m_inactivityTimer->isActive()) + m_inactivityTimer->stop(); + + m_cameraEngine->ReleaseAndPowerOff(); + + m_internalState = QCamera::UnloadedStatus; + emit statusChanged(m_internalState); +} + +void S60CameraControl::startCamera() +{ + if (m_internalState < QCamera::StartingStatus) { + m_internalState = QCamera::StartingStatus; + emit statusChanged(m_internalState); + } else if (m_internalState > QCamera::StartingStatus) { + // Nothing to start (already started) + return; + } + // Status = Starting + + if (m_inactivityTimer->isActive()) + m_inactivityTimer->stop(); + + if (m_viewfinderEngine) + m_viewfinderEngine->startViewfinder(); + else + setError(KErrGeneral, tr("Failed to start viewfinder.")); + + m_internalState = QCamera::ActiveStatus; + emit statusChanged(m_internalState); + + emit cameraReadyChanged(true); + +#ifdef Q_CC_NOKIAX86 // Emulator + MceoCameraReady(); // Signal that we are ready +#endif +} + +void S60CameraControl::stopCamera() +{ + if (m_internalState > QCamera::StartingStatus) { + m_internalState = QCamera::StartingStatus; + emit statusChanged(m_internalState); + } else if (m_internalState < QCamera::StartingStatus) { + // Nothing to stop + return; + } + // Status = Starting + + // Cancel ongoing operations if any + m_imageSession->cancelCapture(); + m_videoSession->stopRecording(); + + emit cameraReadyChanged(false); + if (m_viewfinderEngine) + m_viewfinderEngine->stopViewfinder(); + else + setError(KErrGeneral, tr("Failed to stop viewfinder.")); + + m_internalState = QCamera::LoadedStatus; + emit statusChanged(m_internalState); + + m_inactivityTimer->start(KInactivityTimerTimeout); +} + +void S60CameraControl::videoStateChanged(const S60VideoCaptureSession::TVideoCaptureState state) +{ + // Save video state + m_videoCaptureState = state; + + if (m_rotateCameraWhenReady) { + if (m_videoCaptureState != S60VideoCaptureSession::ERecording && + m_videoCaptureState != S60VideoCaptureSession::EPaused) + resetCameraOrientation(); + } + + // If video recording was stopped, video state reverts back to + // Initializing. In that case revert also Camera status to notify that + // video initialization needs to be completed. + if (state == S60VideoCaptureSession::EInitializing) { + if (m_internalState > QCamera::LoadingStatus) { + m_internalState = QCamera::LoadingStatus; + emit statusChanged(m_internalState); + } + + // Handle video initialization completion + } else if (state == S60VideoCaptureSession::EInitialized) { + + // Make sure state is not downgraded + if (m_internalState == QCamera::LoadedStatus + || m_internalState == QCamera::ActiveStatus) { + // Do nothing (already in target state) + } else if (m_internalState == QCamera::StartingStatus) { + m_internalState = QCamera::ActiveStatus; + emit statusChanged(m_internalState); + } else { + m_internalState = QCamera::LoadedStatus; + emit statusChanged(m_internalState); + } + + switch (m_requestedState) { + case QCamera::UnloadedState: + stopCamera(); + unloadCamera(); + if (m_changeCaptureModeWhenReady) { + m_settingCaptureModeInternally = true; + setCaptureMode(m_requestedCaptureMode); + } + break; + case QCamera::LoadedState: + stopCamera(); + if (m_changeCaptureModeWhenReady) { + m_settingCaptureModeInternally = true; + setCaptureMode(m_requestedCaptureMode); + } + m_inactivityTimer->start(KInactivityTimerTimeout); + break; + case QCamera::ActiveState: + if (m_changeCaptureModeWhenReady) { + m_settingCaptureModeInternally = true; + setCaptureMode(m_requestedCaptureMode); + } + startCamera(); + break; + + default: + setError(KErrGeneral, tr("Unexpected camera error.")); + return; + } + } +} + +void S60CameraControl::imageCaptured(const int imageId, const QImage& preview) +{ + Q_UNUSED(imageId); + Q_UNUSED(preview); + + // Unsubscribe the readyForCaptureChanged notification + disconnect(m_imageSession, SIGNAL(imageCaptured(const int, const QImage&)), + this, SLOT(imageCaptured(const int, const QImage&))); + + if (m_rotateCameraWhenReady) + resetCameraOrientation(); +} + +void S60CameraControl::advancedSettingsCreated() +{ + m_advancedSettings = m_imageSession->advancedSettings(); + + if (m_advancedSettings) + connect(m_advancedSettings, SIGNAL(error(int, const QString&)), this, SIGNAL(error(int, const QString&))); +} + +void S60CameraControl::MceoCameraReady() +{ + // Rotate camera if requested + if (m_rotateCameraWhenReady) { + resetCameraOrientation(); + return; + } + + if (m_internalState != QCamera::LoadedStatus) { + + switch (m_requestedState) { + case QCamera::UnloadedState: + m_internalState = QCamera::LoadedStatus; + emit statusChanged(QCamera::LoadedStatus); + + stopCamera(); + unloadCamera(); + + if (m_changeCaptureModeWhenReady) { + m_settingCaptureModeInternally = true; + setCaptureMode(m_requestedCaptureMode); + } + break; + + case QCamera::LoadedState: + if (m_captureMode == QCamera::CaptureVideo) { + int prepareSuccess = m_videoSession->initializeVideoRecording(); + setError(prepareSuccess, tr("Loading video capture failed.")); + + // State change signalled when reservation is complete (in videoStateChanged()) + return; + } + m_internalState = QCamera::LoadedStatus; + emit statusChanged(QCamera::LoadedStatus); + + if (m_changeCaptureModeWhenReady) { + setCaptureMode(m_requestedCaptureMode); + m_changeCaptureModeWhenReady = false; // Reset + } + + if (m_requestedState == QCamera::LoadedStatus && + m_internalState == QCamera::LoadedStatus) + m_inactivityTimer->start(KInactivityTimerTimeout); + break; + + case QCamera::ActiveState: + if (m_captureMode == QCamera::CaptureVideo) { + int prepareSuccess = m_videoSession->initializeVideoRecording(); + setError(prepareSuccess, tr("Loading video capture failed.")); + + // State change signalled when reservation is complete (in videoStateChanged()) + return; + } + + m_internalState = QCamera::LoadedStatus; + emit statusChanged(QCamera::LoadedStatus); + + if (m_changeCaptureModeWhenReady) { + setCaptureMode(m_requestedCaptureMode); + m_changeCaptureModeWhenReady = false; // Reset + } + startCamera(); + break; + + default: + setError(KErrGeneral, tr("Unexpected camera error.")); + return; + } + } +} + +void S60CameraControl::MceoHandleError(TCameraEngineError aErrorType, TInt aError) +{ + Q_UNUSED(aErrorType); + + if (aError == KErrAccessDenied) { + setError(KErrGeneral, tr("Access to camera device was rejected.")); + } else if (aError == KErrHardwareNotAvailable) { + setError(aError, tr("Camera resources were lost.")); + toStandByStatus(); + } + else + setError(aError, tr("Unexpected camera error.")); +} + +void S60CameraControl::setError(const TInt error, const QString &description) +{ + if (error == KErrNone) + return; + + m_error = error; + QCamera::Error cameraError = fromSymbianErrorToQtMultimediaError(m_error); + + emit this->error(int(cameraError), description); + + // Reset everything, if other than not supported error or resource loss + if (error != KErrNotSupported && error != KErrHardwareNotAvailable) + resetCamera(true); // Try to recover from error + else + m_error = KErrNone; // Reset error +} + +QCamera::Error S60CameraControl::fromSymbianErrorToQtMultimediaError(int aError) +{ + switch(aError) { + case KErrNone: + return QCamera::NoError; // No errors have occurred + + case KErrNotSupported: + return QCamera::NotSupportedFeatureError; // The feature is not supported + case KErrNotFound: + case KErrBadHandle: + return QCamera::ServiceMissingError; // No camera service available + case KErrArgument: + case KErrNotReady: + return QCamera::InvalidRequestError; // Invalid parameter or state + + default: + return QCamera::CameraError; // An error has occurred (i.e. General Error) + } +} + +// For S60CameraVideoDeviceControl +int S60CameraControl::deviceCount() +{ +#ifdef Q_CC_NOKIAX86 // Emulator + return 1; +#endif + + return CCameraEngine::CamerasAvailable(); +} + +int S60CameraControl::defaultDevice() const +{ + return KDefaultCameraDevice; +} + +int S60CameraControl::selectedDevice() const +{ + return m_deviceIndex; +} + +void S60CameraControl::setSelectedDevice(const int index) +{ + if (m_deviceIndex != index) { + if (index >= 0 && index < deviceCount()) { + m_deviceIndex = index; + resetCamera(); + } else { + setError(KErrNotSupported, tr("Requested camera is not available.")); + } + } +} + +QString S60CameraControl::name(const int index) +{ + QString cameraName; + switch (index) { + case 0: + cameraName = tr("Primary camera"); + break; + case 1: + cameraName = tr("Secondary camera"); + break; + case 2: + cameraName = tr("Tertiary camera"); + break; + + default: + cameraName = tr("Unidentified Camera"); + break; + } + + return cameraName; +} + +QString S60CameraControl::description(const int index) +{ + QString cameraDesc; + switch (index) { + case 0: + cameraDesc = tr("Device primary camera"); + break; + case 1: + cameraDesc = tr("Device secondary camera"); + break; + case 2: + cameraDesc = tr("Device tertiary camera"); + break; + + default: + cameraDesc = tr("Unidentified Camera"); + break; + } + + return cameraDesc; +} + +void S60CameraControl::resetCamera(bool errorHandling) +{ + if (m_inactivityTimer->isActive()) + m_inactivityTimer->stop(); + + // Cancel ongoing activity + m_imageSession->cancelCapture(); + m_videoSession->stopRecording(false); // Don't re-initialize video + + // Advanced settings must be destructed before the camera + m_imageSession->deleteAdvancedSettings(); + + // Release resources + stopCamera(); + unloadCamera(); + + disconnect(m_viewfinderEngine, SIGNAL(error(int, const QString&)), this, SIGNAL(error(int,const QString&))); + if (m_viewfinderEngine) { + delete m_viewfinderEngine; + m_viewfinderEngine = 0; + } + + if (m_cameraEngine) { + delete m_cameraEngine; + m_cameraEngine = 0; + } + + TRAPD(err, m_cameraEngine = CCameraEngine::NewL(m_deviceIndex, 0, this)); + if (err) { + m_cameraEngine = 0; + if (errorHandling) { + qWarning("Failed to recover from error."); + if (err == KErrPermissionDenied) + emit error(int(QCamera::ServiceMissingError), tr("Recovering from error failed. Possibly missing capabilities.")); + else + emit error(int(QCamera::CameraError), tr("Recovering from error failed.")); + } else { + if (err == KErrPermissionDenied) + setError(err, tr("Camera device creation failed. Possibly missing capabilities.")); + else + setError(err, tr("Camera device creation failed.")); + } + return; + } + + // Notify list of available camera devices has been updated + emit devicesChanged(); + + m_viewfinderEngine = new S60CameraViewfinderEngine(this, m_cameraEngine, this); + if (m_viewfinderEngine == 0) + setError(KErrNoMemory, tr("Viewfinder device creation failed.")); + connect(m_viewfinderEngine, SIGNAL(error(int, const QString&)), this, SIGNAL(error(int,const QString&))); + + setCameraHandles(); + + // Reset state + //setState(QCamera::UnloadedState); + if (m_internalState != QCamera::UnloadedStatus) { + m_internalState = QCamera::UnloadedStatus; + emit statusChanged(m_internalState); + } + if (m_requestedState != QCamera::UnloadedState) { + m_requestedState = QCamera::UnloadedState; + emit stateChanged(m_requestedState); + } + + // Reset error + m_error = KErrNone; +} + +/* + * Reset everything else than viewfinder engine and errors. + */ +void S60CameraControl::resetCameraOrientation() +{ + // If camera has not been created, it will be created automatically to correct orientation + if (!m_cameraEngine) + return; + + // Check Image/VideoCapture allow rotation + if ((!m_cameraEngine->IsCameraReady() && m_internalState != QCamera::UnloadedStatus) || + m_videoCaptureState == S60VideoCaptureSession::ERecording || + m_videoCaptureState == S60VideoCaptureSession::EPaused) { + + // If image capture is ongoing, request notification about the + // completion (imageCaptured() is used because that comes asynchronously + // after the image is captured) + // Obs! If preview creation is changed to be synchnonously done during + // the image capture this implementation needs to be changed) + if (m_videoCaptureState != S60VideoCaptureSession::ERecording && + m_videoCaptureState != S60VideoCaptureSession::EPaused && + m_internalState == QCamera::ActiveStatus) + connect(m_imageSession, SIGNAL(imageCaptured(const int, const QImage&)), + this, SLOT(imageCaptured(const int, const QImage&))); + + m_rotateCameraWhenReady = true; + return; + } + + m_rotateCameraWhenReady = false; // Reset + + QCamera::State originalState = m_requestedState; + + // Cancel ongoing activity + m_imageSession->cancelCapture(); + m_videoSession->stopRecording(false); // Don't re-initialize video + + // Advanced settings must be destructed before the camera + m_imageSession->deleteAdvancedSettings(); + + // Release resources + stopCamera(); + unloadCamera(); + + // Unset CameraEngine to ViewfinderEngine + m_viewfinderEngine->setNewCameraEngine(0); + if (m_cameraEngine) { + delete m_cameraEngine; + m_cameraEngine = 0; + } + + TRAPD(err, m_cameraEngine = CCameraEngine::NewL(m_deviceIndex, 0, this)); + if (err) { + setError(err, tr("Camera device creation failed.")); + return; + } + // Reset CameraEngine to ViewfinderEngine + m_viewfinderEngine->setNewCameraEngine(m_cameraEngine); + + // Notify list of available camera devices has been updated + emit devicesChanged(); + + setCameraHandles(); + + // Reset state + if (m_internalState != QCamera::UnloadedStatus) { + m_internalState = QCamera::UnloadedStatus; + emit statusChanged(m_internalState); + } + if (m_requestedState != QCamera::UnloadedState) { + m_requestedState = QCamera::UnloadedState; + emit stateChanged(m_requestedState); + } + + setState(originalState); +} + +void S60CameraControl::setCameraHandles() +{ + m_imageSession->setCurrentDevice(m_deviceIndex); + m_imageSession->setCameraHandle(m_cameraEngine); + m_cameraEngine->SetImageCaptureObserver(m_imageSession); + m_videoSession->setCameraHandle(m_cameraEngine); +} + +void S60CameraControl::toStandByStatus() +{ + // Cancel ongoing operations if any + m_imageSession->cancelCapture(); + m_videoSession->stopRecording(false); // Don't re-initialize video + + emit cameraReadyChanged(false); + if (m_viewfinderEngine) + m_viewfinderEngine->stopViewfinder(); + else + setError(KErrGeneral, tr("Failed to stop viewfinder.")); + + m_cameraEngine->ReleaseAndPowerOff(); + + m_internalState = QCamera::StandbyStatus; + emit statusChanged(m_internalState); +} + +// End of file diff --git a/src/plugins/symbian/ecam/s60cameracontrol.h b/src/plugins/symbian/ecam/s60cameracontrol.h new file mode 100644 index 000000000..95c31fb34 --- /dev/null +++ b/src/plugins/symbian/ecam/s60cameracontrol.h @@ -0,0 +1,178 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef S60CAMERACONTROL_H +#define S60CAMERACONTROL_H + +#include <qcameracontrol.h> + +#include "s60cameraengineobserver.h" // MCameraEngineObserver +#include "s60videocapturesession.h" // TVideoCaptureState +#include "s60cameraviewfinderengine.h" // ViewfinderOutputType + +#include <e32base.h> +#include <fbs.h> + +QT_USE_NAMESPACE + +class S60CameraService; +class S60ImageCaptureSession; +class S60VideoCaptureSession; +class S60CameraSettings; +class CCameraEngine; +class S60CameraViewfinderEngine; +class QTimer; + +/* + * Control for controlling camera base operations (e.g. start/stop and capture + * mode). + */ +class S60CameraControl : public QCameraControl, public MCameraEngineObserver +{ + Q_OBJECT + +public: // Constructors & Destructor + + S60CameraControl(QObject *parent = 0); + S60CameraControl(S60VideoCaptureSession *videosession, + S60ImageCaptureSession *imagesession, + QObject *parent = 0); + ~S60CameraControl(); + +public: // QCameraControl + + // State + QCamera::State state() const; + void setState(QCamera::State state); + + // Status + QCamera::Status status() const; + + // Capture Mode + QCamera::CaptureMode captureMode() const; + void setCaptureMode(QCamera::CaptureMode); + bool isCaptureModeSupported(QCamera::CaptureMode mode) const; + + // Property Setting + bool canChangeProperty(QCameraControl::PropertyChangeType changeType, QCamera::Status status) const; + +/* +Q_SIGNALS: + void stateChanged(QCamera::State); + void statusChanged(QCamera::Status); + void error(int error, const QString &errorString); + void captureModeChanged(QCamera::CaptureMode); +*/ + +public: // Internal + + void setError(const TInt error, const QString &description); + void resetCameraOrientation(); + + // To provide QVideoDeviceControl info + static int deviceCount(); + static QString name(const int index); + static QString description(const int index); + int defaultDevice() const; + int selectedDevice() const; + void setSelectedDevice(const int index); + + void setVideoOutput(QObject *output, + const S60CameraViewfinderEngine::ViewfinderOutputType type); + void releaseVideoOutput(const S60CameraViewfinderEngine::ViewfinderOutputType type); + +private slots: // Internal Slots + + void videoStateChanged(const S60VideoCaptureSession::TVideoCaptureState state); + // Needed to detect image capture completion when trying to rotate the camera + void imageCaptured(const int imageId, const QImage& preview); + /* + * This method moves the camera to the StandBy status: + * - If camera access was lost + * - If camera has been inactive in LoadedStatus for a long time + */ + void toStandByStatus(); + void advancedSettingsCreated(); + +protected: // MCameraEngineObserver + + void MceoCameraReady(); + void MceoHandleError(TCameraEngineError aErrorType, TInt aError); + +private: // Internal + + QCamera::Error fromSymbianErrorToQtMultimediaError(int aError); + + void loadCamera(); + void unloadCamera(); + void startCamera(); + void stopCamera(); + + void resetCamera(bool errorHandling = false); + void setCameraHandles(); + +signals: // Internal Signals + + void cameraReadyChanged(bool); + void devicesChanged(); + +private: // Data + + CCameraEngine *m_cameraEngine; + S60CameraViewfinderEngine *m_viewfinderEngine; + S60ImageCaptureSession *m_imageSession; + S60VideoCaptureSession *m_videoSession; + S60CameraSettings *m_advancedSettings; + QObject *m_videoOutput; + QTimer *m_inactivityTimer; + QCamera::CaptureMode m_captureMode; + QCamera::CaptureMode m_requestedCaptureMode; + bool m_settingCaptureModeInternally; + QCamera::Status m_internalState; + QCamera::State m_requestedState; + int m_deviceIndex; + mutable int m_error; + bool m_changeCaptureModeWhenReady; + bool m_rotateCameraWhenReady; + S60VideoCaptureSession::TVideoCaptureState m_videoCaptureState; +}; + +#endif // S60CAMERACONTROL_H diff --git a/src/plugins/symbian/ecam/s60cameraengine.cpp b/src/plugins/symbian/ecam/s60cameraengine.cpp new file mode 100644 index 000000000..dbd5fb33e --- /dev/null +++ b/src/plugins/symbian/ecam/s60cameraengine.cpp @@ -0,0 +1,824 @@ +/**************************************************************************** + ** + ** 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 "s60cameraengine.h" +#include "s60cameraengineobserver.h" +#include "s60cameraconstants.h" +#include <QtCore/qglobal.h> +#include <fbs.h> // CFbsBitmap +#ifdef ECAM_PREVIEW_API + #include <platform/ecam/camerasnapshot.h> +#endif // ECAM_PREVIEW_API + +CCameraEngine::CCameraEngine() +{ +} + +CCameraEngine::CCameraEngine(TInt aCameraHandle, + TInt aPriority, + MCameraEngineObserver* aObserver) : + // CBase initializes member variables to NULL + iObserver(aObserver), + iCameraIndex(aCameraHandle), + iPriority(aPriority), + iEngineState(EEngineNotReady), + iCaptureResolution(TSize(0,0)), + iNew2LImplementation(false), + iLatestImageBufferIndex(1) // Thus we start from index 0 +{ + // Observer is mandatory + ASSERT(aObserver != NULL); +} + +CCameraEngine::~CCameraEngine() +{ + StopViewFinder(); + ReleaseViewFinderBuffer(); // Releases iViewFinderBuffer + ReleaseImageBuffer(); // Releases iImageBuffer + iImageBitmap + + iAdvancedSettingsObserver = NULL; + iImageCaptureObserver = NULL; + iViewfinderObserver = NULL; + +#ifdef S60_CAM_AUTOFOCUS_SUPPORT + delete iAutoFocus; +#endif // S60_CAM_AUTOFOCUS_SUPPORT + + if (iCamera) { + iCamera->Release(); + delete iCamera; + iCamera = NULL; + } +} + +TInt CCameraEngine::CamerasAvailable() +{ + return CCamera::CamerasAvailable(); +} + +CCameraEngine* CCameraEngine::NewL(TInt aCameraHandle, + TInt aPriority, + MCameraEngineObserver* aObserver) +{ + CCameraEngine* self = new (ELeave) CCameraEngine(aCameraHandle, aPriority, aObserver); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(self); + return self; +} + +void CCameraEngine::ConstructL() +{ + if (!CCamera::CamerasAvailable()) + User::Leave(KErrHardwareNotAvailable); + +#ifndef Q_CC_NOKIAX86 // Not Emulator + TInt err(KErrNone); +#else // Emulator + TInt err(KErrNotFound); +#endif // !(Q_CC_NOKIAX86) + +#ifdef S60_31_PLATFORM + // Construct CCamera object for S60 3.1 (NewL) + iNew2LImplementation = false; + TRAP(err, iCamera = CCamera::NewL(*this, iCameraIndex)); + if (err) + User::Leave(err); +#else // For S60 3.2 onwards - use this constructor (New2L) + iNew2LImplementation = true; + TRAP(err, iCamera = CCamera::New2L(*this, iCameraIndex, iPriority)); + if (err) + User::Leave(err); +#endif // S60_31_PLATFORM + +#ifdef S60_CAM_AUTOFOCUS_SUPPORT + // Might not be supported for secondary camera, discard errors + TRAP(err, iAutoFocus = CCamAutoFocus::NewL(iCamera)); +#endif // S60_CAM_AUTOFOCUS_SUPPORT + + if (iCamera == NULL) + User::Leave(KErrNoMemory); + + iCamera->CameraInfo(iCameraInfo); +} + +void CCameraEngine::SetAdvancedObserver(MAdvancedSettingsObserver* aAdvancedSettingsObserver) +{ + iAdvancedSettingsObserver = aAdvancedSettingsObserver; +} + +void CCameraEngine::SetImageCaptureObserver(MCameraEngineImageCaptureObserver* aImageCaptureObserver) +{ + iImageCaptureObserver = aImageCaptureObserver; +} + +void CCameraEngine::SetViewfinderObserver(MCameraViewfinderObserver* aViewfinderObserver) +{ + iViewfinderObserver = aViewfinderObserver; +} + +void CCameraEngine::ReserveAndPowerOn() +{ + if (!iCamera || iEngineState > EEngineNotReady) { + iObserver->MceoHandleError(EErrReserve, KErrNotReady); + return; + } + + iCamera->Reserve(); +} + +void CCameraEngine::ReleaseAndPowerOff() +{ + if (iEngineState >= EEngineIdle) { + CancelCapture(); + StopViewFinder(); + FocusCancel(); + iCamera->PowerOff(); + iCamera->Release(); + } + iEngineState = EEngineNotReady; +} + +void CCameraEngine::StartViewFinderL(TSize& aSize) +{ + if (iEngineState < EEngineIdle) + User::Leave(KErrNotReady); + + if (0 == (iCameraInfo.iOptionsSupported & TCameraInfo::EViewFinderBitmapsSupported)) + User::Leave(KErrNotSupported); + + if (!iCamera->ViewFinderActive()) { + if (iCameraIndex != 0) + iCamera->SetViewFinderMirrorL(true); + iCamera->StartViewFinderBitmapsL(aSize); + } +} + +void CCameraEngine::StopViewFinder() +{ + if (iCamera && iCamera->ViewFinderActive()) + iCamera->StopViewFinder(); +} + +void CCameraEngine::StartDirectViewFinderL(RWsSession& aSession, + CWsScreenDevice& aScreenDevice, + RWindowBase& aWindow, + TRect& aScreenRect, + TRect& aClipRect) +{ + if (iEngineState < EEngineIdle) + User::Leave(KErrNotReady); + + if (0 == (iCameraInfo.iOptionsSupported & TCameraInfo::EViewFinderDirectSupported)) + User::Leave(KErrNotSupported); + + if (!iCamera->ViewFinderActive()) { + // Viewfinder extent needs to be clipped according to the clip rect. + // This is because the native camera framework does not support + // clipping and starting viewfinder with bigger than the display(S60 + // 5.0 and older)/window(Symbian^3 and later) would cause viewfinder + // starting to fail entirely. This causes shrinking effect in some + // cases, but is better than not having the viewfinder at all. + if (aScreenRect.Intersects(aClipRect)) + aScreenRect.Intersection(aClipRect); + + if (iCameraIndex != 0) + iCamera->SetViewFinderMirrorL(true); + if (aScreenRect.Width() > 0 && aScreenRect.Height() > 0) { + iCamera->StartViewFinderDirectL(aSession, aScreenDevice, aWindow, aScreenRect); + } else { + if (iObserver) + iObserver->MceoHandleError(EErrViewFinderReady, KErrArgument); + } + } +} + +void CCameraEngine::PrepareL(TSize& aCaptureSize, CCamera::TFormat aFormat) +{ + iImageCaptureFormat = aFormat; + + TInt closestVar = KMaxTInt, selected = 0; + TSize size; + + // Scan through supported capture sizes and select the closest match + for (TInt index = 0; index < iCameraInfo.iNumImageSizesSupported; index++) { + + iCamera->EnumerateCaptureSizes(size, index, aFormat); + if (size == aCaptureSize) { + selected = index; + break; + } + + TSize varSz = size - aCaptureSize; + TInt variation = varSz.iWidth * varSz.iHeight; + if (variation < closestVar) { + closestVar = variation; + selected = index; + } + } + + iCamera->EnumerateCaptureSizes(aCaptureSize, selected, aFormat); + iCaptureResolution = aCaptureSize; + iCamera->PrepareImageCaptureL(aFormat, selected); +} + +void CCameraEngine::CaptureL() +{ + if (iEngineState < EEngineIdle) + User::Leave(KErrNotReady); + + iCamera->CaptureImage(); + iEngineState = EEngineCapturing; +} + +void CCameraEngine::CancelCapture() +{ + if (iEngineState == EEngineCapturing) { + iCamera->CancelCaptureImage(); + iEngineState = EEngineIdle; + } +} + +void CCameraEngine::HandleEvent(const TECAMEvent &aEvent) +{ + if (aEvent.iEventType == KUidECamEventReserveComplete) { + ReserveComplete(aEvent.iErrorCode); + return; + } + + if (aEvent.iEventType == KUidECamEventPowerOnComplete) { + PowerOnComplete(aEvent.iErrorCode); + return; + } + + if (aEvent.iEventType == KUidECamEventCameraNoLongerReserved) { + // All camera related operations need to be stopped + iObserver->MceoHandleError(EErrReserve, KErrHardwareNotAvailable); + return; + } + +#ifdef ECAM_PREVIEW_API + if (aEvent.iEventType == KUidECamEventCameraSnapshot) { + HandlePreview(); + return; + } +#endif // ECAM_PREVIEW_API + +#if !defined(Q_CC_NOKIAX86) // Not Emulator + // Other events; Exposure, Zoom, etc. (See ecamadvancedsettings.h) + if (iAdvancedSettingsObserver) + iAdvancedSettingsObserver->HandleAdvancedEvent(aEvent); + + if (iImageCaptureObserver) + iImageCaptureObserver->MceoHandleOtherEvent(aEvent); +#endif // !Q_CC_NOKIAX86 +} + +void CCameraEngine::ReserveComplete(TInt aError) +{ + if (aError == KErrNone) { + iCamera->PowerOn(); +#ifdef S60_31_PLATFORM + } else if (aError == KErrAlreadyExists) { // Known Issue on some S60 3.1 devices + User::After(500000); // Wait for 0,5 second and try again + iCamera->Reserve(); +#endif // S60_31_PLATFORM + } else { + iObserver->MceoHandleError(EErrReserve, aError); + } +} + +void CCameraEngine::PowerOnComplete(TInt aError) +{ + if (aError) { + iObserver->MceoHandleError(EErrPowerOn, aError); + iEngineState = EEngineNotReady; + return; + } + + // Init AutoFocus +#ifndef Q_CC_NOKIAX86 // Not Emulator +#ifdef S60_CAM_AUTOFOCUS_SUPPORT // S60 3.1 + if( iAutoFocus ) { + TRAPD(afErr, iAutoFocus->InitL( *this )); + if (afErr) { + delete iAutoFocus; + iAutoFocus = 0; + } + } +#endif // S60_CAM_AUTOFOCUS_SUPPORT +#endif // !Q_CC_NOKIAX86 + + iEngineState = EEngineIdle; + iObserver->MceoCameraReady(); +} + +#ifdef ECAM_PREVIEW_API +/** + * This method creates the CCameraPreview object and requests the previews to + * be provided during the image or video capture + */ +void CCameraEngine::EnablePreviewProvider(MCameraPreviewObserver *aPreviewObserver) +{ + // Delete old one if exists + if (iCameraSnapshot) + delete iCameraSnapshot; + + iPreviewObserver = aPreviewObserver; + + TInt error = KErrNone; + + if (iCamera) { + TRAP(error, iCameraSnapshot = CCamera::CCameraSnapshot::NewL(*iCamera)); + if (error) { + if (iObserver) + iObserver->MceoHandleError(EErrPreview, error); + return; + } + + TRAP(error, iCameraSnapshot->PrepareSnapshotL(KDefaultFormatPreview, SelectPreviewResolution(), EFalse)); + if (error) { + if (iObserver) + iObserver->MceoHandleError(EErrPreview, error); + return; + } + + iCameraSnapshot->StartSnapshot(); + } else { + if (iObserver) + iObserver->MceoHandleError(EErrPreview, KErrNotReady); + } +} + +/** + * This method disables and destroys the CCameraPreview object. Thus previews + * will not be provided during the image or video capture. + */ +void CCameraEngine::DisablePreviewProvider() +{ + if (!iCameraSnapshot) + return; + + iCameraSnapshot->StopSnapshot(); + + delete iCameraSnapshot; + iCameraSnapshot = 0; + + iPreviewObserver = 0; +} +#endif // ECAM_PREVIEW_API + +/* + * MCameraObserver2: + * New viewfinder frame available + */ +void CCameraEngine::ViewFinderReady(MCameraBuffer &aCameraBuffer, TInt aError) +{ + iViewFinderBuffer = &aCameraBuffer; + + if (aError == KErrNone) { + if (iViewfinderObserver) { + TRAPD(err, iViewfinderObserver->MceoViewFinderFrameReady(aCameraBuffer.BitmapL(0))); + if (err) + iObserver->MceoHandleError(EErrViewFinderReady, err); + } else { + iObserver->MceoHandleError(EErrViewFinderReady, KErrNotReady); + } + } + else { + iObserver->MceoHandleError(EErrViewFinderReady, aError); + } +} + +/* + * MCameraObserver: + * New viewfinder frame available + */ +void CCameraEngine::ViewFinderFrameReady(CFbsBitmap& aFrame) +{ + if (iViewfinderObserver) + iViewfinderObserver->MceoViewFinderFrameReady(aFrame); + else + iObserver->MceoHandleError(EErrViewFinderReady, KErrNotReady); +} + +void CCameraEngine::ReleaseViewFinderBuffer() +{ + if (iNew2LImplementation) { // NewL Implementation does not use MCameraBuffer + if (iViewFinderBuffer) { + iViewFinderBuffer->Release(); + iViewFinderBuffer = NULL; + } + } +} + +void CCameraEngine::ReleaseImageBuffer() +{ + // Reset Bitmap + if (iLatestImageBufferIndex == 1 || iImageBitmap2 == NULL) { + if (iImageBitmap1) { + if (!iNew2LImplementation) { // NewL - Ownership transferred + iImageBitmap1->Reset(); // Reset/Delete Bitmap + delete iImageBitmap1; + } + iImageBitmap1 = NULL; + } + } else { + if (iImageBitmap2) { + if (!iNew2LImplementation) { // NewL - Ownership transferred + iImageBitmap2->Reset(); // Reset/Delete Bitmap + delete iImageBitmap2; + } + iImageBitmap2 = NULL; + } + } + + // Reset Data pointers + if (iLatestImageBufferIndex == 1 || iImageData2 == NULL) { + if (!iNew2LImplementation) // NewL - Ownership transfers with buffer + delete iImageData1; + iImageData1 = NULL; + } else { + if (!iNew2LImplementation) // NewL - Ownership transfers with buffer + delete iImageData2; + iImageData2 = NULL; + } + + // Reset ImageBuffer - New2L Implementation only + if (iLatestImageBufferIndex == 1 || iImageBuffer2 == NULL) { + if (iImageBuffer1) { + iImageBuffer1->Release(); + iImageBuffer1 = NULL; + } + } else { + if (iImageBuffer2) { + iImageBuffer2->Release(); + iImageBuffer2 = NULL; + } + } +} + +/* + * MCameraObserver2 + * Captured image is ready (New2L version) + */ +void CCameraEngine::ImageBufferReady(MCameraBuffer &aCameraBuffer, TInt aError) +{ + // Use the buffer that is available + if (!iImageBuffer1) { + iLatestImageBufferIndex = 0; + iImageBuffer1 = &aCameraBuffer; + } else { + iLatestImageBufferIndex = 1; + iImageBuffer2 = &aCameraBuffer; + } + + bool isBitmap = true; + TInt err = KErrNone; + + switch (iImageCaptureFormat) { + case CCamera::EFormatFbsBitmapColor4K: + case CCamera::EFormatFbsBitmapColor64K: + case CCamera::EFormatFbsBitmapColor16M: + case CCamera::EFormatFbsBitmapColor16MU: + if (iLatestImageBufferIndex == 0) { + TRAP(err, iImageBitmap1 = &iImageBuffer1->BitmapL(0)); + if (err) { + if (iImageCaptureObserver) + iImageCaptureObserver->MceoHandleError(EErrImageReady, err); + } + } else { + TRAP(err, iImageBitmap2 = &iImageBuffer2->BitmapL(0)); + if (err) { + if (iImageCaptureObserver) + iImageCaptureObserver->MceoHandleError(EErrImageReady, err); + } + } + isBitmap = true; + break; + case CCamera::EFormatExif: + if (iLatestImageBufferIndex == 0) { + TRAP(err, iImageData1 = iImageBuffer1->DataL(0)); + if (err) { + if (iImageCaptureObserver) + iImageCaptureObserver->MceoHandleError(EErrImageReady, err); + } + } else { + TRAP(err, iImageData2 = iImageBuffer2->DataL(0)); + if (err) { + if (iImageCaptureObserver) + iImageCaptureObserver->MceoHandleError(EErrImageReady, err); + } + } + isBitmap = false; + break; + + default: + if (iImageCaptureObserver) + iImageCaptureObserver->MceoHandleError(EErrImageReady, KErrNotSupported); + return; + } + + // Handle captured image + HandleImageReady(aError, isBitmap); +} + +/* + * MCameraObserver + * Captured image is ready (NewL version) + */ +void CCameraEngine::ImageReady(CFbsBitmap* aBitmap, HBufC8* aData, TInt aError) +{ + bool isBitmap = true; + + // Toggle between the 2 buffers + if (iLatestImageBufferIndex == 1) { + iLatestImageBufferIndex = 0; + } else { + iLatestImageBufferIndex = 1; + } + + switch (iImageCaptureFormat) { + case CCamera::EFormatFbsBitmapColor4K: + case CCamera::EFormatFbsBitmapColor64K: + case CCamera::EFormatFbsBitmapColor16M: + case CCamera::EFormatFbsBitmapColor16MU: + if (iLatestImageBufferIndex == 0) + iImageBitmap1 = aBitmap; + else + iImageBitmap2 = aBitmap; + isBitmap = true; + break; + case CCamera::EFormatExif: + if (iLatestImageBufferIndex == 0) + iImageData1 = aData; + else + iImageData2 = aData; + isBitmap = false; + break; + + default: + if (iImageCaptureObserver) + iImageCaptureObserver->MceoHandleError(EErrImageReady, KErrNotSupported); + return; + } + + // Handle captured image + HandleImageReady(aError, isBitmap); +} + +void CCameraEngine::HandleImageReady(const TInt aError, const bool isBitmap) +{ + iEngineState = EEngineIdle; + + if (aError == KErrNone) { + if (isBitmap) + if (iImageCaptureObserver) { + if (iLatestImageBufferIndex == 0) + iImageCaptureObserver->MceoCapturedBitmapReady(iImageBitmap1); + else + iImageCaptureObserver->MceoCapturedBitmapReady(iImageBitmap2); + } + else + ReleaseImageBuffer(); + else { + if (iImageCaptureObserver) { + if (iLatestImageBufferIndex == 0) + iImageCaptureObserver->MceoCapturedDataReady(iImageData1); + else + iImageCaptureObserver->MceoCapturedDataReady(iImageData2); + } + else + ReleaseImageBuffer(); + } + } else { + if (iImageCaptureObserver) + iImageCaptureObserver->MceoHandleError(EErrImageReady, aError); + } +} + +#ifdef ECAM_PREVIEW_API +void CCameraEngine::HandlePreview() +{ + if (!iCameraSnapshot) { + if (iObserver) + iObserver->MceoHandleError(EErrPreview, KErrGeneral); + return; + } + + RArray<TInt> previewIndices; + CleanupClosePushL(previewIndices); + + MCameraBuffer &newPreview = iCameraSnapshot->SnapshotDataL(previewIndices); + + for (TInt i = 0; i < previewIndices.Count(); ++i) + iPreviewObserver->MceoPreviewReady(newPreview.BitmapL(0)); + + CleanupStack::PopAndDestroy(); // RArray<TInt> previewIndices +} + +TSize CCameraEngine::SelectPreviewResolution() +{ + TSize currentResolution(iCaptureResolution); + + TSize previewResolution(0, 0); + if (currentResolution == TSize(4000,2248) || + currentResolution == TSize(3264,1832) || + currentResolution == TSize(2592,1456) || + currentResolution == TSize(1920,1080) || + currentResolution == TSize(1280,720)) { + previewResolution = KDefaultSizePreview_Wide; + } else if (currentResolution == TSize(352,288) || + currentResolution == TSize(176,144)) { + previewResolution = KDefaultSizePreview_CIF; + } else if (currentResolution == TSize(720,576)) { + previewResolution = KDefaultSizePreview_PAL; + } else if (currentResolution == TSize(720,480)) { + previewResolution = KDefaultSizePreview_NTSC; + } else { + previewResolution = KDefaultSizePreview_Normal; + } + + return previewResolution; +} +#endif // ECAM_PREVIEW_API + +//============================================================================= +// S60 3.1 - AutoFocus support (Other platforms, see S60CameraSettings class) +//============================================================================= + +void CCameraEngine::InitComplete(TInt aError) +{ + if (aError) { + if (iImageCaptureObserver) + iImageCaptureObserver->MceoHandleError(EErrAutoFocusInit, aError); + } +} + +void CCameraEngine::OptimisedFocusComplete(TInt aError) +{ + iEngineState = EEngineIdle; + + if (aError == KErrNone) + if (iImageCaptureObserver) + iImageCaptureObserver->MceoFocusComplete(); + else { + if (iImageCaptureObserver) + iImageCaptureObserver->MceoHandleError(EErrOptimisedFocusComplete, aError); + } +} + +TBool CCameraEngine::IsCameraReady() const +{ + // If reserved and powered on, but not focusing or capturing + if (iEngineState == EEngineIdle) + return ETrue; + + return EFalse; +} + +TBool CCameraEngine::IsDirectViewFinderSupported() const +{ + if (iCameraInfo.iOptionsSupported & TCameraInfo::EViewFinderDirectSupported) + return true; + else + return false; +} + +TCameraInfo *CCameraEngine::CameraInfo() +{ + return &iCameraInfo; +} + +TBool CCameraEngine::IsAutoFocusSupported() const +{ +#ifndef Q_CC_NOKIAX86 // Not Emulator + +#ifdef S60_CAM_AUTOFOCUS_SUPPORT // S60 3.1 + return (iAutoFocus) ? ETrue : EFalse; +#else // !S60_CAM_AUTOFOCUS_SUPPORT + return EFalse; +#endif // S60_CAM_AUTOFOCUS_SUPPORT + +#else // Q_CC_NOKIAX86 - Emulator + return EFalse; +#endif // !Q_CC_NOKIAX86 +} + +/* + * This function is used for focusing in S60 3.1 platform. Platforms from S60 + * 3.2 onwards should use the focusing provided by the S60CameraSettings class. + */ +void CCameraEngine::StartFocusL() +{ + if (iEngineState != EEngineIdle) + return; + +#ifndef Q_CC_NOKIAX86 // Not Emulator +#ifdef S60_CAM_AUTOFOCUS_SUPPORT // S60 3.1 + if (iAutoFocus) { + if (!iAFRange) { + iAFRange = CCamAutoFocus::ERangeNormal; + iAutoFocus->SetFocusRangeL(iAFRange); + } + + iAutoFocus->AttemptOptimisedFocusL(); + iEngineState = EEngineFocusing; + } +#endif // S60_CAM_AUTOFOCUS_SUPPORT +#endif // !Q_CC_NOKIAX86 +} + +/* + * This function is used for cancelling focusing in S60 3.1 platform. Platforms + * from S60 3.2 onwards should use the focusing provided by the + * S60CameraSettings class. + */ +void CCameraEngine::FocusCancel() +{ +#ifndef Q_CC_NOKIAX86 // Not Emulator +#ifdef S60_CAM_AUTOFOCUS_SUPPORT + if (iAutoFocus) { + iAutoFocus->Cancel(); + iEngineState = EEngineIdle; + } +#endif // S60_CAM_AUTOFOCUS_SUPPORT +#endif // !Q_CC_NOKIAX86 +} + +void CCameraEngine::SupportedFocusRanges(TInt& aSupportedRanges) const +{ + aSupportedRanges = 0; + +#ifndef Q_CC_NOKIAX86 // Not Emulator +#ifdef S60_CAM_AUTOFOCUS_SUPPORT + if (iAutoFocus) { + // CCamAutoFocus doesn't provide a method for getting supported ranges! + // Assume everything is supported (rather optimistic) + aSupportedRanges = CCamAutoFocus::ERangeMacro | + CCamAutoFocus::ERangePortrait | + CCamAutoFocus::ERangeNormal | + CCamAutoFocus::ERangeInfinite; + } +#endif // S60_CAM_AUTOFOCUS_SUPPORT +#endif // !Q_CC_NOKIAX86 +} + +void CCameraEngine::SetFocusRange(TInt aFocusRange) +{ +#if !defined(Q_CC_NOKIAX86) // Not Emulator + +#ifdef S60_CAM_AUTOFOCUS_SUPPORT + if (iAutoFocus) { + TRAPD(focusErr, iAutoFocus->SetFocusRangeL((CCamAutoFocus::TAutoFocusRange)aFocusRange)); + if (focusErr) + iObserver->MceoHandleError(EErrAutoFocusRange, focusErr); + } +#endif // S60_CAM_AUTOFOCUS_SUPPORT + +#else // Q_CC_NOKIAX86 // Emulator + Q_UNUSED(aFocusRange); + if (iImageCaptureObserver) + iImageCaptureObserver->MceoHandleError(EErrAutoFocusRange, KErrNotSupported); +#endif // !Q_CC_NOKIAX86 +} + +// End of file diff --git a/src/plugins/symbian/ecam/s60cameraengine.h b/src/plugins/symbian/ecam/s60cameraengine.h new file mode 100644 index 000000000..7a925c0ba --- /dev/null +++ b/src/plugins/symbian/ecam/s60cameraengine.h @@ -0,0 +1,407 @@ +/**************************************************************************** + ** + ** 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$ + ** + ****************************************************************************/ +#ifndef S60CCAMERAENGINE_H +#define S60CCAMERAENGINE_H + +// INCLUDES +#include <e32base.h> +#include <ecam.h> // for MCameraObserver(2) +#ifdef S60_CAM_AUTOFOCUS_SUPPORT +#include <ccamautofocus.h> // for CCamAutoFocus, MCamAutoFocusObserver +#endif + +// FORWARD DECLARATIONS +class MCameraEngineObserver; +class MCameraEngineImageCaptureObserver; +class MAdvancedSettingsObserver; +class MCameraViewfinderObserver; +class MCameraPreviewObserver; + +/* + * CameraEngine handling ECam operations needed. + */ +NONSHARABLE_CLASS( CCameraEngine ) : public CBase, + public MCameraObserver, + public MCameraObserver2 +#ifdef S60_CAM_AUTOFOCUS_SUPPORT + ,public MCamAutoFocusObserver +#endif + +{ +public: // Enums + + enum TCameraEngineState + { + EEngineNotReady = 0, // 0 - No resources reserved + EEngineInitializing, // 1 - Reserving and Powering On + EEngineIdle, // 2 - Reseved and Powered On + EEngineCapturing, // 3 - Capturing Still Image + EEngineFocusing // 4 - Focusing + }; + +public: // Constructor & Destructor + + static CCameraEngine* NewL( TInt aCameraHandle, + TInt aPriority, + MCameraEngineObserver* aObserver ); + ~CCameraEngine(); + +public: + + /** + * External Advanced Settings callback observer. + */ + void SetAdvancedObserver(MAdvancedSettingsObserver *aAdvancedSettingsObserver); + + /** + * External Image Capture callback observer. + */ + void SetImageCaptureObserver(MCameraEngineImageCaptureObserver *aImageCaptureObserver); + + /** + * External Viewfinder callback observer. + */ + void SetViewfinderObserver(MCameraViewfinderObserver *aViewfinderObserver); + + /** + * Static function that returns the number of cameras on the device. + */ + static TInt CamerasAvailable(); + + /** + * Returns the index of the currently active camera device + */ + TInt CurrentCameraIndex() const { return iCameraIndex; } + + /** + * Returns the current state (TCameraEngineState) + * of the camera engine. + */ + TCameraEngineState State() const { return iEngineState; } + + /** + * Returns true if the camera has been reserved and + * powered on, and not recording or capturing image + */ + TBool IsCameraReady() const; + + /** + * Returns whether DirectScreen ViewFinder is supported by the platform + */ + TBool IsDirectViewFinderSupported() const; + + /** + * Returns true if the camera supports AutoFocus. + */ + TBool IsAutoFocusSupported() const; + + /** + * Returns camera info + */ + TCameraInfo *CameraInfo(); + + /** + * Captures an image. When complete, observer will receive + * MceoCapturedDataReady() or MceoCapturedBitmapReady() callback, + * depending on which image format was used in PrepareL(). + * @leave May leave with KErrNotReady if camera is not + * reserved or prepared for capture. + */ + void CaptureL(); + + /** + * Cancels ongoing image capture + */ + void CancelCapture(); + + /** + * Reserves and powers on the camera. When complete, + * observer will receive MceoCameraReady() callback + * + */ + void ReserveAndPowerOn(); + + /** + * Releases and powers off the camera + * + */ + void ReleaseAndPowerOff(); + + /** + * Prepares for image capture. + * @param aCaptureSize requested capture size. On return, + * contains the selected size (closest match) + * @param aFormat Image format to use. Default is JPEG with + * EXIF information as provided by the camera module + * @leave KErrNotSupported, KErrNoMemory, KErrNotReady + */ + void PrepareL( TSize& aCaptureSize, + CCamera::TFormat aFormat = CCamera::EFormatExif ); + + /** + * Starts the viewfinder. Observer will receive + * MceoViewFinderFrameReady() callbacks periodically. + * @param aSize requested viewfinder size. On return, + * contains the selected size. + * + * @leave KErrNotSupported is viewfinding with bitmaps is not + * supported, KErrNotReady + */ + void StartViewFinderL( TSize& aSize ); + + /** + * Stops the viewfinder if active. + */ + void StopViewFinder(); + + void StartDirectViewFinderL(RWsSession& aSession, + CWsScreenDevice& aScreenDevice, + RWindowBase& aWindow, + TRect& aScreenRect, + TRect& aClipRect); + + /** + * Releases memory for the last received viewfinder frame. + * Client must call this in response to MceoViewFinderFrameReady() + * callback, after drawing the viewfinder frame is complete. + */ + void ReleaseViewFinderBuffer(); + + /** + * Releases memory for the last captured image. + * Client must call this in response to MceoCapturedDataReady() + * or MceoCapturedBitmapReady()callback, after processing the + * data/bitmap is complete. + */ + void ReleaseImageBuffer(); + + /** + * Starts focusing. Does nothing if AutoFocus is not supported. + * When complete, observer will receive MceoFocusComplete() + * callback. + * @leave KErrInUse, KErrNotReady + */ + void StartFocusL(); + + /** + * Cancels the ongoing focusing operation. + */ + void FocusCancel(); + + /** + * Gets a bitfield of supported focus ranges. + * @param aSupportedRanges a bitfield of either TAutoFocusRange + * (S60 3.0/3.1 devices) or TFocusRange (S60 3.2 and onwards) values + */ + void SupportedFocusRanges( TInt& aSupportedRanges ) const; + + /** + * Sets the focus range + * @param aFocusRange one of the values returned by + * SupportedFocusRanges(). + */ + void SetFocusRange( TInt aFocusRange ); + + /** + * Returns a pointer to CCamera object used by the engine. + * Allows getting access to additional functionality + * from CCamera - do not use for functionality already provided + * by CCameraEngine methods. + */ + CCamera* Camera() { return iCamera; } + +#ifdef ECAM_PREVIEW_API + /** + * This enables the preview creation during the capture (image or video). + */ + void EnablePreviewProvider(MCameraPreviewObserver *aPreviewObserver); + + /** + * This disabled the preview creation during the capture (image or video) + */ + void DisablePreviewProvider(); +#endif // ECAM_PREVIEW_API + +protected: // Protected constructors + + CCameraEngine(); + CCameraEngine( TInt aCameraHandle, + TInt aPriority, + MCameraEngineObserver* aObserver ); + void ConstructL(); + +protected: // MCameraObserver + + /** + * From MCameraObserver + * Gets called when CCamera::Reserve() is completed. + * (V2: Called internally from HandleEvent) + */ + virtual void ReserveComplete(TInt aError); + + /** + * From MCameraObserver. + * Gets called when CCamera::PowerOn() is completed. + * (V2: Called internally from HandleEvent) + */ + virtual void PowerOnComplete(TInt aError); + + /** + * From MCameraObserver. + * Gets called when CCamera::StartViewFinderBitmapsL() is completed. + * (V2: Called internally from ViewFinderReady) + */ + virtual void ViewFinderFrameReady( CFbsBitmap& aFrame ); + + /** + * From MCameraObserver. + * Gets called when CCamera::CaptureImage() is completed. + */ + virtual void ImageReady( CFbsBitmap* aBitmap, HBufC8* aData, TInt aError ); + + /** + * From MCameraObserver. + * Video capture not implemented. + */ + virtual void FrameBufferReady( MFrameBuffer* /*aFrameBuffer*/, TInt /*aError*/ ) {} + +protected: // MCameraObserver2 + + /** + * From MCameraObserver2 + * Camera event handler + */ + virtual void HandleEvent(const TECAMEvent &aEvent); + + /** + * From MCameraObserver2 + * Notifies the client of new viewfinder data + */ + virtual void ViewFinderReady(MCameraBuffer &aCameraBuffer, TInt aError); + + /** + * From MCameraObserver2 + * Notifies the client of a new captured image + */ + virtual void ImageBufferReady(MCameraBuffer &aCameraBuffer, TInt aError); + + /** + * From MCameraObserver2 + * Video capture not implemented. + */ + virtual void VideoBufferReady(MCameraBuffer& /*aCameraBuffer*/, TInt /*aError*/) {} + +protected: // MCamAutoFocusObserver + + /** + * From MCamAutoFocusObserver. + * Delivers notification of completion of auto focus initialisation to + * an interested party. + * @param aError Reason for completion of focus request. + */ + virtual void InitComplete( TInt aError ); + + /** + * From MCamAutoFocusObserver. + * Gets called when CCamAutoFocus::AttemptOptimisedFocusL() is + * completed. + * (V2: Called internally from HandleEvent) + */ + virtual void OptimisedFocusComplete( TInt aError ); + +private: // Internal functions + + /** + * Internal function to handle ImageReady callbacks from + * both observer (V1 & V2) interfaces + */ + void HandleImageReady(const TInt aError, const bool isBitmap); + +#ifdef ECAM_PREVIEW_API + /** + * Handle preview. Retrieve preview data and notify observer about the + * preview availability. + */ + void HandlePreview(); + + /** + * Calculate proper resolution for the SnapShot (Preview) image. + */ + TSize SelectPreviewResolution(); +#endif // ECAM_PREVIEW_API + +private: // Data + + CCamera *iCamera; + MCameraEngineObserver *iObserver; + MCameraEngineImageCaptureObserver *iImageCaptureObserver; + MAdvancedSettingsObserver *iAdvancedSettingsObserver; + MCameraViewfinderObserver *iViewfinderObserver; + MCameraPreviewObserver *iPreviewObserver; + MCameraBuffer *iViewFinderBuffer; + /* + * Following pointers are for the image buffers: + * * Makes buffering of 2 concurrent image buffers possible + */ + MCameraBuffer *iImageBuffer1; + MCameraBuffer *iImageBuffer2; + TDesC8 *iImageData1; + TDesC8 *iImageData2; + CFbsBitmap *iImageBitmap1; + CFbsBitmap *iImageBitmap2; + TInt iCameraIndex; + TInt iPriority; + TCameraEngineState iEngineState; + TCameraInfo iCameraInfo; + CCamera::TFormat iImageCaptureFormat; + TSize iCaptureResolution; + bool iNew2LImplementation; + int iLatestImageBufferIndex; // 0 = Buffer1, 1 = Buffer2 +#ifdef ECAM_PREVIEW_API + CCamera::CCameraSnapshot *iCameraSnapshot; +#endif // ECAM_PREVIEW_API +#ifdef S60_CAM_AUTOFOCUS_SUPPORT + CCamAutoFocus* iAutoFocus; + CCamAutoFocus::TAutoFocusRange iAFRange; +#endif // S60_CAM_AUTOFOCUS_SUPPORT +}; + +#endif // S60CCAMERAENGINE_H diff --git a/src/plugins/symbian/ecam/s60cameraengineobserver.h b/src/plugins/symbian/ecam/s60cameraengineobserver.h new file mode 100644 index 000000000..b1e669d70 --- /dev/null +++ b/src/plugins/symbian/ecam/s60cameraengineobserver.h @@ -0,0 +1,178 @@ +/**************************************************************************** + ** + ** 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$ + ** + ****************************************************************************/ +#ifndef S60CCAMERAENGINEOBSERVER_H +#define S60CCAMERAENGINEOBSERVER_H + +// FORWARD DECLARATIONS +class CFbsBitmap; +class TECAMEvent; + +enum TCameraEngineError +{ + EErrReserve, + EErrPowerOn, + EErrViewFinderReady, + EErrImageReady, + EErrPreview, + EErrAutoFocusInit, + EErrAutoFocusMode, + EErrAutoFocusArea, + EErrAutoFocusRange, + EErrAutoFocusType, + EErrOptimisedFocusComplete, +}; + +/* + * CameraEngine Observer class towards Camera AdvancedSettings + */ +class MAdvancedSettingsObserver +{ +public: + + virtual void HandleAdvancedEvent( const TECAMEvent &aEvent ) = 0; + +}; + +//============================================================================= + +/* + * CameraEngine Observer class towards Camera Control + */ +class MCameraEngineObserver +{ +public: + + /** + * Camera is ready to use for capturing images. + */ + virtual void MceoCameraReady() = 0; + + /** + * Notifies clients about errors in camera engine + * @param aErrorType type of error (see TCameraEngineError) + * @param aError Symbian system-wide error code + */ + virtual void MceoHandleError( TCameraEngineError aErrorType, TInt aError ) = 0; + +}; + +//============================================================================= + +/* + * CameraEngine Observer class towards Camera ImageCaptureSession + */ +class MCameraEngineImageCaptureObserver +{ +public: + + /** + * Camera AF lens has attained optimal focus + */ + virtual void MceoFocusComplete() = 0; + + /** + * Captured data is ready - call CCameraEngine::ReleaseImageBuffer() + * after processing/saving the data (typically, JPG-encoded image) + * @param aData Pointer to a descriptor containing a frame of camera data. + */ + virtual void MceoCapturedDataReady( TDesC8* aData ) = 0; + + /** + * Captured bitmap is ready. + * after processing/saving the image, call + * CCameraEngine::ReleaseImageBuffer() to free the bitmap. + * @param aBitmap Pointer to an FBS bitmap containing a captured image. + */ + virtual void MceoCapturedBitmapReady( CFbsBitmap* aBitmap ) = 0; + + /** + * Notifies clients about errors in camera engine + * @param aErrorType type of error (see TCameraEngineError) + * @param aError Symbian system-wide error code + */ + virtual void MceoHandleError( TCameraEngineError aErrorType, TInt aError ) = 0; + + /** + * Notifies client about other events not recognized by camera engine. + * The default implementation is empty. + * @param aEvent camera event (see MCameraObserver2::HandleEvent()) + */ + virtual void MceoHandleOtherEvent( const TECAMEvent& /*aEvent*/ ) {} +}; + +//============================================================================= + +/* + * CameraEngine Observer class towards Camera ViewFinderEngine + */ +class MCameraViewfinderObserver +{ +public: + /** + * A new viewfinder frame is ready. + * after displaying the frame, call + * CCameraEngine::ReleaseViewFinderBuffer() + * to free the bitmap. + * @param aFrame Pointer to an FBS bitmap containing a viewfinder frame. + */ + virtual void MceoViewFinderFrameReady( CFbsBitmap& aFrame ) = 0; +}; + +//============================================================================= + +#ifdef ECAM_PREVIEW_API +/* + * CameraEngine Observer class towards Camera ViewFinderEngine + */ +class MCameraPreviewObserver +{ +public: + /** + * A new preview is available. + * @param aPreview Pointer to an FBS bitmap containing a preview. + */ + virtual void MceoPreviewReady( CFbsBitmap& aPreview ) = 0; +}; +#endif // ECAM_PREVIEW_API + +#endif // CCAMERAENGINEOBSERVER_H + +// End of file diff --git a/src/plugins/symbian/ecam/s60cameraexposurecontrol.cpp b/src/plugins/symbian/ecam/s60cameraexposurecontrol.cpp new file mode 100644 index 000000000..9ebdd2c6e --- /dev/null +++ b/src/plugins/symbian/ecam/s60cameraexposurecontrol.cpp @@ -0,0 +1,584 @@ +/**************************************************************************** +** +** 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 "s60cameraexposurecontrol.h" +#include "s60cameraservice.h" +#include "s60imagecapturesession.h" + +S60CameraExposureControl::S60CameraExposureControl(QObject *parent) : + QCameraExposureControl(parent) +{ +} + +S60CameraExposureControl::S60CameraExposureControl(S60ImageCaptureSession *session, QObject *parent) : + QCameraExposureControl(parent), + m_session(0), + m_service(0), + m_advancedSettings(0), + m_exposureMode(QCameraExposure::ExposureAuto), + m_meteringMode(QCameraExposure::MeteringMatrix) +{ + m_session = session; + + connect(m_session, SIGNAL(advancedSettingChanged()), this, SLOT(resetAdvancedSetting())); + m_advancedSettings = m_session->advancedSettings(); + + if (m_advancedSettings) { + connect(m_advancedSettings, SIGNAL(apertureChanged()), this, SLOT(apertureChanged())); + connect(m_advancedSettings, SIGNAL(apertureRangeChanged()), this, SLOT(apertureRangeChanged())); + connect(m_advancedSettings, SIGNAL(shutterSpeedChanged()), this, SLOT(shutterSpeedChanged())); + connect(m_advancedSettings, SIGNAL(isoSensitivityChanged()), this, SLOT(isoSensitivityChanged())); + connect(m_advancedSettings, SIGNAL(evChanged()), this, SLOT(evChanged())); + } +} + +S60CameraExposureControl::~S60CameraExposureControl() +{ + m_advancedSettings = 0; +} + +void S60CameraExposureControl::resetAdvancedSetting() +{ + m_advancedSettings = m_session->advancedSettings(); + if (m_advancedSettings) { + connect(m_advancedSettings, SIGNAL(apertureChanged()), this, SLOT(apertureChanged())); + connect(m_advancedSettings, SIGNAL(apertureRangeChanged()), this, SLOT(apertureRangeChanged())); + connect(m_advancedSettings, SIGNAL(shutterSpeedChanged()), this, SLOT(shutterSpeedChanged())); + connect(m_advancedSettings, SIGNAL(isoSensitivityChanged()), this, SLOT(isoSensitivityChanged())); + connect(m_advancedSettings, SIGNAL(evChanged()), this, SLOT(evChanged())); + } +} + +void S60CameraExposureControl::apertureChanged() +{ + emit exposureParameterChanged(QCameraExposureControl::Aperture); +} + +void S60CameraExposureControl::apertureRangeChanged() +{ + emit exposureParameterRangeChanged(QCameraExposureControl::Aperture); +} + +void S60CameraExposureControl::shutterSpeedChanged() +{ + emit exposureParameterChanged(QCameraExposureControl::ShutterSpeed); +} + +void S60CameraExposureControl::isoSensitivityChanged() +{ + emit exposureParameterChanged(QCameraExposureControl::ISO); +} + +void S60CameraExposureControl::evChanged() +{ + emit exposureParameterChanged(QCameraExposureControl::ExposureCompensation); +} + +QCameraExposure::ExposureMode S60CameraExposureControl::exposureMode() const +{ + return m_session->exposureMode(); +} + +void S60CameraExposureControl::setExposureMode(QCameraExposure::ExposureMode mode) +{ + if (isExposureModeSupported(mode)) { + m_exposureMode = mode; + m_session->setExposureMode(m_exposureMode); + return; + } + + m_session->setError(KErrNotSupported, tr("Requested exposure mode is not supported.")); +} + +bool S60CameraExposureControl::isExposureModeSupported(QCameraExposure::ExposureMode mode) const +{ + if (m_session->isExposureModeSupported(mode)) + return true; + + return false; +} + +QCameraExposure::MeteringMode S60CameraExposureControl::meteringMode() const +{ + if (m_advancedSettings) + return m_advancedSettings->meteringMode(); + + return QCameraExposure::MeteringMode(); +} + +void S60CameraExposureControl::setMeteringMode(QCameraExposure::MeteringMode mode) +{ + if (m_advancedSettings) { + if (isMeteringModeSupported(mode)) { + m_meteringMode = mode; + m_advancedSettings->setMeteringMode(mode); + return; + } + } + + m_session->setError(KErrNotSupported, tr("Requested metering mode is not supported.")); +} + +bool S60CameraExposureControl::isMeteringModeSupported(QCameraExposure::MeteringMode mode) const +{ + if (m_advancedSettings) + return m_advancedSettings->isMeteringModeSupported(mode); + + return false; +} + +bool S60CameraExposureControl::isParameterSupported(ExposureParameter parameter) const +{ + // Settings supported only if advanced settings available + if (m_advancedSettings) { + switch (parameter) { + case QCameraExposureControl::ISO: + if (m_advancedSettings->supportedIsoSensitivities().count() > 0) + return true; + else + return false; + case QCameraExposureControl::Aperture: + if (m_advancedSettings->supportedApertures().count() > 0) + return true; + else + return false; + case QCameraExposureControl::ShutterSpeed: + if (m_advancedSettings->supportedShutterSpeeds().count() > 0) + return true; + else + return false; + case QCameraExposureControl::ExposureCompensation: + if (m_advancedSettings->supportedExposureCompensationValues().count() > 0) + return true; + else + return false; + case QCameraExposureControl::FlashPower: + case QCameraExposureControl::FlashCompensation: + return false; + + default: + return false; + } + } + + return false; +} + +QVariant S60CameraExposureControl::exposureParameter(ExposureParameter parameter) const +{ + switch (parameter) { + case QCameraExposureControl::ISO: + return QVariant(isoSensitivity()); + case QCameraExposureControl::Aperture: + return QVariant(aperture()); + case QCameraExposureControl::ShutterSpeed: + return QVariant(shutterSpeed()); + case QCameraExposureControl::ExposureCompensation: + return QVariant(exposureCompensation()); + case QCameraExposureControl::FlashPower: + case QCameraExposureControl::FlashCompensation: + // Not supported in Symbian + return QVariant(); + + default: + // Not supported in Symbian + return QVariant(); + } +} + +QCameraExposureControl::ParameterFlags S60CameraExposureControl::exposureParameterFlags(ExposureParameter parameter) const +{ + QCameraExposureControl::ParameterFlags flags; + + /* + * ISO, ExposureCompensation: + * - Automatic/Manual + * - Read/Write + * - Discrete range + * + * Aperture, ShutterSpeed, FlashPower, FlashCompensation: + * - Not supported + */ + switch (parameter) { + case QCameraExposureControl::ISO: + case QCameraExposureControl::ExposureCompensation: + flags |= QCameraExposureControl::AutomaticValue; + break; + case QCameraExposureControl::Aperture: + case QCameraExposureControl::ShutterSpeed: + case QCameraExposureControl::FlashPower: + case QCameraExposureControl::FlashCompensation: + // Do nothing - no flags + break; + + default: + // Do nothing - no flags + break; + } + + return flags; +} + +QVariantList S60CameraExposureControl::supportedParameterRange(ExposureParameter parameter) const +{ + QVariantList valueList; + + if (m_advancedSettings) { + switch (parameter) { + case QCameraExposureControl::ISO: { + foreach (int iso, m_advancedSettings->supportedIsoSensitivities()) + valueList << QVariant(iso); + break; + } + case QCameraExposureControl::Aperture: { + foreach (qreal aperture, m_advancedSettings->supportedApertures()) + valueList << QVariant(aperture); + break; + } + case QCameraExposureControl::ShutterSpeed: { + foreach (qreal shutterSpeed, m_advancedSettings->supportedShutterSpeeds()) + valueList << QVariant(shutterSpeed); + break; + } + case QCameraExposureControl::ExposureCompensation: { + foreach (qreal ev, m_advancedSettings->supportedExposureCompensationValues()) + valueList << QVariant(ev); + break; + } + case QCameraExposureControl::FlashPower: + case QCameraExposureControl::FlashCompensation: + // Not supported in Symbian + break; + + default: + // Not supported in Symbian + break; + } + } + + return valueList; +} + +bool S60CameraExposureControl::setExposureParameter(ExposureParameter parameter, const QVariant& value) +{ + bool useDefaultValue = false; + + if (value.isNull()) + useDefaultValue = true; + + switch (parameter) { + case QCameraExposureControl::ISO: + if (useDefaultValue) { + setAutoIsoSensitivity(); + return false; + } + else + return setManualIsoSensitivity(value.toInt()); + + case QCameraExposureControl::Aperture: + if (useDefaultValue) { + setAutoAperture(); + return false; + } + else + return setManualAperture(value.toFloat()); + + case QCameraExposureControl::ShutterSpeed: + if (useDefaultValue) { + setAutoShutterSpeed(); + return false; + } + else + return setManualShutterSpeed(value.toFloat()); + + case QCameraExposureControl::ExposureCompensation: + if (useDefaultValue) { + setAutoExposureCompensation(); + return false; + } + else + return setManualExposureCompensation(value.toFloat()); + + case QCameraExposureControl::FlashPower: + return false; + case QCameraExposureControl::FlashCompensation: + return false; + + default: + // Not supported in Symbian + return false; + } +} + +QString S60CameraExposureControl::extendedParameterName(ExposureParameter parameter) +{ + switch (parameter) { + case QCameraExposureControl::ISO: + return QLatin1String("ISO Sensitivity"); + case QCameraExposureControl::Aperture: + return QLatin1String("Aperture"); + case QCameraExposureControl::ShutterSpeed: + return QLatin1String("Shutter Speed"); + case QCameraExposureControl::ExposureCompensation: + return QLatin1String("Exposure Compensation"); + case QCameraExposureControl::FlashPower: + return QLatin1String("Flash Power"); + case QCameraExposureControl::FlashCompensation: + return QLatin1String("Flash Compensation"); + + default: + return QString(); + } +} + +int S60CameraExposureControl::isoSensitivity() const +{ + if (m_advancedSettings) + return m_advancedSettings->isoSensitivity(); + return 0; +} + +bool S60CameraExposureControl::isIsoSensitivitySupported(const int iso) const +{ + if (m_advancedSettings && + m_advancedSettings->supportedIsoSensitivities().contains(iso)) + return true; + else + return false; +} + +bool S60CameraExposureControl::setManualIsoSensitivity(int iso) +{ + if (m_advancedSettings) { + if (isIsoSensitivitySupported(iso)) { + m_advancedSettings->setManualIsoSensitivity(iso); + return true; + } + } + + return false; +} + +void S60CameraExposureControl::setAutoIsoSensitivity() +{ + if (m_advancedSettings) + m_advancedSettings->setAutoIsoSensitivity(); +} + +qreal S60CameraExposureControl::aperture() const +{ + if (m_advancedSettings) + return m_advancedSettings->aperture(); + return 0.0; +} + +bool S60CameraExposureControl::isApertureSupported(const qreal aperture) const +{ + if (m_advancedSettings) { + QList<qreal> supportedValues = m_advancedSettings->supportedApertures(); + if(supportedValues.indexOf(aperture) != -1) + return true; + } + + return false; +} + +bool S60CameraExposureControl::setManualAperture(qreal aperture) +{ + if (m_advancedSettings) { + if (isApertureSupported(aperture)) { + m_advancedSettings->setManualAperture(aperture); + return true; + } else { + QList<qreal> supportedApertureValues = m_advancedSettings->supportedApertures(); + int minAperture = supportedApertureValues.first(); + int maxAperture = supportedApertureValues.last(); + + if (aperture < minAperture) { // Smaller than minimum + aperture = minAperture; + } else if (aperture > maxAperture) { // Bigger than maximum + aperture = maxAperture; + } else { // Find closest + int indexOfClosest = 0; + int smallestDiff = 100000000; // Sensible max diff + for(int i = 0; i < supportedApertureValues.count(); ++i) { + if((abs((aperture*100) - (supportedApertureValues[i]*100))) < smallestDiff) { + smallestDiff = abs((aperture*100) - (supportedApertureValues[i]*100)); + indexOfClosest = i; + } + } + aperture = supportedApertureValues[indexOfClosest]; + } + m_advancedSettings->setManualAperture(aperture); + } + } + + return false; +} + +void S60CameraExposureControl::setAutoAperture() +{ + // Not supported in Symbian +} + +qreal S60CameraExposureControl::shutterSpeed() const +{ + if (m_advancedSettings) + return m_advancedSettings->shutterSpeed(); + return 0.0; +} + +bool S60CameraExposureControl::isShutterSpeedSupported(const qreal seconds) const +{ + if (m_advancedSettings) { + QList<qreal> supportedValues = m_advancedSettings->supportedShutterSpeeds(); + if(supportedValues.indexOf(seconds) != -1) + return true; + } + + return false; +} + +bool S60CameraExposureControl::setManualShutterSpeed(qreal seconds) +{ + if (m_advancedSettings) { + if (isShutterSpeedSupported(seconds)) { + m_advancedSettings->setManualShutterSpeed(seconds); + return true; + } else { + QList<qreal> supportedShutterSpeeds = m_advancedSettings->supportedShutterSpeeds(); + + if (supportedShutterSpeeds.count() == 0) + return false; + + int minShutterSpeed = supportedShutterSpeeds.first(); + int maxShutterSpeed = supportedShutterSpeeds.last(); + + if (seconds < minShutterSpeed) { // Smaller than minimum + seconds = minShutterSpeed; + } else if (seconds > maxShutterSpeed) { // Bigger than maximum + seconds = maxShutterSpeed; + } else { // Find closest + int indexOfClosest = 0; + int smallestDiff = 100000000; // Sensible max diff + for(int i = 0; i < supportedShutterSpeeds.count(); ++i) { + if((abs((seconds*100) - (supportedShutterSpeeds[i]*100))) < smallestDiff) { + smallestDiff = abs((seconds*100) - (supportedShutterSpeeds[i]*100)); + indexOfClosest = i; + } + } + seconds = supportedShutterSpeeds[indexOfClosest]; + } + m_advancedSettings->setManualShutterSpeed(seconds); + } + } + + return false; +} + +void S60CameraExposureControl::setAutoShutterSpeed() +{ + // Not supported in Symbian +} + +qreal S60CameraExposureControl::exposureCompensation() const +{ + if (m_advancedSettings) + return m_advancedSettings->exposureCompensation(); + return 0.0; +} + +bool S60CameraExposureControl::isExposureCompensationSupported(const qreal ev) const +{ + if (m_advancedSettings) { + QList<qreal> supportedValues = m_advancedSettings->supportedExposureCompensationValues(); + if(supportedValues.indexOf(ev) != -1) + return true; + } + + return false; +} + +bool S60CameraExposureControl::setManualExposureCompensation(qreal ev) +{ + if (m_advancedSettings) { + if (isExposureCompensationSupported(ev)) { + m_advancedSettings->setExposureCompensation(ev); + return true; + } else { + QList<qreal> supportedEVs = m_advancedSettings->supportedExposureCompensationValues(); + + if (supportedEVs.count() == 0) + return false; + + int minEV = supportedEVs.first(); + int maxEV = supportedEVs.last(); + + if (ev < minEV) { // Smaller than minimum + ev = minEV; + } else if (ev > maxEV) { // Bigger than maximum + ev = maxEV; + } else { // Find closest + int indexOfClosest = 0; + int smallestDiff = 100000000; // Sensible max diff + for(int i = 0; i < supportedEVs.count(); ++i) { + if((abs((ev*100) - (supportedEVs[i]*100))) < smallestDiff) { + smallestDiff = abs((ev*100) - (supportedEVs[i]*100)); + indexOfClosest = i; + } + } + ev = supportedEVs[indexOfClosest]; + } + m_advancedSettings->setExposureCompensation(ev); + } + } + + return false; +} + +void S60CameraExposureControl::setAutoExposureCompensation() +{ + // Not supported in Symbian +} + +// End of file diff --git a/src/plugins/symbian/ecam/s60cameraexposurecontrol.h b/src/plugins/symbian/ecam/s60cameraexposurecontrol.h new file mode 100644 index 000000000..1c623c774 --- /dev/null +++ b/src/plugins/symbian/ecam/s60cameraexposurecontrol.h @@ -0,0 +1,138 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef S60CAMERAEXPOSURECONTROL_H +#define S60CAMERAEXPOSURECONTROL_H + +#include <qcameraexposurecontrol.h> + +#include "s60camerasettings.h" + +QT_USE_NAMESPACE + +class S60CameraService; +class S60ImageCaptureSession; + +/* + * Control for exposure related camera operation. + */ +class S60CameraExposureControl : public QCameraExposureControl +{ + Q_OBJECT + +public: // Constructors & Destructor + + S60CameraExposureControl(QObject *parent = 0); + S60CameraExposureControl(S60ImageCaptureSession *session, QObject *parent = 0); + ~S60CameraExposureControl(); + +public: // QCameraExposureControl + + // Exposure Mode + QCameraExposure::ExposureMode exposureMode() const; + void setExposureMode(QCameraExposure::ExposureMode mode); + bool isExposureModeSupported(QCameraExposure::ExposureMode mode) const; + + // Metering Mode + QCameraExposure::MeteringMode meteringMode() const; + void setMeteringMode(QCameraExposure::MeteringMode mode); + bool isMeteringModeSupported(QCameraExposure::MeteringMode mode) const; + + // Exposure Parameter + bool isParameterSupported(ExposureParameter parameter) const; + QVariant exposureParameter(ExposureParameter parameter) const; + QCameraExposureControl::ParameterFlags exposureParameterFlags(ExposureParameter parameter) const; + QVariantList supportedParameterRange(ExposureParameter parameter) const; + bool setExposureParameter(ExposureParameter parameter, const QVariant& value); + + QString extendedParameterName(ExposureParameter parameter); + +/* +Q_SIGNALS: // QCameraExposureControl + void exposureParameterChanged(int parameter); + void exposureParameterRangeChanged(int parameter); +*/ + +private slots: // Internal Slots + + void resetAdvancedSetting(); + void apertureChanged(); + void apertureRangeChanged(); + void shutterSpeedChanged(); + void isoSensitivityChanged(); + void evChanged(); + +private: // Internal - Implementing ExposureParameter + + // ISO Sensitivity + int isoSensitivity() const; + bool setManualIsoSensitivity(int iso); + void setAutoIsoSensitivity(); + bool isIsoSensitivitySupported(const int iso) const; + + // Aperture + qreal aperture() const; + bool setManualAperture(qreal aperture); + void setAutoAperture(); + bool isApertureSupported(const qreal aperture) const; + + // Shutter Speed + qreal shutterSpeed() const; + bool setManualShutterSpeed(qreal seconds); + void setAutoShutterSpeed(); + bool isShutterSpeedSupported(const qreal seconds) const; + + // Exposure Compensation + qreal exposureCompensation() const; + bool setManualExposureCompensation(qreal ev); + void setAutoExposureCompensation(); + bool isExposureCompensationSupported(const qreal ev) const; + +private: // Data + + S60ImageCaptureSession *m_session; + S60CameraService *m_service; + S60CameraSettings *m_advancedSettings; + QCameraExposure::ExposureMode m_exposureMode; + QCameraExposure::MeteringMode m_meteringMode; +}; + +#endif // S60CAMERAEXPOSURECONTROL_H diff --git a/src/plugins/symbian/ecam/s60cameraflashcontrol.cpp b/src/plugins/symbian/ecam/s60cameraflashcontrol.cpp new file mode 100644 index 000000000..a18c57a03 --- /dev/null +++ b/src/plugins/symbian/ecam/s60cameraflashcontrol.cpp @@ -0,0 +1,109 @@ +/**************************************************************************** +** +** 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 "s60cameraflashcontrol.h" +#include "s60cameraservice.h" +#include "s60imagecapturesession.h" + +S60CameraFlashControl::S60CameraFlashControl(QObject *parent) : + QCameraFlashControl(parent) +{ +} + +S60CameraFlashControl::S60CameraFlashControl(S60ImageCaptureSession *session, QObject *parent) : + QCameraFlashControl(parent), + m_session(0), + m_service(0), + m_advancedSettings(0), + m_flashMode(QCameraExposure::FlashOff) +{ + m_session = session; + + connect(m_session, SIGNAL(advancedSettingChanged()), this, SLOT(resetAdvancedSetting())); + m_advancedSettings = m_session->advancedSettings(); + + if (m_advancedSettings) + connect(m_advancedSettings, SIGNAL(flashReady(bool)), this, SIGNAL(flashReady(bool))); +} + +S60CameraFlashControl::~S60CameraFlashControl() +{ + m_advancedSettings = 0; +} + +void S60CameraFlashControl::resetAdvancedSetting() +{ + m_advancedSettings = m_session->advancedSettings(); + if (m_advancedSettings) + connect(m_advancedSettings, SIGNAL(flashReady(bool)), this, SIGNAL(flashReady(bool))); +} + +QCameraExposure::FlashModes S60CameraFlashControl::flashMode() const +{ + return m_session->flashMode(); +} + +void S60CameraFlashControl::setFlashMode(QCameraExposure::FlashModes mode) +{ + if (isFlashModeSupported(mode)) { + m_flashMode = mode; + m_session->setFlashMode(m_flashMode); + } + else + m_session->setError(KErrNotSupported, tr("Requested flash mode is not supported.")); +} + +bool S60CameraFlashControl::isFlashModeSupported(QCameraExposure::FlashModes mode) const +{ + return m_session->supportedFlashModes() & mode; +} + +bool S60CameraFlashControl::isFlashReady() const +{ + if (m_advancedSettings) + return m_advancedSettings->isFlashReady(); + + return false; +} + +// End of file diff --git a/src/plugins/symbian/ecam/s60cameraflashcontrol.h b/src/plugins/symbian/ecam/s60cameraflashcontrol.h new file mode 100644 index 000000000..50dbc41dc --- /dev/null +++ b/src/plugins/symbian/ecam/s60cameraflashcontrol.h @@ -0,0 +1,93 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef S60CAMERAFLASHCONTROL_H +#define S60CAMERAFLASHCONTROL_H + +#include <qcameraflashcontrol.h> + +#include "s60camerasettings.h" + +QT_USE_NAMESPACE + +class S60CameraService; +class S60ImageCaptureSession; + +/* + * Control to setup Flash related camera settings. + */ +class S60CameraFlashControl : public QCameraFlashControl +{ + Q_OBJECT + +public: // Constructors & Destructor + + S60CameraFlashControl(QObject *parent = 0); + S60CameraFlashControl(S60ImageCaptureSession *session, QObject *parent = 0); + ~S60CameraFlashControl(); + +public: // QCameraExposureControl + + // Flash Mode + QCameraExposure::FlashModes flashMode() const; + void setFlashMode(QCameraExposure::FlashModes mode); + bool isFlashModeSupported(QCameraExposure::FlashModes mode) const; + + bool isFlashReady() const; + +/* +Q_SIGNALS: // QCameraExposureControl + void flashReady(bool); +*/ + +private slots: // Internal Slots + + void resetAdvancedSetting(); + +private: // Data + + S60ImageCaptureSession *m_session; + S60CameraService *m_service; + S60CameraSettings *m_advancedSettings; + QCameraExposure::FlashModes m_flashMode; +}; + +#endif // S60CAMERAFLASHCONTROL_H diff --git a/src/plugins/symbian/ecam/s60camerafocuscontrol.cpp b/src/plugins/symbian/ecam/s60camerafocuscontrol.cpp new file mode 100644 index 000000000..a7941ce20 --- /dev/null +++ b/src/plugins/symbian/ecam/s60camerafocuscontrol.cpp @@ -0,0 +1,193 @@ +/**************************************************************************** +** +** 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 "s60camerafocuscontrol.h" +#include "s60cameraservice.h" +#include "s60imagecapturesession.h" +#include "s60cameraconstants.h" + +S60CameraFocusControl::S60CameraFocusControl(QObject *parent) : + QCameraFocusControl(parent) +{ +} + +S60CameraFocusControl::S60CameraFocusControl(S60ImageCaptureSession *session, QObject *parent) : + QCameraFocusControl(parent), + m_session(0), + m_service(0), + m_advancedSettings(0), + m_isFocusLocked(false), + m_opticalZoomValue(KDefaultOpticalZoom), + m_digitalZoomValue(KDefaultDigitalZoom), + m_focusMode(KDefaultFocusMode) +{ + m_session = session; + + connect(m_session, SIGNAL(advancedSettingChanged()), this, SLOT(resetAdvancedSetting())); + m_advancedSettings = m_session->advancedSettings(); + + TRAPD(err, m_session->doSetZoomFactorL(m_opticalZoomValue, m_digitalZoomValue)); + if (err) + m_session->setError(KErrNotSupported, tr("Setting default zoom factors failed.")); +} + +S60CameraFocusControl::~S60CameraFocusControl() +{ +} + +QCameraFocus::FocusMode S60CameraFocusControl::focusMode() const +{ + return m_focusMode; +} + +void S60CameraFocusControl::setFocusMode(QCameraFocus::FocusMode mode) +{ + if (isFocusModeSupported(mode)) { + // FocusMode and FocusRange are set. Focusing is triggered by setting + // the corresponding FocusType active by calling searchAndLock in LocksControl. + m_focusMode = mode; + if (m_advancedSettings) + m_advancedSettings->setFocusMode(m_focusMode); + else + m_session->setError(KErrGeneral, tr("Unable to set focus mode before camera is started.")); + } else { + m_session->setError(KErrNotSupported, tr("Requested focus mode is not supported.")); + } +} + +bool S60CameraFocusControl::isFocusModeSupported(QCameraFocus::FocusMode mode) const +{ + if (m_advancedSettings) { + return m_advancedSettings->supportedFocusModes() & mode; + } else { + if (mode == QCameraFocus::AutoFocus) + return m_session->isFocusSupported(); + } + + return false; +} + +qreal S60CameraFocusControl::maximumOpticalZoom() const +{ + return m_session->maximumZoom(); +} + +qreal S60CameraFocusControl::maximumDigitalZoom() const +{ + return m_session->maxDigitalZoom(); +} + +qreal S60CameraFocusControl::opticalZoom() const +{ + return m_session->opticalZoomFactor(); +} + +qreal S60CameraFocusControl::digitalZoom() const +{ + return m_session->digitalZoomFactor(); +} + +void S60CameraFocusControl::zoomTo(qreal optical, qreal digital) +{ + TRAPD(err, m_session->doSetZoomFactorL(optical, digital)); + if (err) + m_session->setError(KErrNotSupported, tr("Requested zoom factor is not supported.")); + + // Query new values + if (m_opticalZoomValue != m_session->opticalZoomFactor()) { + m_opticalZoomValue = m_session->opticalZoomFactor(); + emit opticalZoomChanged(m_opticalZoomValue); + } + if (m_digitalZoomValue != m_session->digitalZoomFactor()) { + m_digitalZoomValue = m_session->digitalZoomFactor(); + emit digitalZoomChanged(m_digitalZoomValue); + } +} + +void S60CameraFocusControl::resetAdvancedSetting() +{ + m_advancedSettings = m_session->advancedSettings(); +} + +QCameraFocus::FocusPointMode S60CameraFocusControl::focusPointMode() const +{ + // Not supported in Symbian + return QCameraFocus::FocusPointAuto; +} + +void S60CameraFocusControl::setFocusPointMode(QCameraFocus::FocusPointMode mode) +{ + if (mode != QCameraFocus::FocusPointAuto) + m_session->setError(KErrNotSupported, tr("Requested focus point mode is not supported.")); +} + +bool S60CameraFocusControl::isFocusPointModeSupported(QCameraFocus::FocusPointMode mode) const +{ + // Not supported in Symbian + if (mode == QCameraFocus::FocusPointAuto) + return true; + else + return false; +} + +QPointF S60CameraFocusControl::customFocusPoint() const +{ + // Not supported in Symbian, return image center + return QPointF(0.5, 0.5); +} + +void S60CameraFocusControl::setCustomFocusPoint(const QPointF &point) +{ + // Not supported in Symbian + Q_UNUSED(point); + m_session->setError(KErrNotSupported, tr("Setting custom focus point is not supported.")); +} + +QCameraFocusZoneList S60CameraFocusControl::focusZones() const +{ + // Not supported in Symbian + return QCameraFocusZoneList(); // Return empty list +} + +// End of file + diff --git a/src/plugins/symbian/ecam/s60camerafocuscontrol.h b/src/plugins/symbian/ecam/s60camerafocuscontrol.h new file mode 100644 index 000000000..28c83ed70 --- /dev/null +++ b/src/plugins/symbian/ecam/s60camerafocuscontrol.h @@ -0,0 +1,112 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef S60CAMERAFOCUSCONTROL_H +#define S60CAMERAFOCUSCONTROL_H + +#include <qcamerafocuscontrol.h> + +#include "s60camerasettings.h" + +QT_USE_NAMESPACE + +class S60CameraService; +class S60ImageCaptureSession; + +/* + * Control for focusing related operations (inc. zooming) + */ +class S60CameraFocusControl : public QCameraFocusControl +{ + Q_OBJECT + +public: // Constructors & Destructor + + S60CameraFocusControl(QObject *parent = 0); + S60CameraFocusControl(S60ImageCaptureSession *session, QObject *parent = 0); + ~S60CameraFocusControl(); + +public: // QCameraFocusControl + + // Focus Mode + QCameraFocus::FocusMode focusMode() const; + void setFocusMode(QCameraFocus::FocusMode mode); + bool isFocusModeSupported(QCameraFocus::FocusMode) const; + + // Zoom + qreal maximumOpticalZoom() const; + qreal maximumDigitalZoom() const; + qreal opticalZoom() const; + qreal digitalZoom() const; + + void zoomTo(qreal optical, qreal digital); + + // Focus Point + QCameraFocus::FocusPointMode focusPointMode() const; + void setFocusPointMode(QCameraFocus::FocusPointMode mode); + bool isFocusPointModeSupported(QCameraFocus::FocusPointMode mode) const; + QPointF customFocusPoint() const; + void setCustomFocusPoint(const QPointF &point); + + QCameraFocusZoneList focusZones() const; + +/* +Q_SIGNALS: // QCameraFocusControl + void opticalZoomChanged(qreal opticalZoom); + void digitalZoomChanged(qreal digitalZoom); + void focusZonesChanged(); +*/ + +private slots: // Internal Slots + + void resetAdvancedSetting(); + +private: // Data + S60ImageCaptureSession *m_session; + S60CameraService *m_service; + S60CameraSettings *m_advancedSettings; + bool m_isFocusLocked; + qreal m_opticalZoomValue; + qreal m_digitalZoomValue; + QCameraFocus::FocusMode m_focusMode; +}; + +#endif // S60CAMERAFOCUSCONTROL_H diff --git a/src/plugins/symbian/ecam/s60cameraimagecapturecontrol.cpp b/src/plugins/symbian/ecam/s60cameraimagecapturecontrol.cpp new file mode 100644 index 000000000..427a3bd97 --- /dev/null +++ b/src/plugins/symbian/ecam/s60cameraimagecapturecontrol.cpp @@ -0,0 +1,124 @@ +/**************************************************************************** +** +** 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 "s60cameraimagecapturecontrol.h" +#include "s60cameraservice.h" +#include "s60imagecapturesession.h" +#include "s60cameracontrol.h" + +S60CameraImageCaptureControl::S60CameraImageCaptureControl(QObject *parent) : + QCameraImageCaptureControl(parent) +{ +} + +S60CameraImageCaptureControl::S60CameraImageCaptureControl(S60CameraService *service, + S60ImageCaptureSession *session, + QObject *parent) : + QCameraImageCaptureControl(parent), + m_driveMode(QCameraImageCapture::SingleImageCapture) // Default DriveMode +{ + m_session = session; + m_service = service; + m_cameraControl = qobject_cast<S60CameraControl *>(m_service->requestControl(QCameraControl_iid)); + + if (!m_cameraControl) + m_session->setError(KErrGeneral, tr("Unexpected camera error.")); + + // Chain these signals from session class + connect(m_session, SIGNAL(imageCaptured(const int, QImage)), + this, SIGNAL(imageCaptured(const int, QImage))); + connect(m_session, SIGNAL(readyForCaptureChanged(bool)), + this, SIGNAL(readyForCaptureChanged(bool)), Qt::QueuedConnection); + connect(m_session, SIGNAL(imageSaved(const int, const QString&)), + this, SIGNAL(imageSaved(const int, const QString&))); + connect(m_session, SIGNAL(imageExposed(int)), + this, SIGNAL(imageExposed(int))); + connect(m_session, SIGNAL(captureError(int, int, const QString&)), + this, SIGNAL(error(int, int, const QString&))); +} + +S60CameraImageCaptureControl::~S60CameraImageCaptureControl() +{ +} + +bool S60CameraImageCaptureControl::isReadyForCapture() const +{ + if (m_cameraControl && m_cameraControl->captureMode() != QCamera::CaptureStillImage) + return false; + + return m_session->isDeviceReady(); +} + +QCameraImageCapture::DriveMode S60CameraImageCaptureControl::driveMode() const +{ + return m_driveMode; +} + +void S60CameraImageCaptureControl::setDriveMode(QCameraImageCapture::DriveMode mode) +{ + if (mode != QCameraImageCapture::SingleImageCapture) { + emit error((m_session->currentImageId() + 1), QCamera::NotSupportedFeatureError, tr("DriveMode not supported.")); + return; + } + + m_driveMode = mode; +} + +int S60CameraImageCaptureControl::capture(const QString &fileName) +{ + if (m_cameraControl && m_cameraControl->captureMode() != QCamera::CaptureStillImage) { + emit error((m_session->currentImageId() + 1), QCameraImageCapture::NotReadyError, tr("Incorrect CaptureMode.")); + return 0; + } + + int imageId = m_session->capture(fileName); + + return imageId; +} + +void S60CameraImageCaptureControl::cancelCapture() +{ + m_session->cancelCapture(); +} + +// End of file diff --git a/src/plugins/symbian/ecam/s60cameraimagecapturecontrol.h b/src/plugins/symbian/ecam/s60cameraimagecapturecontrol.h new file mode 100644 index 000000000..4c369e807 --- /dev/null +++ b/src/plugins/symbian/ecam/s60cameraimagecapturecontrol.h @@ -0,0 +1,99 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef S60CAMERAIMAGECAPTURECONTROL_H +#define S60CAMERAIMAGECAPTURECONTROL_H + +#include "qcameraimagecapturecontrol.h" + +QT_USE_NAMESPACE + +class S60CameraService; +class S60ImageCaptureSession; +class S60CameraControl; + +/* + * Control for image capture operations. + */ +class S60CameraImageCaptureControl : public QCameraImageCaptureControl +{ + Q_OBJECT + +public: // Contructors & Destrcutor + + S60CameraImageCaptureControl(QObject *parent = 0); + S60CameraImageCaptureControl(S60CameraService *service, + S60ImageCaptureSession *session, + QObject *parent = 0); + ~S60CameraImageCaptureControl(); + +public: // QCameraImageCaptureControl + + bool isReadyForCapture() const; + + // Drive Mode + QCameraImageCapture::DriveMode driveMode() const; + void setDriveMode(QCameraImageCapture::DriveMode mode); + + // Capture + int capture(const QString &fileName); + void cancelCapture(); + +/* +Q_SIGNALS: // QCameraImageCaptureControl + void readyForCaptureChanged(bool); + + void imageExposed(int id); + void imageCaptured(int id, const QImage &preview); + void imageSaved(int id, const QString &fileName); + + void error(int id, int error, const QString &errorString); +*/ + +private: // Data + + S60ImageCaptureSession *m_session; + S60CameraService *m_service; + S60CameraControl *m_cameraControl; + QCameraImageCapture::DriveMode m_driveMode; +}; + +#endif // S60CAMERAIMAGECAPTURECONTROL_H diff --git a/src/plugins/symbian/ecam/s60cameraimageprocessingcontrol.cpp b/src/plugins/symbian/ecam/s60cameraimageprocessingcontrol.cpp new file mode 100644 index 000000000..ae2c4535a --- /dev/null +++ b/src/plugins/symbian/ecam/s60cameraimageprocessingcontrol.cpp @@ -0,0 +1,254 @@ +/**************************************************************************** +** +** 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 "s60cameraimageprocessingcontrol.h" +#include "s60cameraservice.h" +#include "s60imagecapturesession.h" + +S60CameraImageProcessingControl::S60CameraImageProcessingControl(QObject *parent) : + QCameraImageProcessingControl(parent) +{ +} + +S60CameraImageProcessingControl::S60CameraImageProcessingControl(S60ImageCaptureSession *session, QObject *parent) : + QCameraImageProcessingControl(parent), + m_session(0), + m_advancedSettings(0) +{ + m_session = session; + m_advancedSettings = m_session->advancedSettings(); +} + +S60CameraImageProcessingControl::~S60CameraImageProcessingControl() +{ + m_advancedSettings = 0; +} + +void S60CameraImageProcessingControl::resetAdvancedSetting() +{ + m_advancedSettings = m_session->advancedSettings(); +} + +QCameraImageProcessing::WhiteBalanceMode S60CameraImageProcessingControl::whiteBalanceMode() const +{ + return m_session->whiteBalanceMode(); +} + +void S60CameraImageProcessingControl::setWhiteBalanceMode(QCameraImageProcessing::WhiteBalanceMode mode) +{ + if (isWhiteBalanceModeSupported(mode)) + m_session->setWhiteBalanceMode(mode); + else + m_session->setError(KErrNotSupported, tr("Requested white balance mode is not supported.")); +} + +bool S60CameraImageProcessingControl::isWhiteBalanceModeSupported( + QCameraImageProcessing::WhiteBalanceMode mode) const +{ + return m_session->isWhiteBalanceModeSupported(mode); +} + +int S60CameraImageProcessingControl::manualWhiteBalance() const +{ + return 0; +} + +void S60CameraImageProcessingControl::setManualWhiteBalance(int colorTemperature) +{ + m_session->setError(KErrNotSupported, tr("Setting manual white balance is not supported.")); + Q_UNUSED(colorTemperature) +} + +bool S60CameraImageProcessingControl::isProcessingParameterSupported(ProcessingParameter parameter) const +{ + // First check settings requiring Adv. Settings + if (m_advancedSettings) { + switch (parameter) { + case QCameraImageProcessingControl::Saturation: + return true; + case QCameraImageProcessingControl::Sharpening: + return isSharpeningSupported(); + case QCameraImageProcessingControl::Denoising: + return isDenoisingSupported(); + case QCameraImageProcessingControl::ColorTemperature: + return false; + } + } + + // Then the rest + switch (parameter) { + case QCameraImageProcessingControl::Contrast: + case QCameraImageProcessingControl::Brightness: + return true; + + default: + return false; + } +} + +QVariant S60CameraImageProcessingControl::processingParameter( + QCameraImageProcessingControl::ProcessingParameter parameter) const +{ + switch (parameter) { + case QCameraImageProcessingControl::Contrast: + return QVariant(contrast()); + case QCameraImageProcessingControl::Saturation: + return QVariant(saturation()); + case QCameraImageProcessingControl::Brightness: + return QVariant(brightness()); + case QCameraImageProcessingControl::Sharpening: + return QVariant(sharpeningLevel()); + case QCameraImageProcessingControl::Denoising: + return QVariant(denoisingLevel()); + case QCameraImageProcessingControl::ColorTemperature: + return QVariant(manualWhiteBalance()); + + default: + return QVariant(); + } +} + +void S60CameraImageProcessingControl::setProcessingParameter( + QCameraImageProcessingControl::ProcessingParameter parameter, QVariant value) +{ + switch (parameter) { + case QCameraImageProcessingControl::Contrast: + setContrast(value.toInt()); + break; + case QCameraImageProcessingControl::Saturation: + setSaturation(value.toInt()); + break; + case QCameraImageProcessingControl::Brightness: + setBrightness(value.toInt()); + break; + case QCameraImageProcessingControl::Sharpening: + if (isSharpeningSupported()) + setSharpeningLevel(value.toInt()); + break; + case QCameraImageProcessingControl::Denoising: + if (isDenoisingSupported()) + setDenoisingLevel(value.toInt()); + break; + case QCameraImageProcessingControl::ColorTemperature: + setManualWhiteBalance(value.toInt()); + break; + + default: + break; + } +} + +void S60CameraImageProcessingControl::setContrast(int value) +{ + m_session->setContrast(value); +} + +int S60CameraImageProcessingControl::contrast() const +{ + return m_session->contrast(); +} + +void S60CameraImageProcessingControl::setBrightness(int value) +{ + m_session->setBrightness(value); +} + +int S60CameraImageProcessingControl::brightness() const +{ + return m_session->brightness(); +} + +void S60CameraImageProcessingControl::setSaturation(int value) +{ + if (m_advancedSettings) + m_advancedSettings->setSaturation(value); + else + m_session->setError(KErrNotSupported, tr("Setting saturation is not supported.")); +} + +int S60CameraImageProcessingControl::saturation() const +{ + if (m_advancedSettings) + return m_advancedSettings->saturation(); + return 0; +} + +void S60CameraImageProcessingControl::setDenoisingLevel(int value) +{ + m_session->setError(KErrNotSupported, tr("Setting denoising level is not supported.")); + Q_UNUSED(value); // Not supported for Symbian +} + +bool S60CameraImageProcessingControl::isDenoisingSupported() const +{ + return false; // Not supported for Symbian +} + +int S60CameraImageProcessingControl::denoisingLevel() const +{ + return 0; // Not supported for Symbian +} + +void S60CameraImageProcessingControl::setSharpeningLevel(int value) +{ + if (m_advancedSettings) + m_advancedSettings->setSharpeningLevel(value); + else + m_session->setError(KErrNotSupported, tr("Setting sharpening level is not supported.")); +} + +bool S60CameraImageProcessingControl::isSharpeningSupported() const +{ + if (m_advancedSettings) + return m_advancedSettings->isSharpeningSupported(); + return false; +} + +int S60CameraImageProcessingControl::sharpeningLevel() const +{ + if (m_advancedSettings) + return m_advancedSettings->sharpeningLevel(); + return 0; +} + +// End of file diff --git a/src/plugins/symbian/ecam/s60cameraimageprocessingcontrol.h b/src/plugins/symbian/ecam/s60cameraimageprocessingcontrol.h new file mode 100644 index 000000000..7fc6b8900 --- /dev/null +++ b/src/plugins/symbian/ecam/s60cameraimageprocessingcontrol.h @@ -0,0 +1,118 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef S60CAMERAIMAGEPROCESSINGCONTROL_H +#define S60CAMERAIMAGEPROCESSINGCONTROL_H + +#include <qcameraimageprocessing.h> +#include <qcameraimageprocessingcontrol.h> + +#include "s60camerasettings.h" + +QT_USE_NAMESPACE + +class S60CameraService; +class S60ImageCaptureSession; + +/* + * Control for image processing related camera operations (inc. white balance). + */ +class S60CameraImageProcessingControl : public QCameraImageProcessingControl +{ + Q_OBJECT + +public: // Constructors & Destructor + + S60CameraImageProcessingControl(QObject *parent = 0); + S60CameraImageProcessingControl(S60ImageCaptureSession *session, QObject *parent = 0); + ~S60CameraImageProcessingControl(); + +public: // QCameraImageProcessingControl + + // White Balance + QCameraImageProcessing::WhiteBalanceMode whiteBalanceMode() const; + void setWhiteBalanceMode(QCameraImageProcessing::WhiteBalanceMode mode); + bool isWhiteBalanceModeSupported(QCameraImageProcessing::WhiteBalanceMode mode) const; + + // Processing Parameter + bool isProcessingParameterSupported(ProcessingParameter parameter) const; + QVariant processingParameter(QCameraImageProcessingControl::ProcessingParameter parameter) const; + void setProcessingParameter(QCameraImageProcessingControl::ProcessingParameter parameter, QVariant value); + +private slots: // Internal Slots + + void resetAdvancedSetting(); + +private: // Internal operations - Implementing ProcessingParameter + + // Manual White Balance (Color Temperature) + int manualWhiteBalance() const; + void setManualWhiteBalance(int colorTemperature); + + // Contrast + int contrast() const; + void setContrast(int value); + + // Brightness + int brightness() const; + void setBrightness(int value); + + // Saturation + int saturation() const; + void setSaturation(int value); + + // Sharpening + bool isSharpeningSupported() const; + int sharpeningLevel() const; + void setSharpeningLevel(int value); + + // Denoising + bool isDenoisingSupported() const; + int denoisingLevel() const; + void setDenoisingLevel(int value); + +private: // Data + + S60ImageCaptureSession *m_session; + S60CameraSettings *m_advancedSettings; +}; + +#endif // S60CAMERAIMAGEPROCESSINGCONTROL_H diff --git a/src/plugins/symbian/ecam/s60cameralockscontrol.cpp b/src/plugins/symbian/ecam/s60cameralockscontrol.cpp new file mode 100644 index 000000000..cce030f22 --- /dev/null +++ b/src/plugins/symbian/ecam/s60cameralockscontrol.cpp @@ -0,0 +1,263 @@ +/**************************************************************************** +** +** 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 <qcamerafocus.h> // FocusMode + +#include "s60cameralockscontrol.h" +#include "s60cameraservice.h" +#include "s60imagecapturesession.h" +#include "s60camerasettings.h" +#include "s60camerafocuscontrol.h" + +S60CameraLocksControl::S60CameraLocksControl(QObject *parent) : + QCameraLocksControl(parent) +{ +} + +S60CameraLocksControl::S60CameraLocksControl(S60CameraService *service, + S60ImageCaptureSession *session, + QObject *parent) : + QCameraLocksControl(parent), + m_session(0), + m_service(0), + m_advancedSettings(0), + m_focusControl(0), + m_focusStatus(QCamera::Unlocked), + m_exposureStatus(QCamera::Unlocked), + m_whiteBalanceStatus(QCamera::Unlocked) +{ + m_session = session; + m_service = service; + m_focusControl = qobject_cast<S60CameraFocusControl *>(m_service->requestControl(QCameraFocusControl_iid)); + + connect(m_session, SIGNAL(advancedSettingChanged()), this, SLOT(resetAdvancedSetting())); + m_advancedSettings = m_session->advancedSettings(); + + // Exposure Lock Signals + if (m_advancedSettings) + connect(m_advancedSettings, SIGNAL(exposureStatusChanged(QCamera::LockStatus, QCamera::LockChangeReason)), + this, SLOT(exposureStatusChanged(QCamera::LockStatus, QCamera::LockChangeReason))); + + // Focus Lock Signal + // * S60 3.2 and later (through Adv. Settings) + if (m_advancedSettings) + connect(m_advancedSettings, SIGNAL(focusStatusChanged(QCamera::LockStatus, QCamera::LockChangeReason)), + this, SLOT(focusStatusChanged(QCamera::LockStatus, QCamera::LockChangeReason))); + // * S60 3.1 (through ImageSession) + connect(m_session, SIGNAL(focusStatusChanged(QCamera::LockStatus, QCamera::LockChangeReason)), + this, SLOT(focusStatusChanged(QCamera::LockStatus, QCamera::LockChangeReason))); +} + +S60CameraLocksControl::~S60CameraLocksControl() +{ + m_advancedSettings = 0; +} + +QCamera::LockTypes S60CameraLocksControl::supportedLocks() const +{ + QCamera::LockTypes supportedLocks = 0; + +#ifdef S60_CAM_AUTOFOCUS_SUPPORT // S60 3.1 + if (m_session) + if (m_session->isFocusSupported()) + supportedLocks |= QCamera::LockFocus; +#else // S60 3.2 and later + if (m_advancedSettings) { + QCameraFocus::FocusModes supportedFocusModes = m_advancedSettings->supportedFocusModes(); + if (supportedFocusModes & QCameraFocus::AutoFocus) + supportedLocks |= QCamera::LockFocus; + + // Exposure/WhiteBalance Locking not implemented in Symbian + // supportedLocks |= QCamera::LockExposure; + // supportedLocks |= QCamera::LockWhiteBalance; + } +#endif // S60_CAM_AUTOFOCUS_SUPPORT + + return supportedLocks; +} + +QCamera::LockStatus S60CameraLocksControl::lockStatus(QCamera::LockType lock) const +{ + switch (lock) { + case QCamera::LockExposure: + return m_exposureStatus; + case QCamera::LockWhiteBalance: + return m_whiteBalanceStatus; + case QCamera::LockFocus: + return m_focusStatus; + + default: + // Unsupported lock + return QCamera::Unlocked; + } +} + +void S60CameraLocksControl::searchAndLock(QCamera::LockTypes locks) +{ + if (locks & QCamera::LockExposure) { + // Not implemented in Symbian + //startExposureLocking(); + } + if (locks & QCamera::LockWhiteBalance) { + // Not implemented in Symbian + } + if (locks & QCamera::LockFocus) + startFocusing(); +} + +void S60CameraLocksControl::unlock(QCamera::LockTypes locks) +{ + if (locks & QCamera::LockExposure) { + // Not implemented in Symbian + //cancelExposureLocking(); + } + + if (locks & QCamera::LockFocus) + cancelFocusing(); +} + +void S60CameraLocksControl::resetAdvancedSetting() +{ + m_advancedSettings = m_session->advancedSettings(); + + // Reconnect Lock Signals + if (m_advancedSettings) { + connect(m_advancedSettings, SIGNAL(exposureStatusChanged(QCamera::LockStatus, QCamera::LockChangeReason)), + this, SLOT(exposureStatusChanged(QCamera::LockStatus, QCamera::LockChangeReason))); + connect(m_advancedSettings, SIGNAL(focusStatusChanged(QCamera::LockStatus, QCamera::LockChangeReason)), + this, SLOT(focusStatusChanged(QCamera::LockStatus, QCamera::LockChangeReason))); + } +} + +void S60CameraLocksControl::exposureStatusChanged(QCamera::LockStatus status, + QCamera::LockChangeReason reason) +{ + if(status != m_exposureStatus) { + m_exposureStatus = status; + emit lockStatusChanged(QCamera::LockExposure, status, reason); + } +} + +void S60CameraLocksControl::focusStatusChanged(QCamera::LockStatus status, + QCamera::LockChangeReason reason) +{ + if(status != m_focusStatus) { + m_focusStatus = status; + emit lockStatusChanged(QCamera::LockFocus, status, reason); + } +} + +void S60CameraLocksControl::startFocusing() +{ +#ifndef S60_CAM_AUTOFOCUS_SUPPORT // S60 3.2 or later + // Focusing is triggered on Symbian by setting the FocusType corresponding + // to the FocusMode set to FocusControl + if (m_focusControl) { + if (m_advancedSettings) { + m_advancedSettings->startFocusing(); + m_focusStatus = QCamera::Searching; + emit lockStatusChanged(QCamera::LockFocus, QCamera::Searching, QCamera::UserRequest); + } + else + emit lockStatusChanged(QCamera::LockFocus, QCamera::Unlocked, QCamera::LockFailed); + } + else + emit lockStatusChanged(QCamera::LockFocus, QCamera::Unlocked, QCamera::LockFailed); + +#else // S60 3.1 + if (m_focusControl && m_focusControl->focusMode() == QCameraFocus::AutoFocus) { + m_session->startFocus(); + m_focusStatus = QCamera::Searching; + emit lockStatusChanged(QCamera::LockFocus, QCamera::Searching, QCamera::UserRequest); + } + else + emit lockStatusChanged(QCamera::LockFocus, QCamera::Unlocked, QCamera::LockFailed); +#endif // S60_CAM_AUTOFOCUS_SUPPORT +} + +void S60CameraLocksControl::cancelFocusing() +{ + if (m_focusStatus == QCamera::Unlocked) + return; + +#ifndef S60_CAM_AUTOFOCUS_SUPPORT // S60 3.2 or later + if (m_advancedSettings) { + m_advancedSettings->cancelFocusing(); + m_focusStatus = QCamera::Unlocked; + emit lockStatusChanged(QCamera::LockFocus, QCamera::Unlocked, QCamera::UserRequest); + } + else + emit lockStatusChanged(QCamera::LockFocus, QCamera::Unlocked, QCamera::LockFailed); + +#else // S60 3.1 + m_session->cancelFocus(); + m_focusStatus = QCamera::Unlocked; + emit lockStatusChanged(QCamera::LockFocus, QCamera::Unlocked, QCamera::UserRequest); +#endif // S60_CAM_AUTOFOCUS_SUPPORT +} + +void S60CameraLocksControl::startExposureLocking() +{ + if (m_advancedSettings) { + m_advancedSettings->lockExposure(true); + m_exposureStatus = QCamera::Searching; + emit lockStatusChanged(QCamera::LockExposure, QCamera::Searching, QCamera::UserRequest); + } + else + emit lockStatusChanged(QCamera::LockExposure, QCamera::Unlocked, QCamera::LockFailed); +} + +void S60CameraLocksControl::cancelExposureLocking() +{ + if (m_exposureStatus == QCamera::Unlocked) + return; + + if (m_advancedSettings) { + m_advancedSettings->lockExposure(false); + m_exposureStatus = QCamera::Unlocked; + emit lockStatusChanged(QCamera::LockExposure, QCamera::Unlocked, QCamera::UserRequest); + } + else + emit lockStatusChanged(QCamera::LockExposure, QCamera::Unlocked, QCamera::LockFailed); +} + +// End of file diff --git a/src/plugins/symbian/ecam/s60cameralockscontrol.h b/src/plugins/symbian/ecam/s60cameralockscontrol.h new file mode 100644 index 000000000..3b49cbaba --- /dev/null +++ b/src/plugins/symbian/ecam/s60cameralockscontrol.h @@ -0,0 +1,115 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef S60CAMERALOCKSCONTROL_H +#define S60CAMERALOCKSCONTROL_H + +#include <QtCore/qobject.h> +#include "qcameralockscontrol.h" + +QT_USE_NAMESPACE + +class S60CameraService; +class S60ImageCaptureSession; +class S60CameraSettings; +class S60CameraFocusControl; + +/* + * Control for searching and locking 3A algorithms (AutoFocus, AutoExposure + * and AutoWhitebalance). + */ +class S60CameraLocksControl : public QCameraLocksControl +{ + Q_OBJECT + +public: // Contructors & Destrcutor + + S60CameraLocksControl(QObject *parent = 0); + S60CameraLocksControl(S60CameraService *service, + S60ImageCaptureSession *session, + QObject *parent = 0); + ~S60CameraLocksControl(); + +public: // QCameraLocksControl + + QCamera::LockTypes supportedLocks() const; + + QCamera::LockStatus lockStatus(QCamera::LockType lock) const; + + void searchAndLock(QCamera::LockTypes locks); + void unlock(QCamera::LockTypes locks); + +/* +Q_SIGNALS: // QCameraLocksControl + + void lockStatusChanged(QCamera::LockType type, + QCamera::LockStatus status, + QCamera::LockChangeReason reason); +*/ + +private slots: // Internal Slots + + void exposureStatusChanged(QCamera::LockStatus status, QCamera::LockChangeReason reason); + void focusStatusChanged(QCamera::LockStatus status, QCamera::LockChangeReason reason); + void resetAdvancedSetting(); + +private: // Internal + + // Focus + void startFocusing(); + void cancelFocusing(); + + // Exposure + void startExposureLocking(); + void cancelExposureLocking(); + +private: // Data + + S60ImageCaptureSession *m_session; + S60CameraService *m_service; + S60CameraSettings *m_advancedSettings; + S60CameraFocusControl *m_focusControl; + QCamera::LockStatus m_focusStatus; + QCamera::LockStatus m_exposureStatus; + QCamera::LockStatus m_whiteBalanceStatus; +}; + +#endif // S60CAMERALOCKSCONTROL_H diff --git a/src/plugins/symbian/ecam/s60cameraservice.cpp b/src/plugins/symbian/ecam/s60cameraservice.cpp new file mode 100644 index 000000000..5cc4485c1 --- /dev/null +++ b/src/plugins/symbian/ecam/s60cameraservice.cpp @@ -0,0 +1,259 @@ +/**************************************************************************** +** +** 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/qvariant.h> +#include <QtGui/qwidget.h> +#include <QtCore/qlist.h> + +#include "s60cameraservice.h" +#include "s60cameracontrol.h" +#include "s60videodevicecontrol.h" +#include "s60camerafocuscontrol.h" +#include "s60cameraexposurecontrol.h" +#include "s60cameraflashcontrol.h" +#include "s60cameraimageprocessingcontrol.h" +#include "s60cameraimagecapturecontrol.h" +#include "s60mediarecordercontrol.h" +#include "s60videocapturesession.h" +#include "s60imagecapturesession.h" +#include "s60videowidgetcontrol.h" +#include "s60mediacontainercontrol.h" +#include "s60videoencodercontrol.h" +#include "s60audioencodercontrol.h" +#include "s60imageencodercontrol.h" +#include "s60cameralockscontrol.h" +#include "s60videorenderercontrol.h" +#include "s60videowindowcontrol.h" + +#include "s60cameraviewfinderengine.h" // ViewfinderOutputType + +S60CameraService::S60CameraService(QObject *parent) : + QMediaService(parent) +{ + // Session classes for video and image capturing + m_imagesession = new S60ImageCaptureSession(this); + m_videosession = new S60VideoCaptureSession(this); + + if (m_imagesession && m_videosession) { + // Different control classes implementing the Camera API + m_control = new S60CameraControl(m_videosession, m_imagesession, this); + m_videoDeviceControl = new S60VideoDeviceControl(m_control, this); + m_focusControl = new S60CameraFocusControl(m_imagesession, this); + m_exposureControl = new S60CameraExposureControl(m_imagesession, this); + m_flashControl = new S60CameraFlashControl(m_imagesession, this); + m_imageProcessingControl = new S60CameraImageProcessingControl(m_imagesession, this); + m_imageCaptureControl = new S60CameraImageCaptureControl(this, m_imagesession, this); + m_media = new S60MediaRecorderControl(this, m_videosession, this); + m_mediaFormat = new S60MediaContainerControl(m_videosession, this); + m_videoEncoder = new S60VideoEncoderControl(m_videosession, this); + m_audioEncoder = new S60AudioEncoderControl(m_videosession, this); + m_viewFinderWidget = new S60VideoWidgetControl(this); + m_imageEncoderControl = new S60ImageEncoderControl(m_imagesession, this); + m_locksControl = new S60CameraLocksControl(this, m_imagesession, this); + m_rendererControl = new S60VideoRendererControl(this); + m_windowControl = new S60VideoWindowControl(this); + } +} + +S60CameraService::~S60CameraService() +{ + // Delete controls + if (m_videoDeviceControl) + delete m_videoDeviceControl; + if (m_focusControl) + delete m_focusControl; + if (m_exposureControl) + delete m_exposureControl; + if (m_flashControl) + delete m_flashControl; + if (m_imageProcessingControl) + delete m_imageProcessingControl; + if (m_imageCaptureControl) + delete m_imageCaptureControl; + if (m_media) + delete m_media; + if (m_mediaFormat) + delete m_mediaFormat; + if (m_videoEncoder) + delete m_videoEncoder; + if (m_audioEncoder) + delete m_audioEncoder; + if (m_imageEncoderControl) + delete m_imageEncoderControl; + if (m_locksControl) + delete m_locksControl; + + // CameraControl destroys: + // * ViewfinderEngine + // * CameraEngine + if (m_control) + delete m_control; + + // Delete viewfinder controls after CameraControl to be sure that + // ViewFinder gets stopped before widget (and window) is destroyed + if (m_viewFinderWidget) + delete m_viewFinderWidget; + if (m_rendererControl) + delete m_rendererControl; + if (m_windowControl) + delete m_windowControl; + + // Delete sessions + if (m_videosession) + delete m_videosession; + if (m_imagesession) + delete m_imagesession; +} + +QMediaControl *S60CameraService::requestControl(const char *name) +{ + if (qstrcmp(name, QMediaRecorderControl_iid) == 0) + return m_media; + + if (qstrcmp(name, QCameraControl_iid) == 0) + return m_control; + + if (qstrcmp(name, QVideoEncoderControl_iid) == 0) + return m_videoEncoder; + + if (qstrcmp(name, QAudioEncoderControl_iid) == 0) + return m_audioEncoder; + + if (qstrcmp(name, QMediaContainerControl_iid) == 0) + return m_mediaFormat; + + if (qstrcmp(name, QCameraExposureControl_iid) == 0) + return m_exposureControl; + + if (qstrcmp(name, QCameraFlashControl_iid) == 0) + return m_flashControl; + + if (qstrcmp(name, QVideoWidgetControl_iid) == 0) { + if (m_viewFinderWidget) { + m_control->setVideoOutput(m_viewFinderWidget, + S60CameraViewfinderEngine::OutputTypeVideoWidget); + return m_viewFinderWidget; + } + else + return 0; + } + + if (qstrcmp(name, QVideoRendererControl_iid) == 0) { + if (m_rendererControl) { + m_control->setVideoOutput(m_rendererControl, + S60CameraViewfinderEngine::OutputTypeRenderer); + return m_rendererControl; + } + else + return 0; + } + + if (qstrcmp(name, QVideoWindowControl_iid) == 0) { + if (m_windowControl) { + m_control->setVideoOutput(m_windowControl, + S60CameraViewfinderEngine::OutputTypeVideoWindow); + return m_windowControl; + } + else + return 0; + } + + + if (qstrcmp(name, QCameraFocusControl_iid) == 0) + return m_focusControl; + + if (qstrcmp(name, QCameraImageProcessingControl_iid) == 0) + return m_imageProcessingControl; + + if (qstrcmp(name, QCameraImageCaptureControl_iid) == 0) + return m_imageCaptureControl; + + if (qstrcmp(name, QVideoDeviceControl_iid) == 0) + return m_videoDeviceControl; + + if (qstrcmp(name, QImageEncoderControl_iid) == 0) + return m_imageEncoderControl; + + if (qstrcmp(name, QCameraLocksControl_iid) == 0) + return m_locksControl; + + return 0; +} + +void S60CameraService::releaseControl(QMediaControl *control) +{ + if (control == 0) + return; + + // Release viewfinder output + if (control == m_viewFinderWidget) { + if (m_viewFinderWidget) + m_control->releaseVideoOutput(S60CameraViewfinderEngine::OutputTypeVideoWidget); + } + + if (control == m_rendererControl) { + if (m_rendererControl) + m_control->releaseVideoOutput(S60CameraViewfinderEngine::OutputTypeRenderer); + } + + if (control == m_windowControl) { + if (m_windowControl) + m_control->releaseVideoOutput(S60CameraViewfinderEngine::OutputTypeVideoWindow); + } +} + +int S60CameraService::deviceCount() +{ + return S60CameraControl::deviceCount(); +} + +QString S60CameraService::deviceDescription(const int index) +{ + return S60CameraControl::description(index); +} + +QString S60CameraService::deviceName(const int index) +{ + return S60CameraControl::name(index); +} + +// End of file + diff --git a/src/plugins/symbian/ecam/s60cameraservice.h b/src/plugins/symbian/ecam/s60cameraservice.h new file mode 100644 index 000000000..a2744c1fa --- /dev/null +++ b/src/plugins/symbian/ecam/s60cameraservice.h @@ -0,0 +1,111 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef S60CAMERASERVICE_H +#define S60CAMERASERVICE_H + +#include <QtCore/qobject.h> +#include <qmediaservice.h> + +QT_USE_NAMESPACE + +class S60MediaContainerControl; +class S60VideoEncoderControl; +class S60AudioEncoderControl; +class S60CameraControl; +class S60VideoDeviceControl; +class S60MediaRecorderControl; +class S60ImageCaptureSession; +class S60VideoCaptureSession; +class S60CameraFocusControl; +class S60CameraExposureControl; +class S60CameraFlashControl; +class S60CameraImageProcessingControl; +class S60CameraImageCaptureControl; +class S60VideoWidgetControl; +class S60ImageEncoderControl; +class S60CameraLocksControl; +class S60VideoRendererControl; +class S60VideoWindowControl; + +class S60CameraService : public QMediaService +{ + Q_OBJECT + +public: // Contructor & Destructor + + S60CameraService(QObject *parent = 0); + ~S60CameraService(); + +public: // QMediaService + + QMediaControl *requestControl(const char *name); + void releaseControl(QMediaControl *control); + +public: // Static Device Info + + static int deviceCount(); + static QString deviceName(const int index); + static QString deviceDescription(const int index); + +private: // Data + + S60ImageCaptureSession *m_imagesession; + S60VideoCaptureSession *m_videosession; + S60MediaContainerControl *m_mediaFormat; + S60VideoEncoderControl *m_videoEncoder; + S60AudioEncoderControl *m_audioEncoder; + S60CameraControl *m_control; + S60VideoDeviceControl *m_videoDeviceControl; + S60CameraFocusControl *m_focusControl; + S60CameraExposureControl *m_exposureControl; + S60CameraFlashControl *m_flashControl; + S60CameraImageProcessingControl *m_imageProcessingControl; + S60CameraImageCaptureControl *m_imageCaptureControl; + S60MediaRecorderControl *m_media; + S60VideoWidgetControl *m_viewFinderWidget; + S60ImageEncoderControl *m_imageEncoderControl; + S60CameraLocksControl *m_locksControl; + S60VideoRendererControl *m_rendererControl; + S60VideoWindowControl *m_windowControl; +}; + +#endif // S60CAMERASERVICE_H diff --git a/src/plugins/symbian/ecam/s60cameraserviceplugin.cpp b/src/plugins/symbian/ecam/s60cameraserviceplugin.cpp new file mode 100644 index 000000000..8f22fd205 --- /dev/null +++ b/src/plugins/symbian/ecam/s60cameraserviceplugin.cpp @@ -0,0 +1,115 @@ +/**************************************************************************** +** +** 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 "s60cameraserviceplugin.h" +#ifdef QMEDIA_SYMBIAN_CAMERA +#include "s60cameraservice.h" +#endif + +QStringList S60CameraServicePlugin::keys() const +{ + QStringList list; +#ifdef QMEDIA_SYMBIAN_CAMERA + list << QLatin1String(Q_MEDIASERVICE_CAMERA); +#endif + return list; +} + +QMediaService* S60CameraServicePlugin::create(QString const& key) +{ +#ifdef QMEDIA_SYMBIAN_CAMERA + if (key == QLatin1String(Q_MEDIASERVICE_CAMERA)) + return new S60CameraService; +#endif + return 0; +} + +void S60CameraServicePlugin::release(QMediaService *service) +{ + delete service; +} + +QList<QByteArray> S60CameraServicePlugin::devices(const QByteArray &service) const +{ +#ifdef QMEDIA_SYMBIAN_CAMERA + if (service == Q_MEDIASERVICE_CAMERA) { + if (m_cameraDevices.isEmpty()) + updateDevices(); + + return m_cameraDevices; + } +#endif + return QList<QByteArray>(); +} + +QString S60CameraServicePlugin::deviceDescription(const QByteArray &service, const QByteArray &device) +{ +#ifdef QMEDIA_SYMBIAN_CAMERA + if (service == Q_MEDIASERVICE_CAMERA) { + if (m_cameraDevices.isEmpty()) + updateDevices(); + + for (int i=0; i<m_cameraDevices.count(); i++) + if (m_cameraDevices[i] == device) + return m_cameraDescriptions[i]; + } +#endif + return QString(); +} + +void S60CameraServicePlugin::updateDevices() const +{ +#ifdef QMEDIA_SYMBIAN_CAMERA + m_cameraDevices.clear(); + m_cameraDescriptions.clear(); + for (int i=0; i < S60CameraService::deviceCount(); i ++) { + m_cameraDevices.append(S60CameraService::deviceName(i).toUtf8()); + m_cameraDescriptions.append(S60CameraService::deviceDescription(i)); + } +#endif +} + +Q_EXPORT_PLUGIN2(qtmultimedia_ecamngine, S60CameraServicePlugin); + +// End of file + diff --git a/src/plugins/symbian/ecam/s60cameraserviceplugin.h b/src/plugins/symbian/ecam/s60cameraserviceplugin.h new file mode 100644 index 000000000..c56b054c6 --- /dev/null +++ b/src/plugins/symbian/ecam/s60cameraserviceplugin.h @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + + +#ifndef S60CAMERASERVICEPLUGIN_H +#define S60CAMERASERVICEPLUGIN_H + +#include <qmediaservice.h> +#include <qmediaserviceproviderplugin.h> + +QT_USE_NAMESPACE + +/* + * Plugin implementation for the Camera Service + */ +class S60CameraServicePlugin : public QMediaServiceProviderPlugin, + public QMediaServiceSupportedDevicesInterface +{ + Q_OBJECT + Q_INTERFACES(QMediaServiceSupportedDevicesInterface) + +public: // QMediaServiceProviderPlugin + + QStringList keys() const; + QMediaService* create(QString const& key); + void release(QMediaService *service); + +public: // QMediaServiceSupportedDevicesInterface + + QList<QByteArray> devices(const QByteArray &service) const; + QString deviceDescription(const QByteArray &service, const QByteArray &device); + +private: // Internal + + void updateDevices() const; + +private: // Data + + mutable QList<QByteArray> m_cameraDevices; + mutable QStringList m_cameraDescriptions; +}; + +#endif // S60CAMERASERVICEPLUGIN_H diff --git a/src/plugins/symbian/ecam/s60camerasettings.cpp b/src/plugins/symbian/ecam/s60camerasettings.cpp new file mode 100644 index 000000000..a5918078f --- /dev/null +++ b/src/plugins/symbian/ecam/s60camerasettings.cpp @@ -0,0 +1,986 @@ +/**************************************************************************** +** +** 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 "s60camerasettings.h" +#include "s60cameraconstants.h" + +// S60 3.2 Platform +#ifdef USE_S60_32_ECAM_ADVANCED_SETTINGS_HEADER +#define POST_31_PLATFORM +#include <ecamadvancedsettings.h> // CCameraAdvancedSettings (inc. TValueInfo) +#endif // S60 3.2 + +// S60 5.0 or later +#ifdef USE_S60_50_ECAM_ADVANCED_SETTINGS_HEADER +#define POST_31_PLATFORM +#include <ecamadvsettings.h> // CCameraAdvancedSettings +#include <ecam/ecamconstants.h> // TValueInfo +#endif // S60 5.0 or later + +S60CameraSettings::S60CameraSettings(QObject *parent, CCameraEngine *engine) : + QObject(parent), +#ifndef S60_31_PLATFORM // Post S60 3.1 Platforms + m_advancedSettings(0), + m_imageProcessingSettings(0), +#endif // S60_31_PLATFORM + m_cameraEngine(engine), + m_continuousFocusing(false) +{ +} + +S60CameraSettings::~S60CameraSettings() +{ +#ifdef POST_31_PLATFORM + if (m_advancedSettings) { + delete m_advancedSettings; + m_advancedSettings = 0; + } + + if (m_imageProcessingSettings) { + delete m_imageProcessingSettings; + m_imageProcessingSettings = 0; + } +#endif // POST_31_PLATFORM +} + +/* + * This is Symbian NewL kind of consructor, but unlike Symbian version this + * constructor will not leave, but instead it will return possible errors in + * the error variable. This is to be able to write the class without deriving + * it form CBase. Also CleanupStack is cleaned here if the ConstructL leaves. + */ +S60CameraSettings* S60CameraSettings::New(int &error, QObject *parent, CCameraEngine *engine) +{ + S60CameraSettings* self = new S60CameraSettings(parent, engine); + if (!self) { + error = KErrNoMemory; + return 0; + } + + TRAPD(err, self->ConstructL()); + if (err) { + // Clean created object + delete self; + self = 0; + error = err; + return 0; + } + + error = KErrNone; + return self; +} + +void S60CameraSettings::ConstructL() +{ +#ifdef POST_31_PLATFORM + if (!m_cameraEngine) + User::Leave(KErrGeneral); + // From now on it is safe to assume engine exists + + // If no AdvancedSettings is available, there's no benefit of S60CameraSettings + // Leave if creation fails + m_advancedSettings = CCamera::CCameraAdvancedSettings::NewL(*m_cameraEngine->Camera()); + CleanupStack::PushL(m_advancedSettings); + + // ImageProcessing module may not be supported, don't Leave + TRAPD(err, m_imageProcessingSettings = CCamera::CCameraImageProcessing::NewL(*m_cameraEngine->Camera())); + if (err == KErrNone && m_imageProcessingSettings) { + CleanupStack::PushL(m_imageProcessingSettings); + } else { + if (err == KErrNotSupported) + m_imageProcessingSettings = 0; + else { + // Leave with error + if (!m_imageProcessingSettings) + User::Leave(KErrNoMemory); + else + User::Leave(err); + } + } + + if (m_advancedSettings) { + RArray<TInt> digitalZoomFactors; + CleanupClosePushL(digitalZoomFactors); + + TValueInfo info = ENotActive; + m_advancedSettings->GetDigitalZoomStepsL(digitalZoomFactors, info); + + for (int i = 0; i < digitalZoomFactors.Count(); ++i) + m_supportedSymbianDigitalZoomFactors << digitalZoomFactors[i]; + + CleanupStack::PopAndDestroy(); // RArray<TInt> digitalZoomFactors + } + + // Pop objects from CleanupStack + if (m_imageProcessingSettings) + CleanupStack::Pop(m_imageProcessingSettings); + CleanupStack::Pop(m_advancedSettings); + +#else // S60 3.1 + // AdvancedSettings are not suppoted on S60 3.1 (There's no use for S60CameraSettings) + User::Leave(KErrNotSupported); +#endif // POST_31_PLATFORM +} + +void S60CameraSettings::setFocusMode(QCameraFocus::FocusMode mode) +{ +#ifdef POST_31_PLATFORM + if (m_advancedSettings) { + switch (mode) { + case QCameraFocus::ManualFocus: // Manual focus mode + m_advancedSettings->SetFocusMode(CCamera::CCameraAdvancedSettings::EFocusModeManual); + m_continuousFocusing = false; + break; + case QCameraFocus::AutoFocus: // Single-shot AutoFocus mode + m_advancedSettings->SetFocusMode(CCamera::CCameraAdvancedSettings::EFocusModeAuto); + m_advancedSettings->SetFocusRange(CCamera::CCameraAdvancedSettings::EFocusRangeAuto); + m_continuousFocusing = false; + break; + case QCameraFocus::HyperfocalFocus: + m_advancedSettings->SetFocusMode(CCamera::CCameraAdvancedSettings::EFocusModeAuto); + m_advancedSettings->SetFocusRange(CCamera::CCameraAdvancedSettings::EFocusRangeHyperfocal); + m_continuousFocusing = false; + break; + case QCameraFocus::InfinityFocus: + m_advancedSettings->SetFocusMode(CCamera::CCameraAdvancedSettings::EFocusModeAuto); + m_advancedSettings->SetFocusRange(CCamera::CCameraAdvancedSettings::EFocusRangeInfinite); + m_continuousFocusing = false; + break; + case QCameraFocus::ContinuousFocus: + m_advancedSettings->SetFocusMode(CCamera::CCameraAdvancedSettings::EFocusModeAuto); + m_advancedSettings->SetFocusRange(CCamera::CCameraAdvancedSettings::EFocusRangeAuto); + m_continuousFocusing = true; + break; + case QCameraFocus::MacroFocus: + m_advancedSettings->SetFocusMode(CCamera::CCameraAdvancedSettings::EFocusModeAuto); + m_advancedSettings->SetFocusRange(CCamera::CCameraAdvancedSettings::EFocusRangeMacro); + m_continuousFocusing = false; + break; + + default: + emit error(QCamera::NotSupportedFeatureError, tr("Requested focus mode is not supported.")); + break; + } + } else { + emit error(QCamera::CameraError, tr("Unexpected camera error.")); + } +#else // S60 3.1 + Q_UNUSED(mode); + emit error(QCamera::NotSupportedFeatureError, tr("Settings focus mode is not supported.")); +#endif // POST_31_PLATFORM +} + +void S60CameraSettings::startFocusing() +{ +#ifdef POST_31_PLATFORM + // Setting AutoFocusType triggers the focusing on Symbian + if (m_advancedSettings) { + if (m_continuousFocusing) + m_advancedSettings->SetAutoFocusType(CCamera::CCameraAdvancedSettings::EAutoFocusTypeContinuous); + else + m_advancedSettings->SetAutoFocusType(CCamera::CCameraAdvancedSettings::EAutoFocusTypeSingle); + } else { + emit error(QCamera::CameraError, tr("Unable to focus.")); + } +#endif // POST_31_PLATFORM +} + +void S60CameraSettings::cancelFocusing() +{ +#ifdef POST_31_PLATFORM + if (m_advancedSettings) + m_advancedSettings->SetAutoFocusType(CCamera::CCameraAdvancedSettings::EAutoFocusTypeOff); + else + emit error(QCamera::CameraError, tr("Unable to cancel focusing.")); +#endif // POST_31_PLATFORM +} + +QCameraFocus::FocusMode S60CameraSettings::focusMode() +{ +#ifdef POST_31_PLATFORM + if (m_advancedSettings) { + // First request needed info + CCamera::CCameraAdvancedSettings::TFocusMode mode = m_advancedSettings->FocusMode(); + CCamera::CCameraAdvancedSettings::TFocusRange range = m_advancedSettings->FocusRange(); + CCamera::CCameraAdvancedSettings::TAutoFocusType autoType = m_advancedSettings->AutoFocusType(); + + switch (mode) { + case CCamera::CCameraAdvancedSettings::EFocusModeManual: + case CCamera::CCameraAdvancedSettings::EFocusModeFixed: + return QCameraFocus::ManualFocus; + + case CCamera::CCameraAdvancedSettings::EFocusModeAuto: + if (autoType == CCamera::CCameraAdvancedSettings::EAutoFocusTypeContinuous) { + return QCameraFocus::ContinuousFocus; + } else { + // Single-shot focusing + switch (range) { + case CCamera::CCameraAdvancedSettings::EFocusRangeMacro: + case CCamera::CCameraAdvancedSettings::EFocusRangeSuperMacro: + return QCameraFocus::MacroFocus; + case CCamera::CCameraAdvancedSettings::EFocusRangeHyperfocal: + return QCameraFocus::HyperfocalFocus; + case CCamera::CCameraAdvancedSettings::EFocusRangeInfinite: + return QCameraFocus::InfinityFocus; + case CCamera::CCameraAdvancedSettings::EFocusRangeAuto: + case CCamera::CCameraAdvancedSettings::EFocusRangeNormal: + return QCameraFocus::AutoFocus; + + default: + return QCameraFocus::AutoFocus; + } + } + default: + return QCameraFocus::AutoFocus; // Return automatic focusing + } + } else { + emit error(QCamera::CameraError, tr("Unexpected camera error.")); + } +#endif // POST_31_PLATFORM + return QCameraFocus::AutoFocus; // Return automatic focusing +} + +QCameraFocus::FocusModes S60CameraSettings::supportedFocusModes() +{ + QCameraFocus::FocusModes modes = 0; + +#ifdef POST_31_PLATFORM + TInt supportedModes = 0; + TInt autoFocusTypes = 0; + TInt supportedRanges = 0; + + if (m_advancedSettings) { + supportedModes = m_advancedSettings->SupportedFocusModes(); + autoFocusTypes = m_advancedSettings->SupportedAutoFocusTypes(); + supportedRanges = m_advancedSettings->SupportedFocusRanges(); + + if (supportedModes == 0 || autoFocusTypes == 0 || supportedRanges == 0) + return modes; + + // EFocusModeAuto is the only supported on Symbian + if (supportedModes & CCamera::CCameraAdvancedSettings::EFocusModeAuto) { + // Check supported types (Single-shot Auto vs. Continuous) + if (autoFocusTypes & CCamera::CCameraAdvancedSettings::EAutoFocusTypeSingle) + modes |= QCameraFocus::AutoFocus; + if (autoFocusTypes & CCamera::CCameraAdvancedSettings::EAutoFocusTypeContinuous) + modes |= QCameraFocus::ContinuousFocus; + + // Check supported ranges (Note! Some are actually fixed focuses + // even though the mode is Auto on Symbian) + if (supportedRanges & CCamera::CCameraAdvancedSettings::EFocusRangeMacro) + modes |= QCameraFocus::MacroFocus; + if (supportedRanges & CCamera::CCameraAdvancedSettings::EFocusRangeHyperfocal) + modes |= QCameraFocus::HyperfocalFocus; + if (supportedRanges & CCamera::CCameraAdvancedSettings::EFocusRangeInfinite) + modes |= QCameraFocus::InfinityFocus; + } + } else { + emit error(QCamera::CameraError, tr("Unexpected camera error.")); + } +#endif // POST_31_PLATFORM + + return modes; +} + +qreal S60CameraSettings::opticalZoomFactorL() const +{ + // Not supported on Symbian + return 1.0; +} + +void S60CameraSettings::setOpticalZoomFactorL(const qreal zoomFactor) +{ + // Not supported on Symbian + Q_UNUSED(zoomFactor); +} + +QList<qreal> S60CameraSettings::supportedDigitalZoomFactors() const +{ + QList<qreal> zoomFactors; + foreach (int factor, m_supportedSymbianDigitalZoomFactors) + zoomFactors << qreal(factor) / KSymbianFineResolutionFactor; + + return zoomFactors; +} + +qreal S60CameraSettings::digitalZoomFactorL() const +{ + qreal factor = 1.0; + +#ifdef POST_31_PLATFORM + int symbianFactor = 0; + if (m_advancedSettings) + symbianFactor = m_advancedSettings->DigitalZoom(); + else + User::Leave(KErrNotSupported); + + if (symbianFactor != 0) + factor = qreal(symbianFactor) / KSymbianFineResolutionFactor; +#endif // POST_31_PLATFORM + + return factor; +} + +void S60CameraSettings::setDigitalZoomFactorL(const qreal zoomFactor) +{ +#ifdef POST_31_PLATFORM + int symbianFactor = zoomFactor * KSymbianFineResolutionFactor; + + // Find closest supported Symbian ZoomFactor if needed + if (!m_supportedSymbianDigitalZoomFactors.contains(symbianFactor)) { + int closestIndex = -1; + int closestDiff = 1000000; // Sensible maximum + for (int i = 0; i < m_supportedSymbianDigitalZoomFactors.count(); ++i) { + int diff = abs(m_supportedSymbianDigitalZoomFactors.at(i) - symbianFactor); + if (diff < closestDiff) { + closestDiff = diff; + closestIndex = i; + } + } + if (closestIndex != -1) + symbianFactor = m_supportedSymbianDigitalZoomFactors.at(closestIndex); + else + User::Leave(KErrGeneral); + } + if (m_advancedSettings) + m_advancedSettings->SetDigitalZoom(symbianFactor); + else + User::Leave(KErrNotSupported); +#else // S60 3.1 Platform + Q_UNUSED(zoomFactor); + emit error(QCamera::NotSupportedFeatureError, tr("Settings digital zoom factor is not supported.")); +#endif // POST_31_PLATFORM +} + +// MCameraObserver2 +void S60CameraSettings::HandleAdvancedEvent(const TECAMEvent& aEvent) +{ +#ifdef POST_31_PLATFORM + + if (aEvent.iErrorCode != KErrNone) { + switch (aEvent.iErrorCode) { + case KErrECamCameraDisabled: + emit error(QCamera::CameraError, tr("Unexpected camera error.")); + return; + case KErrECamSettingDisabled: + emit error(QCamera::CameraError, tr("Unexpected camera error.")); + return; + case KErrECamParameterNotInRange: + emit error(QCamera::NotSupportedFeatureError, tr("Requested value is not in supported range.")); + return; + case KErrECamSettingNotSupported: + emit error(QCamera::NotSupportedFeatureError, tr("Requested setting is not supported.")); + return; + case KErrECamNotOptimalFocus: + if (m_continuousFocusing) + emit focusStatusChanged(QCamera::Searching, QCamera::LockTemporaryLost); + else + emit focusStatusChanged(QCamera::Unlocked, QCamera::LockFailed); + return; + } + + if (aEvent.iEventType == KUidECamEventCameraSettingFocusRange || + aEvent.iEventType == KUidECamEventCameraSettingAutoFocusType2) { + emit focusStatusChanged(QCamera::Unlocked, QCamera::LockFailed); + return; + } else if (aEvent.iEventType == KUidECamEventCameraSettingIsoRate) { + if (aEvent.iErrorCode == KErrNotSupported) + emit error(QCamera::NotSupportedFeatureError, tr("Requested ISO value is not supported.")); + else + emit error(QCamera::CameraError, tr("Setting ISO value failed.")); + return; + } else if (aEvent.iEventType == KUidECamEventCameraSettingAperture) { + if (aEvent.iErrorCode == KErrNotSupported) + emit error(QCamera::NotSupportedFeatureError, tr("Requested aperture value is not supported.")); + else + emit error(QCamera::CameraError, tr("Setting aperture value failed.")); + return; + } else if (aEvent.iEventType == KUidECamEventCameraSettingExposureCompensation) { + if (aEvent.iErrorCode == KErrNotSupported) + emit error(QCamera::NotSupportedFeatureError, tr("Requested exposure compensation is not supported.")); + else + emit error(QCamera::CameraError, tr("Setting exposure compensation failed.")); + return; + } else if (aEvent.iEventType == KUidECamEventCameraSettingOpticalZoom || + aEvent.iEventType == KUidECamEventCameraSettingDigitalZoom) { + if (aEvent.iErrorCode == KErrNotSupported) + return; // Discard + else { + emit error(QCamera::CameraError, tr("Setting zoom factor failed.")); + return; + } + } else if (aEvent.iEventType == KUidECamEventCameraSettingFocusMode) { + if (aEvent.iErrorCode == KErrNotSupported) + if (m_cameraEngine && m_cameraEngine->CurrentCameraIndex() != 0) + emit error(QCamera::NotSupportedFeatureError, tr("Focusing is not supported with this camera.")); + else + emit error(QCamera::NotSupportedFeatureError, tr("Requested focus mode is not supported.")); + else + emit error(QCamera::CameraError, tr("Setting focus mode failed.")); + return; + } else { + emit error(QCamera::CameraError, tr("Unexpected camera error.")); + return; + } + } + + if (aEvent.iEventType == KUidECamEventCameraSettingExposureLock) { + if (m_advancedSettings) { + if (m_advancedSettings->ExposureLockOn()) + emit exposureStatusChanged(QCamera::Locked, QCamera::LockAcquired); + else + emit exposureStatusChanged(QCamera::Unlocked, QCamera::LockLost); + } + else + emit exposureStatusChanged(QCamera::Unlocked, QCamera::LockLost); + } + else if (aEvent.iEventType == KUidECamEventCameraSettingAperture) + emit apertureChanged(); + + else if (aEvent.iEventType == KUidECamEventCameraSettingApertureRange) + emit apertureRangeChanged(); + + else if (aEvent.iEventType == KUidECamEventCameraSettingIsoRateType) + emit isoSensitivityChanged(); + + else if (aEvent.iEventType == KUidECamEventCameraSettingShutterSpeed) + emit shutterSpeedChanged(); + + else if (aEvent.iEventType == KUidECamEventCameraSettingExposureCompensationStep) + emit evChanged(); + + else if (aEvent.iEventType == KUidECamEventFlashReady) + emit flashReady(true); + + else if (aEvent.iEventType == KUidECamEventFlashNotReady) + emit flashReady(false); + + else if (aEvent.iEventType.iUid == KUidECamEventCameraSettingsOptimalFocusUidValue) + emit focusStatusChanged(QCamera::Locked, QCamera::LockAcquired); + +#else // S60 3.1 Platform + Q_UNUSED(aEvent); +#endif // POST_31_PLATFORM +} + +bool S60CameraSettings::isFlashReady() +{ + TBool isReady = false; +#ifdef POST_31_PLATFORM + if (m_advancedSettings) { + int flashErr = m_advancedSettings->IsFlashReady(isReady); + if(flashErr != KErrNone) { + if (flashErr != KErrNotSupported) + emit error(QCamera::CameraError, tr("Unexpected error with flash.")); + return false; + } + } + else + emit error(QCamera::CameraError, tr("Unexpected camera error.")); +#endif + return isReady; +} + +QCameraExposure::MeteringMode S60CameraSettings::meteringMode() +{ +#ifdef POST_31_PLATFORM + if (m_advancedSettings) { + CCamera::CCameraAdvancedSettings::TMeteringMode mode = m_advancedSettings->MeteringMode(); + switch (mode) { + case CCamera::CCameraAdvancedSettings::EMeteringModeCenterWeighted: + return QCameraExposure::MeteringAverage; + case CCamera::CCameraAdvancedSettings::EMeteringModeEvaluative: + return QCameraExposure::MeteringMatrix; + case CCamera::CCameraAdvancedSettings::EMeteringModeSpot: + return QCameraExposure::MeteringSpot; + + default: + return QCameraExposure::MeteringAverage; + } + }else { + emit error(QCamera::CameraError, tr("Unexpected camera error.")); + return QCameraExposure::MeteringAverage; + } +#else // S60 3.1 Platform + return QCameraExposure::MeteringAverage; +#endif // POST_31_PLATFORM +} + +void S60CameraSettings::setMeteringMode(QCameraExposure::MeteringMode mode) +{ +#ifdef POST_31_PLATFORM + if (m_advancedSettings) { + switch(mode) { + case QCameraExposure::MeteringAverage: + m_advancedSettings->SetMeteringMode(CCamera::CCameraAdvancedSettings::EMeteringModeCenterWeighted); + break; + case QCameraExposure::MeteringMatrix: + m_advancedSettings->SetMeteringMode(CCamera::CCameraAdvancedSettings::EMeteringModeEvaluative); + break; + case QCameraExposure::MeteringSpot: + m_advancedSettings->SetMeteringMode(CCamera::CCameraAdvancedSettings::EMeteringModeSpot); + break; + default: + break; + } + } + else + emit error(QCamera::CameraError, tr("Unexpected camera error.")); +#else // S60 3.1 + Q_UNUSED(mode); + emit error(QCamera::NotSupportedFeatureError, tr("Setting metering mode is not supported.")); +#endif // POST_31_PLATFORM +} + +bool S60CameraSettings::isMeteringModeSupported(QCameraExposure::MeteringMode mode) +{ +#ifdef POST_31_PLATFORM + TInt supportedModes = 0; + + if (m_advancedSettings) { + supportedModes = m_advancedSettings->SupportedMeteringModes(); + if (supportedModes == 0) + return false; + + switch (mode) { + case QCameraExposure::MeteringMatrix: + if (supportedModes & CCamera::CCameraAdvancedSettings::EMeteringModeEvaluative) + return true; + else + return false; + case QCameraExposure::MeteringAverage: + if (supportedModes & CCamera::CCameraAdvancedSettings::EMeteringModeCenterWeighted) + return true; + else + return false; + case QCameraExposure::MeteringSpot: + if (supportedModes & CCamera::CCameraAdvancedSettings::EMeteringModeSpot) + return true; + else + return false; + + default: + return false; + } + } + else + emit error(QCamera::CameraError, tr("Unexpected camera error.")); +#else // S60 3.1 + Q_UNUSED(mode); +#endif // POST_31_PLATFORM + + return false; +} + +int S60CameraSettings::isoSensitivity() +{ +#ifdef POST_31_PLATFORM + if (m_advancedSettings) { + CCamera::CCameraAdvancedSettings::TISORateType isoRateType; + TInt param = 0; + TInt isoRate = 0; + TRAPD(err, m_advancedSettings->GetISORateL(isoRateType, param, isoRate)); + if (err) + return 0; + if (isoRate != KErrNotFound) + return isoRate; + } else { + emit error(QCamera::CameraError, tr("Unexpected camera error.")); + } +#endif // POST_31_PLATFORM + return 0; +} + +QList<int> S60CameraSettings::supportedIsoSensitivities() +{ + QList<int> isoSentitivities; +#ifdef POST_31_PLATFORM + if (m_advancedSettings) { + RArray<TInt> supportedIsoRates; + CleanupClosePushL(supportedIsoRates); + + TRAPD(err, m_advancedSettings->GetSupportedIsoRatesL(supportedIsoRates)); + if (err != KErrNone) { + if (err != KErrNotSupported) // Don's emit error if ISO is not supported + emit error(QCamera::CameraError, tr("Failure while querying supported iso sensitivities.")); + } else { + for (int i = 0; i < supportedIsoRates.Count(); ++i) + isoSentitivities << supportedIsoRates[i]; + } + CleanupStack::PopAndDestroy(); // RArray<TInt> supportedIsoRates + } else { + emit error(QCamera::CameraError, tr("Unexpected camera error.")); + } + + return isoSentitivities; +#else // S60 3.1 Platform + return isoSentitivities; +#endif // POST_31_PLATFORM +} + +void S60CameraSettings::setManualIsoSensitivity(int iso) +{ +#ifdef POST_31_PLATFORM + if (m_advancedSettings) { + TRAPD(err, m_advancedSettings->SetISORateL(CCamera::CCameraAdvancedSettings::EISOManual, iso)); + if (err) + emit error(QCamera::CameraError, tr("Setting manual iso sensitivity failed.")); + return; + } else { + emit error(QCamera::CameraError, tr("Unexpected camera error.")); + } +#else // S60 3.1 Platform + Q_UNUSED(iso); + emit error(QCamera::NotSupportedFeatureError, tr("Setting manual iso sensitivity is not supported.")); +#endif // POST_31_PLATFORM +} + +void S60CameraSettings::setAutoIsoSensitivity() +{ +#ifdef POST_31_PLATFORM + if (m_advancedSettings) { + TRAPD(err, m_advancedSettings->SetISORateL(CCamera::CCameraAdvancedSettings::EISOAutoUnPrioritised, 0)); + if (err) + emit error(QCamera::CameraError, tr("Setting auto iso sensitivity failed.")); + return; + } + else + emit error(QCamera::CameraError, tr("Unexpected camera error.")); +#else // S60 3.1 Platform + emit error(QCamera::NotSupportedFeatureError, tr("Setting auto iso sensitivity is not supported.")); +#endif // POST_31_PLATFORM +} + +qreal S60CameraSettings::aperture() +{ +#ifdef POST_31_PLATFORM + if (m_advancedSettings) + return qreal(m_advancedSettings->Aperture()) / KSymbianFineResolutionFactor; + else + emit error(QCamera::CameraError, tr("Unexpected camera error.")); + return 0; +#else // S60 3.1 Platform + return 0; +#endif // POST_31_PLATFORM +} + +QList<qreal> S60CameraSettings::supportedApertures() +{ + QList<qreal> apertures; + +#ifdef POST_31_PLATFORM + if (m_advancedSettings) { + RArray<TInt> supportedApertures; + TValueInfo info = ENotActive; + + TRAPD(err, m_advancedSettings->GetAperturesL(supportedApertures, info)); + if (err != KErrNone) + if (err != KErrNotSupported) + emit error(QCamera::CameraError, tr("Failure while querying supported apertures.")); + else { + for (int i = 0; i < supportedApertures.Count(); i++) { + qreal q = qreal(supportedApertures[i]) / KSymbianFineResolutionFactor; + apertures.append(q); + } + } + supportedApertures.Close(); + } + else + emit error(QCamera::CameraError, tr("Unexpected camera error.")); + return apertures; +#else // S60 3.1 Platform + return apertures; +#endif // POST_31_PLATFORM +} + +void S60CameraSettings::setManualAperture(qreal aperture) +{ +#ifdef POST_31_PLATFORM + if (m_advancedSettings) { + int symbianAperture = (aperture * KSymbianFineResolutionFactor); // KSymbianFineResolutionFactor = 100 + m_advancedSettings->SetAperture(symbianAperture); + } + else + emit error(QCamera::CameraError, tr("Unexpected camera error.")); +#else // S60 3.1 + Q_UNUSED(aperture); + emit error(QCamera::NotSupportedFeatureError, tr("Setting manual aperture is not supported.")); +#endif // POST_31_PLATFORM +} + +void S60CameraSettings::lockExposure(bool lock) +{ +#ifdef POST_31_PLATFORM + if (m_advancedSettings) { + m_advancedSettings->SetExposureLockOn(lock); + return; + } + else + emit error(QCamera::CameraError, tr("Unexpected camera error.")); +#else // S60 3.1 + Q_UNUSED(lock); + emit error(QCamera::NotSupportedFeatureError, tr("Locking exposure is not supported.")); +#endif // POST_31_PLATFORM +} + +bool S60CameraSettings::isExposureLocked() +{ +#ifdef POST_31_PLATFORM + if (m_advancedSettings) + return m_advancedSettings->ExposureLockOn(); + else + emit error(QCamera::CameraError, tr("Unexpected camera error.")); +#endif // POST_31_PLATFORM + return false; +} + +qreal S60CameraSettings::shutterSpeed() +{ +#ifdef POST_31_PLATFORM + if (m_advancedSettings) { + qreal shutterSpeed = qreal(m_advancedSettings->ShutterSpeed()) / 1000000.0; + return shutterSpeed; // In seconds + } else { + emit error(QCamera::CameraError, tr("Unexpected camera error.")); + } + return 0; +#else // S60 3.1 Platform + return 0; +#endif // POST_31_PLATFORM +} + +QList<qreal> S60CameraSettings::supportedShutterSpeeds() +{ + QList<qreal> speeds; + +#ifdef POST_31_PLATFORM + if (m_advancedSettings) { + RArray<TInt> supportedSpeeds; + TValueInfo info = ENotActive; + + TRAPD(err, m_advancedSettings->GetShutterSpeedsL(supportedSpeeds, info)); + if (err != KErrNone) + if (err != KErrNotSupported) + emit error(QCamera::CameraError, tr("Failure while querying supported shutter speeds.")); + else { + for (int i = 0; i < supportedSpeeds.Count(); i++) { + qreal q = qreal(supportedSpeeds[i]) / 1000000.0; + speeds.append(q); // In seconds + } + } + supportedSpeeds.Close(); + } + else + emit error(QCamera::CameraError, tr("Unexpected camera error.")); + return speeds; +#else // S60 3.1 Platform + return speeds; +#endif // POST_31_PLATFORM +} + +void S60CameraSettings::setManualShutterSpeed(qreal speed) +{ +#ifdef POST_31_PLATFORM + if (m_advancedSettings) { + TInt shutterSpeed = speed * 1000000; // From seconds to microseconds + m_advancedSettings->SetShutterSpeed(shutterSpeed); + } else { + emit error(QCamera::CameraError, tr("Unexpected camera error.")); + } +#else // S60 3.1 + emit error(QCamera::NotSupportedFeatureError, tr("Setting manual shutter speed is not supported.")); + Q_UNUSED(speed); +#endif // POST_31_PLATFORM +} + +void S60CameraSettings::setExposureCompensation(qreal ev) +{ +#ifdef POST_31_PLATFORM + if (m_advancedSettings) { + TInt evStep = ev * KSymbianFineResolutionFactor; + m_advancedSettings->SetExposureCompensationStep(evStep); + } else { + emit error(QCamera::CameraError, tr("Unexpected camera error.")); + } +#else // S60 3.1 Platform + Q_UNUSED(ev); + emit error(QCamera::NotSupportedFeatureError, tr("Setting exposure compensation is not supported.")); +#endif // POST_31_PLATFORM +} + +qreal S60CameraSettings::exposureCompensation() +{ +#ifdef POST_31_PLATFORM + if (m_advancedSettings) { + TInt evStepSymbian = 0; + m_advancedSettings->GetExposureCompensationStep(evStepSymbian); + qreal evStep = evStepSymbian; + evStep /= KSymbianFineResolutionFactor; + return evStep; + } else { + emit error(QCamera::CameraError, tr("Unexpected camera error.")); + } + return 0; +#else // S60 3.1 Platform + return 0; +#endif // POST_31_PLATFORM +} + +QList<qreal> S60CameraSettings::supportedExposureCompensationValues() +{ + QList<qreal> valueList; + +#ifdef POST_31_PLATFORM + if (m_advancedSettings) { + RArray<TInt> evSteps; + TValueInfo info; + TRAPD(err, m_advancedSettings->GetExposureCompensationStepsL(evSteps, info)); + if (err) { + if (err != KErrNotSupported) + emit error(QCamera::CameraError, tr("Failure while querying supported exposure compensation values.")); + return valueList; + } + + if (info == ENotActive || evSteps.Count() == 0) { + // EV not supported, return empty list + return valueList; + } + + for (int i = 0; i < evSteps.Count(); ++i) { + qreal appendValue = evSteps[i]; + appendValue /= KSymbianFineResolutionFactor; + valueList.append(appendValue); + } + } + else + emit error(QCamera::CameraError, tr("Unexpected camera error.")); + return valueList; +#else // S60 3.1 Platform + return valueList; +#endif // POST_31_PLATFORM +} + +void S60CameraSettings::setSharpeningLevel(int value) +{ +#ifdef POST_31_PLATFORM + if (m_imageProcessingSettings && isSharpeningSupported()) + m_imageProcessingSettings->SetTransformationValue(KUidECamEventImageProcessingAdjustSharpness, value); + else + emit error(QCamera::NotSupportedFeatureError, tr("Setting sharpening level is not supported.")); +#else // S60 3.1 + Q_UNUSED(value); + emit error(QCamera::NotSupportedFeatureError, tr("Setting sharpening level is not supported.")); +#endif // POST_31_PLATFORM +} + +bool S60CameraSettings::isSharpeningSupported() const +{ +#ifdef POST_31_PLATFORM + if (m_imageProcessingSettings) { + RArray<TUid> suppTransforms; + TRAPD(err, m_imageProcessingSettings->GetSupportedTransformationsL(suppTransforms)); + if (err) + return false; + + if (suppTransforms.Find(KUidECamEventImageProcessingAdjustSharpness)) + return true; + } + return false; +#else // S60 3.1 Platform + return false; +#endif // POST_31_PLATFORM +} + +int S60CameraSettings::sharpeningLevel() const +{ +#ifdef POST_31_PLATFORM + if (m_imageProcessingSettings && isSharpeningSupported()) + return m_imageProcessingSettings->TransformationValue(KUidECamEventImageProcessingAdjustSharpness); + else + return 0; +#else // S60 3.1 Platform + return 0; +#endif // POST_31_PLATFORM +} + +void S60CameraSettings::setSaturation(int value) +{ +#ifdef POST_31_PLATFORM + if (m_imageProcessingSettings) { + RArray<TUid> suppTransforms; + TRAPD(err, m_imageProcessingSettings->GetSupportedTransformationsL(suppTransforms)); + if (err) + if (err != KErrNotSupported) + emit error(QCamera::CameraError, tr("Failure while querying supported transformations.")); + + if (suppTransforms.Find(KUidECamEventtImageProcessingAdjustSaturation)) + m_imageProcessingSettings->SetTransformationValue(KUidECamEventtImageProcessingAdjustSaturation, value == -1 ? 0 : value*2-100); + else + emit error(QCamera::NotSupportedFeatureError, tr("Setting saturation is not supported.")); + } + else + emit error(QCamera::NotSupportedFeatureError, tr("Setting saturation is not supported.")); +#else // S60 3.1 + Q_UNUSED(value); + emit error(QCamera::NotSupportedFeatureError, tr("Setting saturation is not supported.")); +#endif // POST_31_PLATFORM +} + +int S60CameraSettings::saturation() +{ +#ifdef POST_31_PLATFORM + if (m_imageProcessingSettings) { + RArray<TUid> suppTransforms; + TRAPD(err, m_imageProcessingSettings->GetSupportedTransformationsL(suppTransforms)); + if (err) + if (err != KErrNotSupported) + emit error(QCamera::CameraError, tr("Failure while querying supported transformations.")); + + if (suppTransforms.Find(KUidECamEventtImageProcessingAdjustSaturation)) + return m_imageProcessingSettings->TransformationValue(KUidECamEventtImageProcessingAdjustSaturation); + } + return 0; +#else // S60 3.1 Platform + return 0; +#endif // POST_31_PLATFORM +} + +// End of file diff --git a/src/plugins/symbian/ecam/s60camerasettings.h b/src/plugins/symbian/ecam/s60camerasettings.h new file mode 100644 index 000000000..4ecb131b2 --- /dev/null +++ b/src/plugins/symbian/ecam/s60camerasettings.h @@ -0,0 +1,177 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef S60CAMERASETTINGS_H +#define S60CAMERASETTINGS_H + +#include "qcamera.h" + +#include "s60cameraengine.h" +#include "s60cameraengineobserver.h" + +#include <e32base.h> + +QT_USE_NAMESPACE + +/* + * Class handling CCamera AdvancedSettings and ImageProcessing operations. + */ +class S60CameraSettings : public QObject, + public MAdvancedSettingsObserver +{ + Q_OBJECT + +public: // Static Contructor & Destructor + + static S60CameraSettings* New(int &error, QObject *parent = 0, CCameraEngine *engine = 0); + ~S60CameraSettings(); + +public: // Methods + + // Focus + QCameraFocus::FocusMode focusMode(); + void setFocusMode(QCameraFocus::FocusMode mode); + QCameraFocus::FocusModes supportedFocusModes(); + void startFocusing(); + void cancelFocusing(); + + // Zoom + qreal opticalZoomFactorL() const; + void setOpticalZoomFactorL(const qreal zoomFactor); + QList<qreal> supportedDigitalZoomFactors() const; + qreal digitalZoomFactorL() const; + void setDigitalZoomFactorL(const qreal zoomFactor); + + // Flash + bool isFlashReady(); + + // Exposure + void setExposureMode(QCameraExposure::ExposureMode mode); + void lockExposure(bool lock); + bool isExposureLocked(); + + // Metering Mode + QCameraExposure::MeteringMode meteringMode(); + void setMeteringMode(QCameraExposure::MeteringMode mode); + bool isMeteringModeSupported(QCameraExposure::MeteringMode mode); + + // ISO Sensitivity + int isoSensitivity(); + void setManualIsoSensitivity(int iso); + void setAutoIsoSensitivity(); + QList<int> supportedIsoSensitivities(); + + // Aperture + qreal aperture(); + void setManualAperture(qreal aperture); + QList<qreal> supportedApertures(); + + // Shutter Speed + qreal shutterSpeed(); + void setManualShutterSpeed(qreal speed); + QList<qreal> supportedShutterSpeeds(); + + // ExposureCompensation + qreal exposureCompensation(); + void setExposureCompensation(qreal ev); + QList<qreal> supportedExposureCompensationValues(); + + // Sharpening Level + int sharpeningLevel() const; + void setSharpeningLevel(int value); + bool isSharpeningSupported() const; + + // Saturation + int saturation(); + void setSaturation(int value); + +signals: // Notifications + + // For QCameraExposureControl + void flashReady(bool ready); + void apertureChanged(); + void apertureRangeChanged(); + void shutterSpeedChanged(); + void isoSensitivityChanged(); + void evChanged(); + + // For QCameraLocksControl + void exposureStatusChanged(QCamera::LockStatus, QCamera::LockChangeReason); + void focusStatusChanged(QCamera::LockStatus, QCamera::LockChangeReason); + + // Errors + void error(int, const QString&); + +protected: // Protected constructors + + S60CameraSettings(QObject *parent, CCameraEngine *engine); + void ConstructL(); + +protected: // MAdvancedSettingsObserver + + void HandleAdvancedEvent(const TECAMEvent& aEvent); + +private: // Internal + + bool queryAdvancedSettingsInfo(); + +private: // Enums + + enum EcamErrors { + KErrECamCameraDisabled = -12100, // The camera has been disabled, hence calls do not succeed + KErrECamSettingDisabled = -12101, // This parameter or operation is supported, but presently is disabled. + KErrECamParameterNotInRange = -12102, // This value is out of range. + KErrECamSettingNotSupported = -12103, // This parameter or operation is not supported. + KErrECamNotOptimalFocus = -12104 // The optimum focus is lost + }; + +private: // Data + +#ifndef S60_31_PLATFORM // Post S60 3.1 Platforms + CCamera::CCameraAdvancedSettings *m_advancedSettings; + CCamera::CCameraImageProcessing *m_imageProcessingSettings; +#endif // S60_31_PLATFORM + CCameraEngine *m_cameraEngine; + QList<int> m_supportedSymbianDigitalZoomFactors; + bool m_continuousFocusing; +}; + +#endif // S60CAMERASETTINGS_H diff --git a/src/plugins/symbian/ecam/s60cameraviewfinderengine.cpp b/src/plugins/symbian/ecam/s60cameraviewfinderengine.cpp new file mode 100644 index 000000000..55d7cbc67 --- /dev/null +++ b/src/plugins/symbian/ecam/s60cameraviewfinderengine.cpp @@ -0,0 +1,789 @@ +/**************************************************************************** +** +** 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 <QApplication> +#include <QDesktopWidget> +#include <qcamera.h> +#include <qabstractvideosurface.h> +#include <qvideoframe.h> + +#include "s60cameraviewfinderengine.h" +#include "s60cameraengine.h" +#include "s60cameracontrol.h" +#include "s60videowidgetcontrol.h" +#include "s60videowidgetdisplay.h" +#include "s60videorenderercontrol.h" +#include "s60videowindowcontrol.h" +#include "s60videowindowdisplay.h" +#include "s60cameraconstants.h" + +#include <coemain.h> // CCoeEnv +#include <coecntrl.h> // CCoeControl +#include <w32std.h> + +// Helper function +TRect qRect2TRect(const QRect &qr) +{ + return TRect(TPoint(qr.left(), qr.top()), TSize(qr.width(), qr.height())); +} + + +S60CameraViewfinderEngine::S60CameraViewfinderEngine(S60CameraControl *control, + CCameraEngine *engine, + QObject *parent): + QObject(parent), + m_cameraEngine(engine), + m_cameraControl(0), + m_viewfinderOutput(0), + m_viewfinderDisplay(0), + m_viewfinderSurface(0), + m_wsSession(CCoeEnv::Static()->WsSession()), + m_screenDevice(*CCoeEnv::Static()->ScreenDevice()), + m_window(0), + m_desktopWidget(0), + m_vfState(EVFNotConnectedNotStarted), + m_viewfinderSize(KDefaultViewfinderSize), + m_actualViewFinderSize(KDefaultViewfinderSize), + m_viewfinderAspectRatio(0.0), + m_viewfinderType(OutputTypeNotSet), + m_viewfinderNativeType(EBitmapViewFinder), // Default type + m_isViewFinderVisible(true), // True by default (only QVideoWidgetControl supports being hidden) + m_uiLandscape(true), + m_vfErrorsSignalled(0) +{ + m_cameraControl = control; + + // Check whether platform supports DirectScreen ViewFinder + if (m_cameraEngine) { + if (m_cameraEngine->IsDirectViewFinderSupported()) + m_viewfinderNativeType = EDirectScreenViewFinder; + else + m_viewfinderNativeType = EBitmapViewFinder; + + MCameraViewfinderObserver *vfObserver = this; + m_cameraEngine->SetViewfinderObserver(vfObserver); + } + else + m_cameraControl->setError(KErrGeneral, tr("Unexpected camera error.")); + // From now on it is safe to assume engine exists + + // Check the UI orientation + QDesktopWidget* desktopWidget = QApplication::desktop(); + QRect screenRect = desktopWidget->screenGeometry(); + if (screenRect.width() > screenRect.height()) + m_uiLandscape = true; + else + m_uiLandscape = false; + + // Detect UI Rotations + m_desktopWidget = QApplication::desktop(); + if (m_desktopWidget) + connect(m_desktopWidget, SIGNAL(resized(int)), this, SLOT(handleDesktopResize(int))); +} + +S60CameraViewfinderEngine::~S60CameraViewfinderEngine() +{ + // No need to stop viewfinder: + // Engine has stopped it already + // Surface will be stopped by VideoRendererControl + + m_viewfinderOutput = 0; + m_viewfinderSurface = 0; +} + +void S60CameraViewfinderEngine::setNewCameraEngine(CCameraEngine *engine) +{ + m_cameraEngine = engine; + + if (m_cameraEngine) { + // And set observer to the new CameraEngine + MCameraViewfinderObserver *vfObserver = this; + m_cameraEngine->SetViewfinderObserver(vfObserver); + } +} + +void S60CameraViewfinderEngine::handleDesktopResize(int screen) +{ + Q_UNUSED(screen); + // UI Rotation is handled by the QVideoWidgetControl, thus this is needed + // only for the QVideoRendererControl + if (m_viewfinderType == OutputTypeRenderer) { + QSize newResolution(-1,-1); + if (m_viewfinderSurface) + newResolution = m_viewfinderSurface->nativeResolution(); + + if (newResolution.width() == -1 || newResolution.height() == -1) { + QDesktopWidget* desktopWidget = QApplication::desktop(); + QRect screenRect = desktopWidget->screenGeometry(); + newResolution = QSize(screenRect.width(), screenRect.height()); + } + + resetViewfinderSize(newResolution); + } + + // Rotate Camera if UI has rotated + checkAndRotateCamera(); +} + +void S60CameraViewfinderEngine::setVideoWidgetControl(QObject *viewfinderOutput) +{ + // Release old control if it has not already been done + if (m_viewfinderOutput) + releaseControl(m_viewfinderType); + + // Rotate Camera if UI has rotated + checkAndRotateCamera(); + + S60VideoWidgetControl* viewFinderWidgetControl = + qobject_cast<S60VideoWidgetControl*>(viewfinderOutput); + + if (viewFinderWidgetControl) { + // Check whether platform supports DirectScreen ViewFinder + if (m_cameraEngine) { + if (m_cameraEngine->IsDirectViewFinderSupported()) + m_viewfinderNativeType = EDirectScreenViewFinder; + else + m_viewfinderNativeType = EBitmapViewFinder; + } + else + return; + + m_viewfinderDisplay = viewFinderWidgetControl->display(); + + if (m_viewfinderNativeType == EDirectScreenViewFinder) { + m_viewfinderDisplay->setPaintingEnabled(false); // No Qt Painter painting - Direct rendering + connect(m_viewfinderDisplay, SIGNAL(windowHandleChanged(RWindow *)), this, SLOT(resetViewfinderDisplay())); + } else { + m_viewfinderDisplay->setPaintingEnabled(true); // Qt Painter painting - Bitmap rendering + connect(this, SIGNAL(viewFinderFrameReady(const CFbsBitmap &)), m_viewfinderDisplay, SLOT(setFrame(const CFbsBitmap &))); + } + + connect(m_viewfinderDisplay, SIGNAL(visibilityChanged(bool)), this, SLOT(handleVisibilityChange(bool))); + connect(m_viewfinderDisplay, SIGNAL(displayRectChanged(QRect, QRect)), this, SLOT(resetVideoWindowSize())); + connect(m_viewfinderDisplay, SIGNAL(windowHandleChanged(RWindow*)), this, SLOT(handleWindowChange(RWindow*))); + + m_viewfinderSize = m_viewfinderDisplay->extentRect().size(); + m_viewfinderOutput = viewfinderOutput; + m_viewfinderType = OutputTypeVideoWidget; + m_isViewFinderVisible = m_viewfinderDisplay->isVisible(); + + switch (m_vfState) { + case EVFNotConnectedNotStarted: + m_vfState = EVFIsConnectedNotStarted; + break; + case EVFNotConnectedIsStarted: + if (m_isViewFinderVisible) + m_vfState = EVFIsConnectedIsStartedIsVisible; + else + m_vfState = EVFIsConnectedIsStartedNotVisible; + break; + case EVFIsConnectedNotStarted: + case EVFIsConnectedIsStartedNotVisible: + case EVFIsConnectedIsStartedIsVisible: + // Already connected, state does not change + break; + default: + emit error(QCamera::CameraError, tr("General viewfinder error.")); + break; + } + + if (m_vfState == EVFIsConnectedIsStartedIsVisible) + startViewfinder(true); // Internal start (i.e. start if started externally) + } +} + +void S60CameraViewfinderEngine::setVideoRendererControl(QObject *viewfinderOutput) +{ + // Release old control if it has not already been done + if (m_viewfinderOutput) + releaseControl(m_viewfinderType); + + // Rotate Camera if UI has rotated + checkAndRotateCamera(); + + S60VideoRendererControl* viewFinderRenderControl = + qobject_cast<S60VideoRendererControl*>(viewfinderOutput); + + if (viewFinderRenderControl) { + m_viewfinderNativeType = EBitmapViewFinder; // Always Bitmap + + connect(viewFinderRenderControl, SIGNAL(viewFinderSurfaceSet()), + this, SLOT(rendererSurfaceSet())); + + Q_ASSERT(!viewFinderRenderControl->surface()); + m_viewfinderOutput = viewfinderOutput; + m_viewfinderType = OutputTypeRenderer; + // RendererControl viewfinder is "visible" when surface is set + m_isViewFinderVisible = false; + if (EVFIsConnectedIsStartedIsVisible) + m_vfState = EVFIsConnectedIsStartedNotVisible; + + // Use display resolution as default viewfinder resolution + m_viewfinderSize = QApplication::desktop()->screenGeometry().size(); + + switch (m_vfState) { + case EVFNotConnectedNotStarted: + m_vfState = EVFIsConnectedNotStarted; + break; + case EVFNotConnectedIsStarted: + m_vfState = EVFIsConnectedIsStartedIsVisible; // GraphicsItem "always visible" (FrameWork decides to draw/not draw) + break; + case EVFIsConnectedNotStarted: + case EVFIsConnectedIsStartedNotVisible: + case EVFIsConnectedIsStartedIsVisible: + // Already connected, state does not change + break; + default: + emit error(QCamera::CameraError, tr("General viewfinder error.")); + break; + } + + if (m_vfState == EVFIsConnectedIsStartedIsVisible) + startViewfinder(true); + } +} + +void S60CameraViewfinderEngine::setVideoWindowControl(QObject *viewfinderOutput) +{ + // Release old control if it has not already been done + if (m_viewfinderOutput) + releaseControl(m_viewfinderType); + + // Rotate Camera if UI has rotated + checkAndRotateCamera(); + + S60VideoWindowControl* viewFinderWindowControl = + qobject_cast<S60VideoWindowControl*>(viewfinderOutput); + + if (viewFinderWindowControl) { + // Check whether platform supports DirectScreen ViewFinder + if (m_cameraEngine) { + if (m_cameraEngine->IsDirectViewFinderSupported()) + m_viewfinderNativeType = EDirectScreenViewFinder; + else + m_viewfinderNativeType = EBitmapViewFinder; + } else { + return; + } + + m_viewfinderDisplay = viewFinderWindowControl->display(); + + if (m_viewfinderNativeType == EDirectScreenViewFinder) { + m_viewfinderDisplay->setPaintingEnabled(false); // No Qt Painter painting - Direct rendering + connect(m_viewfinderDisplay, SIGNAL(windowHandleChanged(RWindow *)), this, SLOT(resetViewfinderDisplay())); + } else { + m_viewfinderDisplay->setPaintingEnabled(true); // Qt Painter painting - Bitmap rendering + connect(this, SIGNAL(viewFinderFrameReady(const CFbsBitmap &)), m_viewfinderDisplay, SLOT(setFrame(const CFbsBitmap &))); + } + + connect(m_viewfinderDisplay, SIGNAL(displayRectChanged(QRect, QRect)), this, SLOT(resetVideoWindowSize())); + connect(m_viewfinderDisplay, SIGNAL(visibilityChanged(bool)), this, SLOT(handleVisibilityChange(bool))); + connect(m_viewfinderDisplay, SIGNAL(windowHandleChanged(RWindow*)), this, SLOT(handleWindowChange(RWindow*))); + + m_viewfinderSize = m_viewfinderDisplay->extentRect().size(); + m_viewfinderOutput = viewfinderOutput; + m_viewfinderType = OutputTypeVideoWindow; + m_isViewFinderVisible = m_viewfinderDisplay->isVisible(); + + switch (m_vfState) { + case EVFNotConnectedNotStarted: + m_vfState = EVFIsConnectedNotStarted; + break; + case EVFNotConnectedIsStarted: + if (m_isViewFinderVisible) + m_vfState = EVFIsConnectedIsStartedIsVisible; + else + m_vfState = EVFIsConnectedIsStartedNotVisible; + break; + case EVFIsConnectedNotStarted: + case EVFIsConnectedIsStartedNotVisible: + case EVFIsConnectedIsStartedIsVisible: + // Already connected, state does not change + break; + default: + emit error(QCamera::CameraError, tr("General viewfinder error.")); + break; + } + + if (m_vfState == EVFIsConnectedIsStartedIsVisible) + startViewfinder(true); // Internal start (i.e. start if started externally) + } +} + +void S60CameraViewfinderEngine::releaseControl(ViewfinderOutputType type) +{ + if (m_vfState == EVFIsConnectedIsStartedIsVisible) + stopViewfinder(true); + + if (m_viewfinderOutput) { + switch (type) { + case OutputTypeNotSet: + return; + case OutputTypeVideoWidget: + if (m_viewfinderType != OutputTypeVideoWidget) + return; + disconnect(m_viewfinderOutput); + m_viewfinderOutput->disconnect(this); + Q_ASSERT(m_viewfinderDisplay); + disconnect(m_viewfinderDisplay); + m_viewfinderDisplay->disconnect(this); + m_viewfinderDisplay = 0; + // Invalidate the extent rect + qobject_cast<S60VideoWidgetControl*>(m_viewfinderOutput)->setExtentRect(QRect()); + break; + case OutputTypeVideoWindow: + if (m_viewfinderType != OutputTypeVideoWindow) + return; + disconnect(m_viewfinderOutput); + m_viewfinderOutput->disconnect(this); + Q_ASSERT(m_viewfinderDisplay); + disconnect(m_viewfinderDisplay); + m_viewfinderDisplay->disconnect(this); + m_viewfinderDisplay = 0; + break; + case OutputTypeRenderer: + if (m_viewfinderType != OutputTypeRenderer) + return; + disconnect(m_viewfinderOutput); + m_viewfinderOutput->disconnect(this); + if (m_viewfinderSurface) + m_viewfinderSurface->disconnect(this); + disconnect(this, SIGNAL(viewFinderFrameReady(const CFbsBitmap &)), + this, SLOT(viewFinderBitmapReady(const CFbsBitmap &))); + break; + default: + emit error(QCamera::CameraError, tr("Unexpected viewfinder error.")); + return; + } + } + + Q_ASSERT(!m_viewfinderDisplay); + m_viewfinderOutput = 0; + m_viewfinderType = OutputTypeNotSet; + + // Update state + switch (m_vfState) { + case EVFNotConnectedNotStarted: + case EVFNotConnectedIsStarted: + // Do nothing + break; + case EVFIsConnectedNotStarted: + m_vfState = EVFNotConnectedNotStarted; + break; + case EVFIsConnectedIsStartedNotVisible: + case EVFIsConnectedIsStartedIsVisible: + m_vfState = EVFNotConnectedIsStarted; + break; + default: + emit error(QCamera::CameraError, tr("General viewfinder error.")); + break; + } +} + +void S60CameraViewfinderEngine::startViewfinder(const bool internalStart) +{ + if (!internalStart) { + switch (m_vfState) { + case EVFNotConnectedNotStarted: + m_vfState = EVFNotConnectedIsStarted; + break; + case EVFIsConnectedNotStarted: + if (m_isViewFinderVisible) + m_vfState = EVFIsConnectedIsStartedIsVisible; + else + m_vfState = EVFIsConnectedIsStartedNotVisible; + break; + case EVFNotConnectedIsStarted: + case EVFIsConnectedIsStartedNotVisible: + case EVFIsConnectedIsStartedIsVisible: + // Already started, state does not change + break; + default: + emit error(QCamera::CameraError, tr("General viewfinder error.")); + break; + } + } + + // Start viewfinder + if (m_vfState == EVFIsConnectedIsStartedIsVisible) { + + if (!m_cameraEngine) + return; + + if (m_viewfinderNativeType == EDirectScreenViewFinder) { + + if (RWindow *window = m_viewfinderDisplay ? m_viewfinderDisplay->windowHandle() : 0) { + m_window = window; + } else { + emit error(QCamera::CameraError, tr("Requesting window for viewfinder failed.")); + return; + } + + const QRect extentRect = m_viewfinderDisplay ? m_viewfinderDisplay->extentRect() : QRect(); + const QRect clipRect = m_viewfinderDisplay ? m_viewfinderDisplay->clipRect() : QRect(); + + TRect extentRectSymbian = qRect2TRect(extentRect); + TRect clipRectSymbian = qRect2TRect(clipRect); + TRAPD(err, m_cameraEngine->StartDirectViewFinderL(m_wsSession, m_screenDevice, *m_window, extentRectSymbian, clipRectSymbian)); + if (err) { + if (err == KErrNotSupported) { + emit error(QCamera::NotSupportedFeatureError, tr("Requested viewfinder size is not supported.")); + } else { + emit error(QCamera::CameraError, tr("Starting viewfinder failed.")); + } + return; + } + + m_actualViewFinderSize = QSize(extentRectSymbian.Size().iWidth, extentRectSymbian.Size().iHeight); + m_viewfinderAspectRatio = qreal(m_actualViewFinderSize.width()) / qreal(m_actualViewFinderSize.height()); + + } else { // Bitmap ViewFinder + TSize size = TSize(m_viewfinderSize.width(), m_viewfinderSize.height()); + + if( m_viewfinderType == OutputTypeRenderer && m_viewfinderSurface) { + if (!m_surfaceFormat.isValid()) { + emit error(QCamera::NotSupportedFeatureError, tr("Invalid surface format.")); + return; + } + + // Start rendering to surface with correct size and format + if (!m_viewfinderSurface->isFormatSupported(m_surfaceFormat) || + !m_viewfinderSurface->start(m_surfaceFormat)) { + emit error(QCamera::NotSupportedFeatureError, tr("Failed to start surface.")); + return; + } + + if (!m_viewfinderSurface->isActive()) + return; + } + + TRAPD(vfErr, m_cameraEngine->StartViewFinderL(size)); + if (vfErr) { + if (vfErr == KErrNotSupported) { + emit error(QCamera::NotSupportedFeatureError, tr("Requested viewfinder size is not supported.")); + } else { + emit error(QCamera::CameraError, tr("Starting viewfinder failed.")); + } + return; + } + + m_actualViewFinderSize = QSize(size.iWidth, size.iHeight); + m_viewfinderAspectRatio = qreal(m_actualViewFinderSize.width()) / qreal(m_actualViewFinderSize.height()); + + // Notify control about the frame size (triggers frame position calculation) + if (m_viewfinderDisplay) { + m_viewfinderDisplay->setNativeSize(m_actualViewFinderSize); + } else { + if (m_viewfinderType == OutputTypeRenderer && m_viewfinderSurface) { + m_viewfinderSurface->stop(); + QVideoSurfaceFormat format = m_viewfinderSurface->surfaceFormat(); + format.setFrameSize(QSize(m_actualViewFinderSize)); + format.setViewport(QRect(0, 0, m_actualViewFinderSize.width(), m_actualViewFinderSize.height())); + m_viewfinderSurface->start(format); + } + } + } + } +} + +void S60CameraViewfinderEngine::stopViewfinder(const bool internalStop) +{ + // Stop if viewfinder is started + if (m_vfState == EVFIsConnectedIsStartedIsVisible) { + if (m_viewfinderOutput && m_viewfinderType == OutputTypeRenderer && m_viewfinderSurface) { + // Stop surface if one still exists + m_viewfinderSurface->stop(); + } + + if (m_cameraEngine) + m_cameraEngine->StopViewFinder(); + } + + // Update state + if (!internalStop) { + switch (m_vfState) { + case EVFNotConnectedNotStarted: + case EVFIsConnectedNotStarted: + // Discard + break; + case EVFNotConnectedIsStarted: + m_vfState = EVFNotConnectedNotStarted; + break; + case EVFIsConnectedIsStartedNotVisible: + case EVFIsConnectedIsStartedIsVisible: + m_vfState = EVFIsConnectedNotStarted; + break; + default: + emit error(QCamera::CameraError, tr("General viewfinder error.")); + break; + } + } +} + +void S60CameraViewfinderEngine::MceoViewFinderFrameReady(CFbsBitmap& aFrame) +{ + emit viewFinderFrameReady(aFrame); + if (m_cameraEngine) + m_cameraEngine->ReleaseViewFinderBuffer(); +} + +void S60CameraViewfinderEngine::resetViewfinderSize(const QSize size) +{ + m_viewfinderSize = size; + + if(m_vfState != EVFIsConnectedIsStartedIsVisible) { + // Set native size to Window/Renderer Control + if (m_viewfinderDisplay) + m_viewfinderDisplay->setNativeSize(m_actualViewFinderSize); + return; + } + + stopViewfinder(true); + + startViewfinder(true); +} + +void S60CameraViewfinderEngine::resetVideoWindowSize() +{ + if (m_viewfinderDisplay) + resetViewfinderSize(m_viewfinderDisplay->extentRect().size()); +} + +void S60CameraViewfinderEngine::resetViewfinderDisplay() +{ + if (m_viewfinderNativeType == EDirectScreenViewFinder) { + + switch (m_viewfinderType) { + case OutputTypeVideoWidget: { + if (!m_viewfinderOutput) + return; + + // First stop viewfinder + stopViewfinder(true); + + RWindow *window = m_viewfinderDisplay->windowHandle(); + if (!window) { + return; + } + + // Then start it with the new WindowID + startViewfinder(true); + break; + } + case OutputTypeRenderer: + case OutputTypeVideoWindow: + // Do nothing + break; + + default: + // Not ViewFinder Output has been set, Discard + break; + } + } +} + +void S60CameraViewfinderEngine::rendererSurfaceSet() +{ + S60VideoRendererControl* viewFinderRenderControl = + qobject_cast<S60VideoRendererControl*>(m_viewfinderOutput); + + // Reset old surface if needed + if (m_viewfinderSurface) { + handleVisibilityChange(false); + disconnect(m_viewfinderSurface); + if (viewFinderRenderControl->surface()) + stopViewfinder(true); // Temporary stop + else + stopViewfinder(); // Stop for good + m_viewfinderSize = QApplication::desktop()->screenGeometry().size(); + m_viewfinderSurface = 0; + } + + // Set new surface + m_viewfinderSurface = viewFinderRenderControl->surface(); + if (!m_viewfinderSurface) + return; + if (!m_viewfinderSurface->nativeResolution().isEmpty()) { + if (m_viewfinderSurface->nativeResolution() != m_viewfinderSize) + resetViewfinderSize(m_viewfinderSurface->nativeResolution()); + } + + connect(m_viewfinderSurface, SIGNAL(nativeResolutionChanged(const QSize&)), + this, SLOT(resetViewfinderSize(QSize))); + + // Set Surface Properties + if (m_viewfinderSurface->supportedPixelFormats().contains(QVideoFrame::Format_RGB32)) + m_surfaceFormat = QVideoSurfaceFormat(m_actualViewFinderSize, QVideoFrame::Format_RGB32); + else if (m_viewfinderSurface->supportedPixelFormats().contains(QVideoFrame::Format_ARGB32)) + m_surfaceFormat = QVideoSurfaceFormat(m_actualViewFinderSize, QVideoFrame::Format_ARGB32); + else { + return; + } + m_surfaceFormat.setFrameRate(KViewfinderFrameRate); + m_surfaceFormat.setYCbCrColorSpace(QVideoSurfaceFormat::YCbCr_Undefined); // EColor16MU (compatible with EColor16MA) + m_surfaceFormat.setPixelAspectRatio(1,1); // PAR 1:1 + + + connect(this, SIGNAL(viewFinderFrameReady(const CFbsBitmap &)), + this, SLOT(viewFinderBitmapReady(const CFbsBitmap &))); + + // Surface set, viewfinder is "visible" + handleVisibilityChange(true); +} + +void S60CameraViewfinderEngine::viewFinderBitmapReady(const CFbsBitmap &bitmap) +{ + CFbsBitmap *bitmapPtr = const_cast<CFbsBitmap*>(&bitmap); + QPixmap pixmap = QPixmap::fromSymbianCFbsBitmap(bitmapPtr); + + QImage newImage = pixmap.toImage(); + if (newImage.format() != QImage::Format_ARGB32 && + newImage.format() != QImage::Format_RGB32) { + newImage = newImage.convertToFormat(QImage::Format_RGB32); + } + + if (!newImage.isNull()) { + QVideoFrame newFrame(newImage); + if (newFrame.isValid()) { + if (!m_viewfinderSurface->present(newFrame)) { + // Presenting may fail even if there are no errors (e.g. busy) + if (m_viewfinderSurface->error()) { + if (m_vfErrorsSignalled < KMaxVFErrorsSignalled) { + emit error(QCamera::CameraError, tr("Presenting viewfinder frame failed.")); + ++m_vfErrorsSignalled; + } + } + } + } else { + if (m_vfErrorsSignalled < KMaxVFErrorsSignalled) { + emit error(QCamera::CameraError, tr("Invalid viewfinder frame was received.")); + ++m_vfErrorsSignalled; + } + } + + } else { + if (m_vfErrorsSignalled < KMaxVFErrorsSignalled) { + emit error(QCamera::CameraError, tr("Failed to convert viewfinder frame to presentable image.")); + ++m_vfErrorsSignalled; + } + } +} + +void S60CameraViewfinderEngine::handleVisibilityChange(const bool isVisible) +{ + if (m_isViewFinderVisible == isVisible) + return; + + m_isViewFinderVisible = isVisible; + + if (m_isViewFinderVisible) { + switch (m_vfState) { + case EVFNotConnectedNotStarted: + case EVFIsConnectedNotStarted: + case EVFNotConnectedIsStarted: + case EVFIsConnectedIsStartedIsVisible: + // Discard + break; + case EVFIsConnectedIsStartedNotVisible: + m_vfState = EVFIsConnectedIsStartedIsVisible; + break; + default: + emit error(QCamera::CameraError, tr("General viewfinder error.")); + break; + } + startViewfinder(true); + } else { + // Stopping takes care of the state change + stopViewfinder(true); + } +} + +void S60CameraViewfinderEngine::handleWindowChange(RWindow *handle) +{ + stopViewfinder(true); + + if (handle) // New handle available, start viewfinder + startViewfinder(true); +} + +void S60CameraViewfinderEngine::checkAndRotateCamera() +{ + bool isUiNowLandscape = false; + QDesktopWidget* desktopWidget = QApplication::desktop(); + QRect screenRect = desktopWidget->screenGeometry(); + + if (screenRect.width() > screenRect.height()) + isUiNowLandscape = true; + else + isUiNowLandscape = false; + + // Rotate camera if possible + if (isUiNowLandscape != m_uiLandscape) { + stopViewfinder(true); + + // Request orientation reset + m_cameraControl->resetCameraOrientation(); + } + m_uiLandscape = isUiNowLandscape; +} + +void S60CameraViewfinderEngine::handleContentAspectRatioChange(const QSize& newSize) +{ + qreal newAspectRatio = qreal(newSize.width()) / qreal(newSize.height()); + // Check if aspect ratio changed + if (qFuzzyCompare(newAspectRatio, m_viewfinderAspectRatio)) + return; + + // Resize viewfinder by reducing either width or height to comply with the new aspect ratio + QSize newNativeResolution; + if (newAspectRatio > m_viewfinderAspectRatio) { // New AspectRatio is wider => Reduce height + newNativeResolution = QSize(m_actualViewFinderSize.width(), (m_actualViewFinderSize.width() / newAspectRatio)); + } else { // New AspectRatio is higher => Reduce width + newNativeResolution = QSize((m_actualViewFinderSize.height() * newAspectRatio), m_actualViewFinderSize.height()); + } + + // Notify aspect ratio change (use actual content size to notify that) + // This triggers item size/position re-calculation + if (m_viewfinderDisplay) + m_viewfinderDisplay->setNativeSize(newNativeResolution); +} + +// End of file diff --git a/src/plugins/symbian/ecam/s60cameraviewfinderengine.h b/src/plugins/symbian/ecam/s60cameraviewfinderengine.h new file mode 100644 index 000000000..c5df760d9 --- /dev/null +++ b/src/plugins/symbian/ecam/s60cameraviewfinderengine.h @@ -0,0 +1,182 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ +#ifndef S60CAMERAVIEWFINDERENGINE_H +#define S60CAMERAVIEWFINDERENGINE_H + +#include <QtCore/qsize.h> +#include <QtGui/qpixmap.h> + +#include <qvideosurfaceformat.h> + +#include "s60cameraengineobserver.h" + +class CCameraEngine; +class S60CameraControl; +class QAbstractVideoSurface; + +// For DirectScreen ViewFinder +class RWsSession; +class CWsScreenDevice; +class RWindowBase; +class RWindow; +class QDesktopWidget; + +class S60VideoDisplay; + +/* + * Class implementing video output selection for the viewfinder and the handler of + * all common viewfinder operations. + */ +class S60CameraViewfinderEngine : public QObject, public MCameraViewfinderObserver +{ + Q_OBJECT + +public: // Enums + + /* + * Defines whether viewfinder output backend control is of type + * QVideoWidgetControl, QVideoRendererControl or QVideoWindowControl + */ + enum ViewfinderOutputType { + OutputTypeNotSet = 0, // No viewfinder output connected + OutputTypeVideoWidget, // Using QVideoWidget + OutputTypeRenderer, // (Using QGraphicsVideoItem with) QVideoRendererControl + OutputTypeVideoWindow // Using QGraphicsVideoItem with QVideoWindow + }; + +public: // Constructor & Destructor + + S60CameraViewfinderEngine(S60CameraControl *control, + CCameraEngine *engine, + QObject *parent = 0); + ~S60CameraViewfinderEngine(); + +public: // Methods + + // Setting Viewfinder Output + void setVideoWidgetControl(QObject *viewfinderOutput); + void setVideoRendererControl(QObject *viewfinderOutput); + void setVideoWindowControl(QObject *viewfinderOutput); + void releaseControl(ViewfinderOutputType type); + + // Controls + void startViewfinder(const bool internalStart = false); + void stopViewfinder(const bool internalStop = false); + + // Start using new CameraEngine + void setNewCameraEngine(CCameraEngine *engine); + +protected: // MCameraViewfinderObserver + + void MceoViewFinderFrameReady(CFbsBitmap& aFrame); + +private: // Internal operation + + void checkAndRotateCamera(); + +signals: + + void error(int error, const QString &errorString); + void viewFinderFrameReady(const CFbsBitmap &bitmap); + +private slots: + + void resetViewfinderSize(const QSize size); + void resetVideoWindowSize(); + void resetViewfinderDisplay(); + void viewFinderBitmapReady(const CFbsBitmap &bitmap); + void handleVisibilityChange(const bool isVisible); + void handleWindowChange(RWindow *handle); + void handleDesktopResize(int screen); + void handleContentAspectRatioChange(const QSize& newSize); + void rendererSurfaceSet(); + +private: // Enums + + /* + * Defines the internal state of the viewfinder. ViewFinder will only be + * started if output is connected to Camera and Camera is started (and + * ViewFinder widget is visible in case of QVideoWidget). + */ + enum ViewFinderState { + EVFNotConnectedNotStarted = 0, // 0 - No output connected, viewfinder is not started + EVFNotConnectedIsStarted, // 1 - No output connected, viewfinder is started + EVFIsConnectedNotStarted, // 2 - Output is connected, viewfinder is not started + EVFIsConnectedIsStartedNotVisible, // 3 - Output is connected, viewfinder is started but is not visible + EVFIsConnectedIsStartedIsVisible // 4 - Output is connected, viewfinder is started and is visible + }; + + /* + * The native type of ViewFinder. DirectScreen ViewFinder is used with + * QVideoWidget if support for it is available in the platform. For + * QGraphicsVideoItem Bitmap ViewFinder is always used. + */ + enum NativeViewFinderType { + EBitmapViewFinder = 0, + EDirectScreenViewFinder + }; + +private: // Data + + CCameraEngine *m_cameraEngine; + S60CameraControl *m_cameraControl; + QObject *m_viewfinderOutput; + S60VideoDisplay *m_viewfinderDisplay; + QAbstractVideoSurface *m_viewfinderSurface; // Used only by QVideoRendererControl + RWsSession &m_wsSession; + CWsScreenDevice &m_screenDevice; + RWindowBase *m_window; + QDesktopWidget *m_desktopWidget; + ViewFinderState m_vfState; + QSize m_viewfinderSize; + // Actual viewfinder size, which may differ from requested + // (m_viewfinderSize), if the size/aspect ratio was not supported. + QSize m_actualViewFinderSize; + qreal m_viewfinderAspectRatio; + ViewfinderOutputType m_viewfinderType; + NativeViewFinderType m_viewfinderNativeType; + QVideoSurfaceFormat m_surfaceFormat; // Used only by QVideoRendererControl + bool m_isViewFinderVisible; + bool m_uiLandscape; // For detecting UI rotation + int m_vfErrorsSignalled; +}; + +#endif // S60CAMERAVIEWFINDERENGINE_H diff --git a/src/plugins/symbian/ecam/s60imagecapturesession.cpp b/src/plugins/symbian/ecam/s60imagecapturesession.cpp new file mode 100644 index 000000000..16d240c7b --- /dev/null +++ b/src/plugins/symbian/ecam/s60imagecapturesession.cpp @@ -0,0 +1,1884 @@ +/**************************************************************************** +** +** 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 "s60imagecapturesession.h" +#include "s60videowidgetcontrol.h" +#include "s60cameraservice.h" +#include "s60cameraconstants.h" + +#include <fbs.h> // CFbsBitmap +#include <pathinfo.h> +#include <imageconversion.h> // ICL Decoder (for SnapShot) & Encoder (for Bitmap Images) + +S60ImageCaptureDecoder::S60ImageCaptureDecoder(S60ImageCaptureSession *imageSession, + RFs *fileSystemAccess, + const TDesC8 *data, + const TDesC16 *fileName) : + CActive(CActive::EPriorityStandard), + m_imageSession(imageSession), + m_fs(fileSystemAccess), + m_jpegImageData(data), + m_jpegImageFile(fileName), + m_fileInput(false) +{ + CActiveScheduler::Add(this); +} + +S60ImageCaptureDecoder::~S60ImageCaptureDecoder() +{ + if (m_imageDecoder) { + delete m_imageDecoder; + m_imageDecoder = 0; + } +} + +S60ImageCaptureDecoder *S60ImageCaptureDecoder::FileNewL(S60ImageCaptureSession *imageSession, + RFs *fileSystemAccess, + const TDesC16 *fileName) +{ + S60ImageCaptureDecoder* self = new (ELeave) S60ImageCaptureDecoder(imageSession, + fileSystemAccess, + 0, + fileName); + CleanupStack::PushL(self); + self->ConstructL(true); + CleanupStack::Pop(self); + return self; +} + +S60ImageCaptureDecoder *S60ImageCaptureDecoder::DataNewL(S60ImageCaptureSession *imageSession, + RFs *fileSystemAccess, + const TDesC8 *data) +{ + S60ImageCaptureDecoder* self = new (ELeave) S60ImageCaptureDecoder(imageSession, + fileSystemAccess, + data, + 0); + CleanupStack::PushL(self); + self->ConstructL(false); + CleanupStack::Pop(self); + return self; +} + +void S60ImageCaptureDecoder::ConstructL(const bool fileInput) +{ + if (fileInput) { + if (!m_imageSession || !m_fs || !m_jpegImageFile) + User::Leave(KErrGeneral); + m_imageDecoder = CImageDecoder::FileNewL(*m_fs, *m_jpegImageFile); + } else { + if (!m_imageSession || !m_fs || !m_jpegImageData) + User::Leave(KErrGeneral); + m_imageDecoder = CImageDecoder::DataNewL(*m_fs, *m_jpegImageData); + } +} + +void S60ImageCaptureDecoder::decode(CFbsBitmap *destBitmap) +{ + if (m_imageDecoder) { + m_imageDecoder->Convert(&iStatus, *destBitmap, 0); + SetActive(); + } + else + m_imageSession->setError(KErrGeneral, QLatin1String("Preview image creation failed.")); +} + +TFrameInfo *S60ImageCaptureDecoder::frameInfo() +{ + if (m_imageDecoder) { + m_frameInfo = m_imageDecoder->FrameInfo(); + return &m_frameInfo; + } + else + return 0; +} + +void S60ImageCaptureDecoder::RunL() +{ + m_imageSession->handleImageDecoded(iStatus.Int()); +} + +void S60ImageCaptureDecoder::DoCancel() +{ + if (m_imageDecoder) + m_imageDecoder->Cancel(); +} + +TInt S60ImageCaptureDecoder::RunError(TInt aError) +{ + m_imageSession->setError(aError, QLatin1String("Preview image creation failed.")); + return KErrNone; +} + +//============================================================================= + +S60ImageCaptureEncoder::S60ImageCaptureEncoder(S60ImageCaptureSession *imageSession, + RFs *fileSystemAccess, + const TDesC16 *fileName, + TInt jpegQuality) : + CActive(CActive::EPriorityStandard), + m_imageSession(imageSession), + m_fileSystemAccess(fileSystemAccess), + m_fileName(fileName), + m_jpegQuality(jpegQuality) +{ + CActiveScheduler::Add(this); +} + +S60ImageCaptureEncoder::~S60ImageCaptureEncoder() +{ + if (m_frameImageData) { + delete m_frameImageData; + m_frameImageData = 0; + } + if (m_imageEncoder) { + delete m_imageEncoder; + m_imageEncoder = 0; + } +} + +S60ImageCaptureEncoder *S60ImageCaptureEncoder::NewL(S60ImageCaptureSession *imageSession, + RFs *fileSystemAccess, + const TDesC16 *fileName, + TInt jpegQuality) +{ + S60ImageCaptureEncoder* self = new (ELeave) S60ImageCaptureEncoder(imageSession, + fileSystemAccess, + fileName, + jpegQuality); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(self); + return self; +} + +void S60ImageCaptureEncoder::ConstructL() +{ + if (!m_imageSession || !m_fileSystemAccess || !m_fileName) + User::Leave(KErrGeneral); + + m_imageEncoder = CImageEncoder::FileNewL(*m_fileSystemAccess, + *m_fileName, + CImageEncoder::EOptionNone, + KImageTypeJPGUid); + CleanupStack::PushL(m_imageEncoder); + + // Set Jpeg Quality + m_frameImageData = CFrameImageData::NewL(); + CleanupStack::PushL(m_frameImageData); + + TJpegImageData* jpegFormat = new( ELeave ) TJpegImageData; + CleanupStack::PushL(jpegFormat); + + jpegFormat->iQualityFactor = m_jpegQuality; + + // jpegFormat (TJpegImageData) ownership transferred to m_frameImageData (CFrameImageData) + User::LeaveIfError( m_frameImageData->AppendImageData(jpegFormat)); + + CleanupStack::Pop(jpegFormat); + CleanupStack::Pop(m_frameImageData); + CleanupStack::Pop(m_imageEncoder); +} + +void S60ImageCaptureEncoder::encode(CFbsBitmap *sourceBitmap) +{ + if (m_imageEncoder) { + m_imageEncoder->Convert(&iStatus, *sourceBitmap, m_frameImageData); + SetActive(); + } + else + m_imageSession->setError(KErrGeneral, QLatin1String("Saving image to file failed.")); +} + +void S60ImageCaptureEncoder::RunL() +{ + m_imageSession->handleImageEncoded(iStatus.Int()); +} + +void S60ImageCaptureEncoder::DoCancel() +{ + if (m_imageEncoder) + m_imageEncoder->Cancel(); +} + +TInt S60ImageCaptureEncoder::RunError(TInt aError) +{ + m_imageSession->setError(aError, QLatin1String("Saving image to file failed.")); + return KErrNone; +} + +//============================================================================= + +S60ImageCaptureSession::S60ImageCaptureSession(QObject *parent) : + QObject(parent), + m_cameraEngine(0), + m_advancedSettings(0), + m_cameraInfo(0), + m_previewBitmap(0), + m_activeScheduler(0), + m_fileSystemAccess(0), + m_imageDecoder(0), + m_imageEncoder(0), + m_error(KErrNone), + m_activeDeviceIndex(KDefaultCameraDevice), + m_cameraStarted(false), + m_icState(EImageCaptureNotPrepared), + m_currentCodec(QString()), + m_captureSize(QSize()), + m_symbianImageQuality(QtMultimediaKit::HighQuality * KSymbianImageQualityCoefficient), + m_captureSettingsSet(false), + m_stillCaptureFileName(QString()), + m_requestedStillCaptureFileName(QString()), + m_currentImageId(0), + m_captureWhenReady(false), + m_previewDecodingOngoing(false), + m_previewInWaitLoop(false) +{ + // Define supported image codecs + m_supportedImageCodecs << "image/jpeg"; + + initializeImageCaptureSettings(); + + // Install ActiveScheduler if needed + if (!CActiveScheduler::Current()) { + m_activeScheduler = new CActiveScheduler; + CActiveScheduler::Install(m_activeScheduler); + } +} + +S60ImageCaptureSession::~S60ImageCaptureSession() +{ + // Delete AdvancedSettings (Should already be destroyed by CameraControl) + deleteAdvancedSettings(); + + m_formats.clear(); + m_supportedImageCodecs.clear(); + + if (m_imageDecoder) { + m_imageDecoder->Cancel(); + delete m_imageDecoder; + m_imageDecoder = 0; + } + if (m_imageEncoder) { + m_imageEncoder->Cancel(); + delete m_imageEncoder; + m_imageEncoder = 0; + } + + if (m_previewBitmap) { + delete m_previewBitmap; + m_previewBitmap = 0; + } + + // Uninstall ActiveScheduler if needed + if (m_activeScheduler) { + CActiveScheduler::Install(0); + delete m_activeScheduler; + m_activeScheduler = 0; + } +} + +CCamera::TFormat S60ImageCaptureSession::defaultImageFormat() +{ + // Primary Camera + if (m_activeDeviceIndex == 0) + return KDefaultImageFormatPrimaryCam; + + // Secondary Camera or other + else + return KDefaultImageFormatSecondaryCam; +} + +bool S60ImageCaptureSession::isDeviceReady() +{ +#ifdef Q_CC_NOKIAX86 // Emulator + return true; +#endif + + if (m_cameraEngine) + return m_cameraEngine->IsCameraReady(); + + return false; +} + +void S60ImageCaptureSession::deleteAdvancedSettings() +{ + if (m_advancedSettings) { + delete m_advancedSettings; + m_advancedSettings = 0; + emit advancedSettingChanged(); + } +} + +void S60ImageCaptureSession::setCameraHandle(CCameraEngine* camerahandle) +{ + if (camerahandle) { + m_cameraEngine = camerahandle; + resetSession(); + + // Set default settings + initializeImageCaptureSettings(); + } +} + +void S60ImageCaptureSession::setCurrentDevice(TInt deviceindex) +{ + m_activeDeviceIndex = deviceindex; +} + +void S60ImageCaptureSession::notifySettingsSet() +{ + m_captureSettingsSet = true; +} + +void S60ImageCaptureSession::resetSession(bool errorHandling) +{ + // Delete old AdvancedSettings + deleteAdvancedSettings(); + + m_captureWhenReady = false; + m_previewDecodingOngoing = false; + m_previewInWaitLoop = false; + m_stillCaptureFileName = QString(); + m_requestedStillCaptureFileName = QString(); + m_icState = EImageCaptureNotPrepared; + + m_error = KErrNone; + m_currentFormat = defaultImageFormat(); + + int err = KErrNone; + m_advancedSettings = S60CameraSettings::New(err, this, m_cameraEngine); + if (err == KErrNotSupported) { + m_advancedSettings = 0; +#ifndef S60_31_PLATFORM // Post S60 3.1 Platform + // Adv. settings may not be supported for other than the Primary Camera + if (m_cameraEngine->CurrentCameraIndex() == 0) + setError(err, tr("Unexpected camera error.")); +#endif // !S60_31_PLATFORM + } else if (err != KErrNone) { // Other errors + m_advancedSettings = 0; + qWarning("Failed to create camera settings handler."); + if (errorHandling) + emit cameraError(QCamera::ServiceMissingError, tr("Failed to recover from error.")); + else + setError(err, tr("Unexpected camera error.")); + return; + } + + if (m_advancedSettings) { + if (m_cameraEngine) + m_cameraEngine->SetAdvancedObserver(m_advancedSettings); + else + setError(KErrNotReady, tr("Unexpected camera error.")); + } + + updateImageCaptureFormats(); + + emit advancedSettingChanged(); +} + +S60CameraSettings* S60ImageCaptureSession::advancedSettings() +{ + return m_advancedSettings; +} + +/* + * This function can be used both internally and from Control classes using + * this session. The error notification will go to the client application + * either through QCameraImageCapture (if captureError is true) or QCamera (if + * captureError is false, default) error signal. + */ +void S60ImageCaptureSession::setError(const TInt error, + const QString &description, + const bool captureError) +{ + if (error == KErrNone) + return; + + m_error = error; + QCameraImageCapture::Error cameraError = fromSymbianErrorToQtMultimediaError(error); + + if (captureError) { + emit this->captureError(m_currentImageId, cameraError, description); + if (cameraError != QCameraImageCapture::NotSupportedFeatureError) + resetSession(true); + } else { + emit this->cameraError(cameraError, description); + if (cameraError != QCamera::NotSupportedFeatureError) + resetSession(true); + } +} + +QCameraImageCapture::Error S60ImageCaptureSession::fromSymbianErrorToQtMultimediaError(int aError) +{ + switch(aError) { + case KErrNone: + return QCameraImageCapture::NoError; // No errors have occurred + case KErrNotReady: + return QCameraImageCapture::NotReadyError; // Not ready for operation + case KErrNotSupported: + return QCameraImageCapture::NotSupportedFeatureError; // The feature is not supported + case KErrNoMemory: + return QCameraImageCapture::OutOfSpaceError; // Out of disk space + case KErrNotFound: + case KErrBadHandle: + return QCameraImageCapture::ResourceError; // No resources available + + default: + return QCameraImageCapture::ResourceError; // Other error has occurred + } +} + +int S60ImageCaptureSession::currentImageId() const +{ + return m_currentImageId; +} + +void S60ImageCaptureSession::initializeImageCaptureSettings() +{ + if (m_captureSettingsSet) + return; + + m_currentCodec = KDefaultImageCodec; + m_captureSize = QSize(-1, -1); + m_currentFormat = defaultImageFormat(); + + // Resolution + if (m_cameraEngine) { + QList<QSize> resolutions = supportedCaptureSizesForCodec(imageCaptureCodec()); + foreach (QSize reso, resolutions) { + if ((reso.width() * reso.height()) > (m_captureSize.width() * m_captureSize.height())) + m_captureSize = reso; + } + } else { + m_captureSize = KDefaultImageResolution; + } + + m_symbianImageQuality = KDefaultImageQuality; +} + +/* + * This function selects proper format to be used for the captured image based + * on the requested image codec. + */ +CCamera::TFormat S60ImageCaptureSession::selectFormatForCodec(const QString &codec) +{ + CCamera::TFormat format = CCamera::EFormatMonochrome; + + if (codec == "image/jpg" || codec == "image/jpeg") { + // Primary Camera + if (m_activeDeviceIndex == 0) + format = KDefaultImageFormatPrimaryCam; + + // Secondary Camera or other + else + format = KDefaultImageFormatSecondaryCam; + + return format; + } + + setError(KErrNotSupported, tr("Failed to select color format to be used with image codec.")); + return format; +} + +int S60ImageCaptureSession::prepareImageCapture() +{ + if (m_cameraEngine) { + if (!m_cameraEngine->IsCameraReady()) { + // Reset state to make sure camera is prepared before capturing image + m_icState = EImageCaptureNotPrepared; + return KErrNotReady; + } + + // First set the quality + CCamera *camera = m_cameraEngine->Camera(); + if (camera) + camera->SetJpegQuality(m_symbianImageQuality); + else + setError(KErrNotReady, tr("Setting image quality failed."), true); + + // Then prepare with correct resolution and format + TSize captureSize = TSize(m_captureSize.width(), m_captureSize.height()); + TRAPD(symbianError, m_cameraEngine->PrepareL(captureSize, m_currentFormat)); + if (!symbianError) + m_icState = EImageCapturePrepared; + + // Check if CaptureSize was modified + if (captureSize.iWidth != m_captureSize.width() || captureSize.iHeight != m_captureSize.height()) + m_captureSize = QSize(captureSize.iWidth, captureSize.iHeight); + emit captureSizeChanged(m_captureSize); + +#ifdef ECAM_PREVIEW_API + // Subscribe previews + MCameraPreviewObserver *observer = this; + m_cameraEngine->EnablePreviewProvider(observer); +#endif // ECAM_PREVIEW_API + + return symbianError; + } + + return KErrGeneral; +} + +void S60ImageCaptureSession::releaseImageCapture() +{ + // Make sure ImageCapture is prepared the next time it is being activated + m_icState = EImageCaptureNotPrepared; + +#ifdef ECAM_PREVIEW_API + // Cancel preview subscription + m_cameraEngine->DisablePreviewProvider(); +#endif // ECAM_PREVIEW_API +} + +int S60ImageCaptureSession::capture(const QString &fileName) +{ + if (!m_cameraStarted) { + m_captureWhenReady = true; + m_requestedStillCaptureFileName = fileName; // Save name, it will be processed during actual capture + return 0; + } + + if (m_icState < EImageCapturePrepared) { + int prepareSuccess = prepareImageCapture(); + if (prepareSuccess) { + setError(prepareSuccess, tr("Failure during image capture preparation."), true); + return 0; + } + } else if (m_icState > EImageCapturePrepared) { + setError(KErrNotReady, tr("Previous operation is still ongoing."), true); + return 0; + } + + m_icState = EImageCaptureCapturing; + + // Give new ID for the new image + m_currentImageId += 1; + + emit readyForCaptureChanged(false); + + processFileName(fileName); + + if (m_cameraEngine) { + TRAPD(err, m_cameraEngine->CaptureL()); + setError(err, tr("Image capture failed."), true); + } else { + setError(KErrNotReady, tr("Unexpected camera error."), true); + } + +#ifdef Q_CC_NOKIAX86 // Emulator + QImage *snapImage = new QImage(QLatin1String("C:/Data/testimage.jpg")); + emit imageExposed(m_currentImageId); + emit imageCaptured(m_currentImageId, *snapImage); + emit imageSaved(m_currentImageId, m_stillCaptureFileName); +#endif // Q_CC_NOKIAX86 + + return m_currentImageId; +} + +void S60ImageCaptureSession::cancelCapture() +{ + if (m_icState != EImageCaptureCapturing) + return; + + if (m_cameraEngine) + m_cameraEngine->CancelCapture(); + + m_icState = EImageCapturePrepared; +} + +void S60ImageCaptureSession::processFileName(const QString &fileName) +{ + // Empty FileName - Use default file name and path (C:\Data\Images\image.jpg) + if (fileName.isEmpty()) { + // Make sure default directory exists + QDir videoDir(QDir::rootPath()); + if (!videoDir.exists(KDefaultImagePath)) + videoDir.mkpath(KDefaultImagePath); + QString defaultFile = KDefaultImagePath; + defaultFile.append("\\"); + defaultFile.append(KDefaultImageFileName); + m_stillCaptureFileName = defaultFile; + + } else { // Not empty + + QString fullFileName; + + // Relative FileName + if (!fileName.contains(":")) { + // Extract file name and path from the URL + fullFileName = KDefaultImagePath; + if (fileName.at(0) != '\\') + fullFileName.append("\\"); + fullFileName.append(QDir::toNativeSeparators(QDir::cleanPath(fileName))); + + // Absolute FileName + } else { + // Extract file name and path from the given location + fullFileName = QDir::toNativeSeparators(QDir::cleanPath(fileName)); + } + + QString fileNameOnly = fullFileName.right(fullFileName.length() - fullFileName.lastIndexOf("\\") - 1); + QString directory = fullFileName.left(fullFileName.lastIndexOf("\\")); + if (directory.lastIndexOf("\\") == (directory.length() - 1)) + directory = directory.left(directory.length() - 1); + + // URL is Absolute path, not including file name + if (!fileNameOnly.contains(".")) { + if (fileNameOnly != "") { + directory.append("\\"); + directory.append(fileNameOnly); + } + fileNameOnly = KDefaultImageFileName; + } + + // Make sure absolute directory exists + QDir imageDir(QDir::rootPath()); + if (!imageDir.exists(directory)) + imageDir.mkpath(directory); + + QString resolvedFileName = directory; + resolvedFileName.append("\\"); + resolvedFileName.append(fileNameOnly); + m_stillCaptureFileName = resolvedFileName; + } +} + +void S60ImageCaptureSession::MceoFocusComplete() +{ + emit focusStatusChanged(QCamera::Locked, QCamera::LockAcquired); +} + +void S60ImageCaptureSession::MceoCapturedDataReady(TDesC8* aData) +{ + emit imageExposed(m_currentImageId); + + m_icState = EImageCaptureWritingImage; + + TFileName path = convertImagePath(); + + // Try to save image and inform if it was succcesful + TRAPD(err, saveImageL(aData, path)); + if (err) { + if (m_previewDecodingOngoing) + m_previewDecodingOngoing = false; // Reset + + setError(err, tr("Writing captured image to a file failed."), true); + m_icState = EImageCapturePrepared; + return; + } + + m_icState = EImageCapturePrepared; + +} + +void S60ImageCaptureSession::MceoCapturedBitmapReady(CFbsBitmap* aBitmap) +{ + emit imageExposed(m_currentImageId); + + m_icState = EImageCaptureWritingImage; + + if(aBitmap) + { +#ifndef ECAM_PREVIEW_API + if (m_previewDecodingOngoing) { + m_previewInWaitLoop = true; + CActiveScheduler::Start(); // Wait for the completion of the previous Preview generation + } + + // Delete old instances if needed + if (m_imageDecoder) { + delete m_imageDecoder; + m_imageDecoder = 0; + } + if (m_previewBitmap) { + delete m_previewBitmap; + m_previewBitmap = 0; + } +#endif // ECAM_CAMERA_API + if (m_imageEncoder) { + delete m_imageEncoder; + m_imageEncoder = 0; + } + if (m_fileSystemAccess) { + m_fileSystemAccess->Close(); + delete m_fileSystemAccess; + m_fileSystemAccess = 0; + } + + TInt saveError = KErrNone; + TFileName path = convertImagePath(); + + // Create FileSystem access + m_fileSystemAccess = new RFs; + if (!m_fileSystemAccess) { + setError(KErrNoMemory, tr("Failed to write captured image to a file.")); + return; + } + saveError = m_fileSystemAccess->Connect(); + if (saveError) { + setError(saveError, tr("Failed to write captured image to a file.")); + return; + } + + TRAP(saveError, m_imageEncoder = S60ImageCaptureEncoder::NewL(this, + m_fileSystemAccess, + &path, + m_symbianImageQuality)); + if (saveError) + setError(saveError, tr("Saving captured image failed."), true); + m_previewDecodingOngoing = true; + m_imageEncoder->encode(aBitmap); + + } else { + setError(KErrBadHandle, tr("Unexpected camera error."), true); + } + + m_icState = EImageCapturePrepared; +} + +void S60ImageCaptureSession::MceoHandleError(TCameraEngineError aErrorType, TInt aError) +{ + Q_UNUSED(aErrorType); + setError(aError, tr("General camera error.")); +} + +TFileName S60ImageCaptureSession::convertImagePath() +{ + TFileName path = KNullDesC(); + + // Convert to Symbian path + TPtrC16 attachmentPath(KNullDesC); + + // Path is already included in filename + attachmentPath.Set(reinterpret_cast<const TUint16*>(QDir::toNativeSeparators(m_stillCaptureFileName).utf16())); + path.Append(attachmentPath); + + return path; +} + +/* + * Creates (asynchronously) Preview Image from Jpeg ImageBuffer and also + * writes Jpeg (synchronously) to a file. + */ +void S60ImageCaptureSession::saveImageL(TDesC8 *aData, TFileName &aPath) +{ + if (aData == 0) + setError(KErrGeneral, tr("Captured image data is not available."), true); + + if (aPath.Size() > 0) { +#ifndef ECAM_PREVIEW_API + if (m_previewDecodingOngoing) { + m_previewInWaitLoop = true; + CActiveScheduler::Start(); // Wait for the completion of the previous Preview generation + } + + // Delete old instances if needed + if (m_imageDecoder) { + delete m_imageDecoder; + m_imageDecoder = 0; + } + if (m_previewBitmap) { + delete m_previewBitmap; + m_previewBitmap = 0; + } +#endif // ECAM_PREVIEW_API + if (m_fileSystemAccess) { + m_fileSystemAccess->Close(); + delete m_fileSystemAccess; + m_fileSystemAccess = 0; + } + + RFs *fileSystemAccess = new (ELeave) RFs; + User::LeaveIfError(fileSystemAccess->Connect()); + CleanupClosePushL(*fileSystemAccess); + +#ifndef ECAM_PREVIEW_API + // Generate Thumbnail to be used as Preview + S60ImageCaptureDecoder *imageDecoder = S60ImageCaptureDecoder::DataNewL(this, fileSystemAccess, aData); + CleanupStack::PushL(imageDecoder); + + // Set proper Preview Size + TSize scaledSize((m_captureSize.width() / KSnapshotDownScaleFactor), (m_captureSize.height() / KSnapshotDownScaleFactor)); + if (scaledSize.iWidth < KSnapshotMinWidth || scaledSize.iHeight < KSnapshotMinHeight) + scaledSize.SetSize((m_captureSize.width() / (KSnapshotDownScaleFactor/2)), (m_captureSize.height() / (KSnapshotDownScaleFactor/2))); + if (scaledSize.iWidth < KSnapshotMinWidth || scaledSize.iHeight < KSnapshotMinHeight) + scaledSize.SetSize((m_captureSize.width() / (KSnapshotDownScaleFactor/4)), (m_captureSize.height() / (KSnapshotDownScaleFactor/4))); + if (scaledSize.iWidth < KSnapshotMinWidth || scaledSize.iHeight < KSnapshotMinHeight) + scaledSize.SetSize(m_captureSize.width(), m_captureSize.height()); + + TFrameInfo *info = imageDecoder->frameInfo(); + if (!info) { + setError(KErrGeneral, tr("Preview image creation failed.")); + return; + } + + CFbsBitmap *previewBitmap = new (ELeave) CFbsBitmap; + CleanupStack::PushL(previewBitmap); + TInt bitmapCreationErr = previewBitmap->Create(scaledSize, info->iFrameDisplayMode); + if (bitmapCreationErr) { + setError(bitmapCreationErr, tr("Preview creation failed.")); + return; + } + + // Jpeg conversion completes in RunL + m_previewDecodingOngoing = true; + imageDecoder->decode(previewBitmap); +#endif // ECAM_PREVIEW_API + + RFile file; + TInt fileWriteErr = KErrNone; + fileWriteErr = file.Replace(*fileSystemAccess, aPath, EFileWrite); + if (fileWriteErr) + User::Leave(fileWriteErr); + CleanupClosePushL(file); // Close if Leaves + + fileWriteErr = file.Write(*aData); + if (fileWriteErr) + User::Leave(fileWriteErr); + + CleanupStack::PopAndDestroy(&file); +#ifdef ECAM_PREVIEW_API + CleanupStack::PopAndDestroy(fileSystemAccess); +#else // !ECAM_PREVIEW_API + // Delete when Image is decoded + CleanupStack::Pop(previewBitmap); + CleanupStack::Pop(imageDecoder); + CleanupStack::Pop(fileSystemAccess); + + // Set member variables (Cannot leave any more) + m_previewBitmap = previewBitmap; + m_imageDecoder = imageDecoder; + m_fileSystemAccess = fileSystemAccess; +#endif // ECAM_PREVIEW_API + + emit imageSaved(m_currentImageId, m_stillCaptureFileName); + + // Inform that we can continue taking more pictures + emit readyForCaptureChanged(true); + + // For custom preview generation, image buffer gets released in RunL() +#ifdef ECAM_PREVIEW_API + releaseImageBuffer(); +#endif // ECAM_PREVIEW_API + + } else { + setError(KErrPathNotFound, tr("Invalid path given."), true); + } +} + +void S60ImageCaptureSession::releaseImageBuffer() +{ + if (m_cameraEngine) + m_cameraEngine->ReleaseImageBuffer(); + else + setError(KErrNotReady, tr("Unexpected camera error."), true); +} + +/* + * Queries camera properties + * Results are returned to member variable m_info + * + * @return boolean indicating if querying the info was a success + */ +bool S60ImageCaptureSession::queryCurrentCameraInfo() +{ + if (m_cameraEngine) { + m_cameraInfo = m_cameraEngine->CameraInfo(); + return true; + } + + return false; +} + +/* + * This function handles different camera status changes + */ +void S60ImageCaptureSession::cameraStatusChanged(QCamera::Status status) +{ + if (status == QCamera::ActiveStatus) { + m_cameraStarted = true; + if (m_captureWhenReady) + capture(m_requestedStillCaptureFileName); + }else if (status == QCamera::UnloadedStatus) { + m_cameraStarted = false; + m_icState = EImageCaptureNotPrepared; + } + else + m_cameraStarted = false; +} + +QSize S60ImageCaptureSession::captureSize() const +{ + return m_captureSize; +} + +QSize S60ImageCaptureSession::minimumCaptureSize() +{ + return supportedCaptureSizesForCodec(formatMap().key(m_currentFormat)).first(); +} +QSize S60ImageCaptureSession::maximumCaptureSize() +{ + return supportedCaptureSizesForCodec(formatMap().key(m_currentFormat)).last(); +} + +void S60ImageCaptureSession::setCaptureSize(const QSize &size) +{ + if (size.isNull() || + size.isEmpty() || + size == QSize(-1,-1)) { + // An empty QSize indicates the encoder should make an optimal choice based on what is + // available from the image source and the limitations of the codec. + m_captureSize = supportedCaptureSizesForCodec(formatMap().key(m_currentFormat)).last(); + } + else + m_captureSize = size; +} + +QList<QSize> S60ImageCaptureSession::supportedCaptureSizesForCodec(const QString &codecName) +{ + QList<QSize> list; + + // If we have CameraEngine loaded and we can update CameraInfo + if (m_cameraEngine && queryCurrentCameraInfo()) { + CCamera::TFormat format; + if (codecName == "") + format = defaultImageFormat(); + else + format = selectFormatForCodec(codecName); + + CCamera *camera = m_cameraEngine->Camera(); + TSize imageSize; + if (camera) { + for (int i = 0; i < m_cameraInfo->iNumImageSizesSupported; i++) { + camera->EnumerateCaptureSizes(imageSize, i, format); + list << QSize(imageSize.iWidth, imageSize.iHeight); // Add resolution to the list + } + } + } + +#ifdef Q_CC_NOKIAX86 // Emulator + // Add some for testing purposes + list << QSize(50, 50); + list << QSize(100, 100); + list << QSize(800,600); +#endif + + return list; +} + +QMap<QString, int> S60ImageCaptureSession::formatMap() +{ + QMap<QString, int> formats; + + // Format list copied from CCamera::TFormat (in ecam.h) + formats.insert("Monochrome", 0x0001); + formats.insert("16bitRGB444", 0x0002); + formats.insert("16BitRGB565", 0x0004); + formats.insert("32BitRGB888", 0x0008); + formats.insert("Jpeg", 0x0010); + formats.insert("Exif", 0x0020); + formats.insert("FbsBitmapColor4K", 0x0040); + formats.insert("FbsBitmapColor64K", 0x0080); + formats.insert("FbsBitmapColor16M", 0x0100); + formats.insert("UserDefined", 0x0200); + formats.insert("YUV420Interleaved", 0x0400); + formats.insert("YUV420Planar", 0x0800); + formats.insert("YUV422", 0x1000); + formats.insert("YUV422Reversed", 0x2000); + formats.insert("YUV444", 0x4000); + formats.insert("YUV420SemiPlanar", 0x8000); + formats.insert("FbsBitmapColor16MU", 0x00010000); + formats.insert("MJPEG", 0x00020000); + formats.insert("EncodedH264", 0x00040000); + + return formats; +} + +QMap<QString, QString> S60ImageCaptureSession::codecDescriptionMap() +{ + QMap<QString, QString> formats; + + formats.insert("image/jpg", "JPEG image codec"); + + return formats; +} + +QStringList S60ImageCaptureSession::supportedImageCaptureCodecs() +{ +#ifdef Q_CC_NOKIAX86 // Emulator + return formatMap().keys(); +#endif + + return m_supportedImageCodecs; +} + +void S60ImageCaptureSession::updateImageCaptureFormats() +{ + m_formats.clear(); + if (m_cameraEngine && queryCurrentCameraInfo()) { + TUint32 supportedFormats = m_cameraInfo->iImageFormatsSupported; + +#ifdef S60_3X_PLATFORM // S60 3.1 & 3.2 + int maskEnd = CCamera::EFormatFbsBitmapColor16MU; +#else // S60 5.0 or later + int maskEnd = CCamera::EFormatEncodedH264; +#endif // S60_3X_PLATFORM + + for (int mask = CCamera::EFormatMonochrome; mask <= maskEnd; mask <<= 1) { + if (supportedFormats & mask) + m_formats << mask; // Store mask of supported format + } + } +} + +QString S60ImageCaptureSession::imageCaptureCodec() +{ + return m_currentCodec; +} +void S60ImageCaptureSession::setImageCaptureCodec(const QString &codecName) +{ + if (!codecName.isEmpty()) { + if (supportedImageCaptureCodecs().contains(codecName, Qt::CaseInsensitive) || + codecName == "image/jpg") { + m_currentCodec = codecName; + m_currentFormat = selectFormatForCodec(m_currentCodec); + } else { + setError(KErrNotSupported, tr("Requested image codec is not supported")); + } + } else { + m_currentCodec = KDefaultImageCodec; + m_currentFormat = selectFormatForCodec(m_currentCodec); + } +} + +QString S60ImageCaptureSession::imageCaptureCodecDescription(const QString &codecName) +{ + QString description = codecDescriptionMap().value(codecName); + return description; +} + +QtMultimediaKit::EncodingQuality S60ImageCaptureSession::captureQuality() const +{ + switch (m_symbianImageQuality) { + case KJpegQualityVeryLow: + return QtMultimediaKit::VeryLowQuality; + case KJpegQualityLow: + return QtMultimediaKit::LowQuality; + case KJpegQualityNormal: + return QtMultimediaKit::NormalQuality; + case KJpegQualityHigh: + return QtMultimediaKit::HighQuality; + case KJpegQualityVeryHigh: + return QtMultimediaKit::VeryHighQuality; + + default: + // Return normal as default + return QtMultimediaKit::NormalQuality; + } +} + +void S60ImageCaptureSession::setCaptureQuality(const QtMultimediaKit::EncodingQuality &quality) +{ + // Use sensible presets + switch (quality) { + case QtMultimediaKit::VeryLowQuality: + m_symbianImageQuality = KJpegQualityVeryLow; + break; + case QtMultimediaKit::LowQuality: + m_symbianImageQuality = KJpegQualityLow; + break; + case QtMultimediaKit::NormalQuality: + m_symbianImageQuality = KJpegQualityNormal; + break; + case QtMultimediaKit::HighQuality: + m_symbianImageQuality = KJpegQualityHigh; + break; + case QtMultimediaKit::VeryHighQuality: + m_symbianImageQuality = KJpegQualityVeryHigh; + break; + + default: + m_symbianImageQuality = quality * KSymbianImageQualityCoefficient; + break; + } +} + +qreal S60ImageCaptureSession::maximumZoom() +{ + qreal maxZoomFactor = 1.0; + + if (queryCurrentCameraInfo()) { + maxZoomFactor = m_cameraInfo->iMaxZoomFactor; + + if (maxZoomFactor == 0.0 || maxZoomFactor == 1.0) { + return 1.0; // Not supported + } else { + return maxZoomFactor; + } + } else { + return 1.0; + } +} + +qreal S60ImageCaptureSession::minZoom() +{ + qreal minZoomValue = 1.0; + + if (queryCurrentCameraInfo()) { + minZoomValue = m_cameraInfo->iMinZoomFactor; + if (minZoomValue == 0.0 || minZoomValue == 1.0) + return 1.0; // Macro Zoom is not supported + else { + return minZoomValue; + } + + } else { + return 1.0; + } +} + +qreal S60ImageCaptureSession::maxDigitalZoom() +{ + qreal maxDigitalZoomFactor = 1.0; + + if (queryCurrentCameraInfo()) { + maxDigitalZoomFactor = m_cameraInfo->iMaxDigitalZoomFactor; + return maxDigitalZoomFactor; + } else { + return 1.0; + } +} + +void S60ImageCaptureSession::doSetZoomFactorL(qreal optical, qreal digital) +{ +#if !defined(USE_S60_32_ECAM_ADVANCED_SETTINGS_HEADER) & !defined(USE_S60_50_ECAM_ADVANCED_SETTINGS_HEADER) + // Convert Zoom Factor to Zoom Value if AdvSettings are not available + int digitalSymbian = (digital * m_cameraInfo->iMaxDigitalZoom) / maxDigitalZoom(); + if (m_cameraInfo->iMaxDigitalZoom != 0 && digital == 1.0) + digitalSymbian = 1; // Make sure zooming out to initial value if requested +#endif // !USE_S60_32_ECAM_ADVANCED_SETTINGS_HEADER & !USE_S60_50_ECAM_ADVANCED_SETTINGS_HEADER + + if (m_cameraEngine && !m_cameraEngine->IsCameraReady()) + return; + + if (m_cameraEngine && queryCurrentCameraInfo()) { + CCamera *camera = m_cameraEngine->Camera(); + if (camera) { + + // Optical Zoom + if (!qFuzzyCompare(optical, qreal(1.0)) && !qFuzzyCompare(optical, qreal(0.0))) { + setError(KErrNotSupported, tr("Requested optical zoom factor is not supported.")); + return; + } + + // Digital Zoom (Smooth Zoom - Zoom value set in steps) + if (digital != digitalZoomFactor()) { + if ((digital > 1.0 || qFuzzyCompare(digital, qreal(1.0))) && + digital <= m_cameraInfo->iMaxDigitalZoomFactor) { +#if defined(USE_S60_32_ECAM_ADVANCED_SETTINGS_HEADER) | defined(USE_S60_50_ECAM_ADVANCED_SETTINGS_HEADER) + if (m_advancedSettings) { + qreal currentZoomFactor = m_advancedSettings->digitalZoomFactorL(); + + QList<qreal> smoothZoomSetValues; + QList<qreal> factors = m_advancedSettings->supportedDigitalZoomFactors(); + if (currentZoomFactor < digital) { + for (int i = 0; i < factors.count(); ++i) { + if (factors.at(i) > currentZoomFactor && factors.at(i) < digital) + smoothZoomSetValues << factors.at(i); + } + + for (int i = 0; i < smoothZoomSetValues.count(); i = i + KSmoothZoomStep) { + m_advancedSettings->setDigitalZoomFactorL(smoothZoomSetValues[i]); // Using Zoom Factor + } + + } else { + for (int i = 0; i < factors.count(); ++i) { + if (factors.at(i) < currentZoomFactor && factors.at(i) > digital) + smoothZoomSetValues << factors.at(i); + } + + for (int i = (smoothZoomSetValues.count() - 1); i >= 0; i = i - KSmoothZoomStep) { + m_advancedSettings->setDigitalZoomFactorL(smoothZoomSetValues[i]); // Using Zoom Factor + } + } + + // Set final value + m_advancedSettings->setDigitalZoomFactorL(digital); + } + else + setError(KErrNotReady, tr("Zooming failed.")); +#else // No advanced settigns + // Define zoom steps + int currentZoomFactor = camera->DigitalZoomFactor(); + int difference = abs(currentZoomFactor - digitalSymbian); + int midZoomValue = currentZoomFactor; + + if (currentZoomFactor < digitalSymbian) { + while (midZoomValue < (digitalSymbian - KSmoothZoomStep)) { + midZoomValue = midZoomValue + KSmoothZoomStep; + camera->SetDigitalZoomFactorL(midZoomValue); + } + } else { + while (midZoomValue > (digitalSymbian + KSmoothZoomStep)) { + midZoomValue = midZoomValue - KSmoothZoomStep; + camera->SetDigitalZoomFactorL(midZoomValue); + } + } + + // Set final and emit signal + camera->SetDigitalZoomFactorL(digitalSymbian); +#endif // USE_S60_32_ECAM_ADVANCED_SETTINGS_HEADER | USE_S60_50_ECAM_ADVANCED_SETTINGS_HEADER + } else { + setError(KErrNotSupported, tr("Requested digital zoom factor is not supported.")); + return; + } + } + } + } else { + setError(KErrGeneral, tr("Unexpected camera error.")); + } +} + +qreal S60ImageCaptureSession::opticalZoomFactor() +{ + qreal factor = 1.0; + +#if defined(USE_S60_32_ECAM_ADVANCED_SETTINGS_HEADER) | defined(USE_S60_50_ECAM_ADVANCED_SETTINGS_HEADER) + if (m_advancedSettings) { + TRAPD(err, factor = m_advancedSettings->opticalZoomFactorL()); + if (err) + return 1.0; + } +#else // No advanced settigns + if (m_cameraEngine && m_cameraInfo) { + if (m_cameraEngine->Camera()) { + if (m_cameraInfo->iMaxZoom != 0) + factor = (m_cameraEngine->Camera()->ZoomFactor()* maximumZoom()) / m_cameraInfo->iMaxZoom; + else + factor = 1.0; + } + } +#endif // USE_S60_32_ECAM_ADVANCED_SETTINGS_HEADER | USE_S60_50_ECAM_ADVANCED_SETTINGS_HEADER + + if (factor == 0.0) // If not supported + factor = 1.0; + + return factor; +} + +qreal S60ImageCaptureSession::digitalZoomFactor() +{ + qreal factor = 1.0; + +#if defined(USE_S60_32_ECAM_ADVANCED_SETTINGS_HEADER) | defined(USE_S60_50_ECAM_ADVANCED_SETTINGS_HEADER) + if (m_advancedSettings) { + TRAPD(err, factor = m_advancedSettings->digitalZoomFactorL()); + if (err) + return 1.0; + } +#else // No advanced settigns + if (m_cameraEngine && m_cameraInfo) { + if (m_cameraEngine->Camera()) { + if (m_cameraInfo->iMaxDigitalZoom != 0) + factor = (m_cameraEngine->Camera()->DigitalZoomFactor()* maxDigitalZoom()) / m_cameraInfo->iMaxDigitalZoom; + else + factor = 1.0; + } + } +#endif // USE_S60_32_ECAM_ADVANCED_SETTINGS_HEADER | USE_S60_50_ECAM_ADVANCED_SETTINGS_HEADER + + if (factor == 0.0) + factor = 1.0; + + return factor; +} + +void S60ImageCaptureSession::setFlashMode(QCameraExposure::FlashModes mode) +{ + TRAPD(err, doSetFlashModeL(mode)); + setError(err, tr("Failed to set flash mode.")); +} + +void S60ImageCaptureSession::doSetFlashModeL(QCameraExposure::FlashModes mode) +{ + if (m_cameraEngine && m_cameraEngine->Camera()) { + CCamera *camera = m_cameraEngine->Camera(); + switch(mode) { + case QCameraExposure::FlashOff: + camera->SetFlashL(CCamera::EFlashNone); + break; + case QCameraExposure::FlashAuto: + camera->SetFlashL(CCamera::EFlashAuto); + break; + case QCameraExposure::FlashOn: + camera->SetFlashL(CCamera::EFlashForced); + break; + case QCameraExposure::FlashRedEyeReduction: + camera->SetFlashL(CCamera::EFlashRedEyeReduce); + break; + case QCameraExposure::FlashFill: + camera->SetFlashL(CCamera::EFlashFillIn); + break; + + default: + setError(KErrNotSupported, tr("Requested flash mode is not suported")); + break; + } + } else { + setError(KErrNotReady, tr("Unexpected camera error.")); + } +} + +QCameraExposure::FlashMode S60ImageCaptureSession::flashMode() +{ + if (m_cameraEngine && m_cameraEngine->Camera()) { + CCamera *camera = m_cameraEngine->Camera(); + switch(camera->Flash()) { + case CCamera::EFlashAuto: + return QCameraExposure::FlashAuto; + case CCamera::EFlashForced: + return QCameraExposure::FlashOn; + case CCamera::EFlashRedEyeReduce: + return QCameraExposure::FlashRedEyeReduction; + case CCamera::EFlashFillIn: + return QCameraExposure::FlashFill; + case CCamera::EFlashNone: + return QCameraExposure::FlashOff; + + default: + return QCameraExposure::FlashAuto; // Most probable default + } + } else { + setError(KErrNotReady, tr("Unexpected camera error.")); + } + + return QCameraExposure::FlashOff; +} + +QCameraExposure::FlashModes S60ImageCaptureSession::supportedFlashModes() +{ + QCameraExposure::FlashModes modes = QCameraExposure::FlashOff; + + if (queryCurrentCameraInfo()) { + TInt supportedModes = m_cameraInfo->iFlashModesSupported; + + if (supportedModes == 0) + return modes; + + if (supportedModes & CCamera::EFlashManual) + modes |= QCameraExposure::FlashOff; + if (supportedModes & CCamera::EFlashForced) + modes |= QCameraExposure::FlashOn; + if (supportedModes & CCamera::EFlashAuto) + modes |= QCameraExposure::FlashAuto; + if (supportedModes & CCamera::EFlashFillIn) + modes |= QCameraExposure::FlashFill; + if (supportedModes & CCamera::EFlashRedEyeReduce) + modes |= QCameraExposure::FlashRedEyeReduction; + } + + return modes; +} + +QCameraExposure::ExposureMode S60ImageCaptureSession::exposureMode() +{ + if (m_cameraEngine && m_cameraEngine->Camera()) { + CCamera* camera = m_cameraEngine->Camera(); + switch(camera->Exposure()) { + case CCamera::EExposureManual: + return QCameraExposure::ExposureManual; + case CCamera::EExposureAuto: + return QCameraExposure::ExposureAuto; + case CCamera::EExposureNight: + return QCameraExposure::ExposureNight; + case CCamera::EExposureBacklight: + return QCameraExposure::ExposureBacklight; + case CCamera::EExposureSport: + return QCameraExposure::ExposureSports; + case CCamera::EExposureSnow: + return QCameraExposure::ExposureSnow; + case CCamera::EExposureBeach: + return QCameraExposure::ExposureBeach; + + default: + return QCameraExposure::ExposureAuto; + } + } + + return QCameraExposure::ExposureAuto; +} + +bool S60ImageCaptureSession::isExposureModeSupported(QCameraExposure::ExposureMode mode) const +{ + TInt supportedModes = m_cameraInfo->iExposureModesSupported; + + if (supportedModes == 0) + return false; + + switch (mode) { + case QCameraExposure::ExposureManual: + if(supportedModes & CCamera::EExposureManual) + return true; + else + return false; + case QCameraExposure::ExposureAuto: + return true; // Always supported + case QCameraExposure::ExposureNight: + if(supportedModes & CCamera::EExposureNight) + return true; + else + return false; + case QCameraExposure::ExposureBacklight: + if(supportedModes & CCamera::EExposureBacklight) + return true; + else + return false; + case QCameraExposure::ExposureSports: + if(supportedModes & CCamera::EExposureSport) + return true; + else + return false; + case QCameraExposure::ExposureSnow: + if(supportedModes & CCamera::EExposureSnow) + return true; + else + return false; + case QCameraExposure::ExposureBeach: + if(supportedModes & CCamera::EExposureBeach) + return true; + else + return false; + + default: + return false; + } +} + +void S60ImageCaptureSession::setExposureMode(QCameraExposure::ExposureMode mode) +{ + TRAPD(err, doSetExposureModeL(mode)); + setError(err, tr("Failed to set exposure mode.")); +} + +void S60ImageCaptureSession::doSetExposureModeL( QCameraExposure::ExposureMode mode) +{ + if (m_cameraEngine && m_cameraEngine->Camera()) { + CCamera *camera = m_cameraEngine->Camera(); + switch(mode) { + case QCameraExposure::ExposureManual: + camera->SetExposureL(CCamera::EExposureManual); + break; + case QCameraExposure::ExposureAuto: + camera->SetExposureL(CCamera::EExposureAuto); + break; + case QCameraExposure::ExposureNight: + camera->SetExposureL(CCamera::EExposureNight); + break; + case QCameraExposure::ExposureBacklight: + camera->SetExposureL(CCamera::EExposureBacklight); + break; + case QCameraExposure::ExposureSports: + camera->SetExposureL(CCamera::EExposureSport); + break; + case QCameraExposure::ExposureSnow: + camera->SetExposureL(CCamera::EExposureSnow); + break; + case QCameraExposure::ExposureBeach: + camera->SetExposureL(CCamera::EExposureBeach); + break; + case QCameraExposure::ExposureLargeAperture: + case QCameraExposure::ExposureSmallAperture: + break; + case QCameraExposure::ExposurePortrait: + case QCameraExposure::ExposureSpotlight: + default: + setError(KErrNotSupported, tr("Requested exposure mode is not suported")); + break; + } + } else { + setError(KErrNotReady, tr("Unexpected camera error.")); + } +} + +int S60ImageCaptureSession::contrast() const +{ + if (m_cameraEngine && m_cameraEngine->Camera()) { + return m_cameraEngine->Camera()->Contrast(); + } else { + return 0; + } +} + +void S60ImageCaptureSession::setContrast(int value) +{ + if (m_cameraEngine && m_cameraEngine->Camera()) { + TRAPD(err, m_cameraEngine->Camera()->SetContrastL(value)); + setError(err, tr("Failed to set contrast.")); + } else { + setError(KErrNotReady, tr("Unexpected camera error.")); + } +} + +int S60ImageCaptureSession::brightness() const +{ + if (m_cameraEngine && m_cameraEngine->Camera()) { + return m_cameraEngine->Camera()->Brightness(); + } else { + return 0; + } +} + +void S60ImageCaptureSession::setBrightness(int value) +{ + if (m_cameraEngine && m_cameraEngine->Camera()) { + TRAPD(err, m_cameraEngine->Camera()->SetBrightnessL(value)); + setError(err, tr("Failed to set brightness.")); + } else { + setError(KErrNotReady, tr("Unexpected camera error.")); + } +} + + QCameraImageProcessing::WhiteBalanceMode S60ImageCaptureSession::whiteBalanceMode() +{ + if (m_cameraEngine && m_cameraEngine->Camera()) { + CCamera::TWhiteBalance mode = m_cameraEngine->Camera()->WhiteBalance(); + switch(mode) { + case CCamera::EWBAuto: + return QCameraImageProcessing::WhiteBalanceAuto; + case CCamera::EWBDaylight: + return QCameraImageProcessing::WhiteBalanceSunlight; + case CCamera::EWBCloudy: + return QCameraImageProcessing::WhiteBalanceCloudy; + case CCamera::EWBTungsten: + return QCameraImageProcessing::WhiteBalanceTungsten; + case CCamera::EWBFluorescent: + return QCameraImageProcessing::WhiteBalanceFluorescent; + case CCamera::EWBFlash: + return QCameraImageProcessing::WhiteBalanceFlash; + case CCamera::EWBBeach: + return QCameraImageProcessing::WhiteBalanceSunset; + case CCamera::EWBManual: + return QCameraImageProcessing::WhiteBalanceManual; + case CCamera::EWBShade: + return QCameraImageProcessing::WhiteBalanceShade; + + default: + return QCameraImageProcessing::WhiteBalanceAuto; + } + } + + return QCameraImageProcessing::WhiteBalanceAuto; +} + +void S60ImageCaptureSession::setWhiteBalanceMode( QCameraImageProcessing::WhiteBalanceMode mode) +{ + TRAPD(err, doSetWhiteBalanceModeL(mode)); + setError(err, tr("Failed to set white balance mode.")); +} + +void S60ImageCaptureSession::doSetWhiteBalanceModeL( QCameraImageProcessing::WhiteBalanceMode mode) +{ + if (m_cameraEngine && m_cameraEngine->Camera()) { + CCamera* camera = m_cameraEngine->Camera(); + switch(mode) { + case QCameraImageProcessing::WhiteBalanceAuto: + camera->SetWhiteBalanceL(CCamera::EWBAuto); + break; + case QCameraImageProcessing::WhiteBalanceSunlight: + camera->SetWhiteBalanceL(CCamera::EWBDaylight); + break; + case QCameraImageProcessing::WhiteBalanceCloudy: + camera->SetWhiteBalanceL(CCamera::EWBCloudy); + break; + case QCameraImageProcessing::WhiteBalanceTungsten: + camera->SetWhiteBalanceL(CCamera::EWBTungsten); + break; + case QCameraImageProcessing::WhiteBalanceFluorescent: + camera->SetWhiteBalanceL(CCamera::EWBFluorescent); + break; + case QCameraImageProcessing::WhiteBalanceFlash: + camera->SetWhiteBalanceL(CCamera::EWBFlash); + break; + case QCameraImageProcessing::WhiteBalanceSunset: + camera->SetWhiteBalanceL(CCamera::EWBBeach); + break; + case QCameraImageProcessing::WhiteBalanceManual: + camera->SetWhiteBalanceL(CCamera::EWBManual); + break; + case QCameraImageProcessing::WhiteBalanceShade: + camera->SetWhiteBalanceL(CCamera::EWBShade); + break; + + default: + setError(KErrNotSupported, tr("Requested white balance mode is not suported")); + break; + } + } else { + setError(KErrNotReady, tr("Unexpected camera error.")); + } +} + +bool S60ImageCaptureSession::isWhiteBalanceModeSupported(QCameraImageProcessing::WhiteBalanceMode mode) const +{ + if (m_cameraEngine) { + TInt supportedModes = m_cameraInfo->iWhiteBalanceModesSupported; + switch (mode) { + case QCameraImageProcessing::WhiteBalanceManual: + if (supportedModes & CCamera::EWBManual) + return true; + else + return false; + case QCameraImageProcessing::WhiteBalanceAuto: + if (supportedModes & CCamera::EWBAuto) + return true; + else + return false; + case QCameraImageProcessing::WhiteBalanceSunlight: + if (supportedModes & CCamera::EWBDaylight) + return true; + else + return false; + case QCameraImageProcessing::WhiteBalanceCloudy: + if (supportedModes & CCamera::EWBCloudy) + return true; + else + return false; + case QCameraImageProcessing::WhiteBalanceShade: + if (supportedModes & CCamera::EWBShade) + return true; + else + return false; + case QCameraImageProcessing::WhiteBalanceTungsten: + if (supportedModes & CCamera::EWBTungsten) + return true; + else + return false; + case QCameraImageProcessing::WhiteBalanceFluorescent: + if (supportedModes & CCamera::EWBFluorescent) + return true; + else + return false; + case QCameraImageProcessing::WhiteBalanceIncandescent: // Not available in Symbian + return false; + case QCameraImageProcessing::WhiteBalanceFlash: + if (supportedModes & CCamera::EWBFlash) + return true; + else + return false; + case QCameraImageProcessing::WhiteBalanceSunset: + if (supportedModes & CCamera::EWBBeach) + return true; + else + return false; + + default: + return false; + } + } + + return false; +} + +/* + * ==================== + * S60 3.1 AutoFocosing + * ==================== + */ +bool S60ImageCaptureSession::isFocusSupported() const +{ + return m_cameraEngine->IsAutoFocusSupported(); +} + +void S60ImageCaptureSession::startFocus() +{ + if (m_cameraEngine) { + TRAPD(err, m_cameraEngine->StartFocusL()); + setError(err, tr("Failed to start focusing.")); + } + else + setError(KErrNotReady, tr("Unexpected camera error.")); +} + +void S60ImageCaptureSession::cancelFocus() +{ + if (m_cameraEngine) { + TRAPD(err, m_cameraEngine->FocusCancel()); + setError(err, tr("Failed to cancel focusing.")); + } + else + setError(KErrNotReady, tr("Unexpected camera error.")); +} + +void S60ImageCaptureSession::handleImageDecoded(int error) +{ + // Delete unneeded objects + if (m_imageDecoder) { + delete m_imageDecoder; + m_imageDecoder = 0; + } + if (m_fileSystemAccess) { + m_fileSystemAccess->Close(); + delete m_fileSystemAccess; + m_fileSystemAccess = 0; + } + + // Check status of decoding + if (error != KErrNone) { + if (m_previewBitmap) { + m_previewBitmap->Reset(); + delete m_previewBitmap; + m_previewBitmap = 0; + } + releaseImageBuffer(); + if (m_previewInWaitLoop) { + CActiveScheduler::Stop(); // Notify to continue execution of next Preview Image generation + m_previewInWaitLoop = false; // Reset + } + setError(error, tr("Preview creation failed.")); + return; + } + + m_previewDecodingOngoing = false; + + QPixmap prevPixmap = QPixmap::fromSymbianCFbsBitmap(m_previewBitmap); + QImage preview = prevPixmap.toImage(); + + if (m_previewBitmap) { + m_previewBitmap->Reset(); + delete m_previewBitmap; + m_previewBitmap = 0; + } + + QT_TRYCATCH_LEAVING( emit imageCaptured(m_currentImageId, preview) ); + + // Release image resources (if not already done) + releaseImageBuffer(); + + if (m_previewInWaitLoop) { + CActiveScheduler::Stop(); // Notify to continue execution of next Preview Image generation + m_previewInWaitLoop = false; // Reset + } +} + +void S60ImageCaptureSession::handleImageEncoded(int error) +{ + // Check status of encoding + if (error != KErrNone) { + releaseImageBuffer(); + if (m_previewInWaitLoop) { + CActiveScheduler::Stop(); // Notify to continue execution of next Preview Image generation + m_previewInWaitLoop = false; // Reset + } + setError(error, tr("Saving captured image to file failed.")); + return; + } else { + QT_TRYCATCH_LEAVING( emit imageSaved(m_currentImageId, m_stillCaptureFileName) ); + } + + if (m_imageEncoder) { + delete m_imageEncoder; + m_imageEncoder = 0; + } + +#ifndef ECAM_PREVIEW_API + // Start preview generation + TInt previewError = KErrNone; + TFileName fileName = convertImagePath(); + TRAP(previewError, m_imageDecoder = S60ImageCaptureDecoder::FileNewL(this, m_fileSystemAccess, &fileName)); + if (previewError) { + setError(previewError, tr("Failed to create preview image.")); + return; + } + + // Set proper Preview Size + TSize scaledSize((m_captureSize.width() / KSnapshotDownScaleFactor), (m_captureSize.height() / KSnapshotDownScaleFactor)); + if (scaledSize.iWidth < KSnapshotMinWidth || scaledSize.iHeight < KSnapshotMinHeight) + scaledSize.SetSize((m_captureSize.width() / (KSnapshotDownScaleFactor/2)), (m_captureSize.height() / (KSnapshotDownScaleFactor/2))); + if (scaledSize.iWidth < KSnapshotMinWidth || scaledSize.iHeight < KSnapshotMinHeight) + scaledSize.SetSize((m_captureSize.width() / (KSnapshotDownScaleFactor/4)), (m_captureSize.height() / (KSnapshotDownScaleFactor/4))); + if (scaledSize.iWidth < KSnapshotMinWidth || scaledSize.iHeight < KSnapshotMinHeight) + scaledSize.SetSize(m_captureSize.width(), m_captureSize.height()); + + TFrameInfo *info = m_imageDecoder->frameInfo(); + if (!info) { + setError(KErrGeneral, tr("Preview image creation failed.")); + return; + } + + m_previewBitmap = new CFbsBitmap; + if (!m_previewBitmap) { + setError(KErrNoMemory, tr("Failed to create preview image.")); + return; + } + previewError = m_previewBitmap->Create(scaledSize, info->iFrameDisplayMode); + if (previewError) { + setError(previewError, tr("Preview creation failed.")); + return; + } + + // Jpeg decoding completes in handleImageDecoded() + m_imageDecoder->decode(m_previewBitmap); +#endif // ECAM_PREVIEW_API + + // Buffer can be released since Preview is created from file + releaseImageBuffer(); + + // Inform that we can continue taking more pictures + QT_TRYCATCH_LEAVING( emit readyForCaptureChanged(true) ); +} + +#ifdef ECAM_PREVIEW_API +void S60ImageCaptureSession::MceoPreviewReady(CFbsBitmap& aPreview) +{ + QPixmap previewPixmap = QPixmap::fromSymbianCFbsBitmap(&aPreview); + QImage preview = previewPixmap.toImage(); + + // Notify preview availability + emit imageCaptured(m_currentImageId, preview); +} +#endif // ECAM_PREVIEW_API + +// End of file + diff --git a/src/plugins/symbian/ecam/s60imagecapturesession.h b/src/plugins/symbian/ecam/s60imagecapturesession.h new file mode 100644 index 000000000..9cae05fc9 --- /dev/null +++ b/src/plugins/symbian/ecam/s60imagecapturesession.h @@ -0,0 +1,359 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef S60IMAGECAPTURESESSION_H +#define S60IMAGECAPTURESESSION_H + +#include <QtCore/qurl.h> +#include <QtCore/qlist.h> +#include <QtCore/qmap.h> +#include <QtGui/qicon.h> + +#include <qcamera.h> +#include <qcamerafocus.h> +#include <qcameraimagecapture.h> +#include <qvideoframe.h> + +#include "s60camerasettings.h" +#include "s60cameraengine.h" +#include "s60cameraengineobserver.h" +#include "s60cameraconstants.h" // Default Jpeg Quality + +#include <icl/imagedata.h> // TFrameInfo + +QT_USE_NAMESPACE + +class S60CameraService; +class CImageDecoder; +class CImageEncoder; +class CFrameImageData; +class RFs; +class S60ImageCaptureSession; + +/* + * This class implements asynchronous image decoding service for the + * S60ImageCaptureSession. + */ +class S60ImageCaptureDecoder : public CActive +{ +public: // Static Contructor & Destructor + + static S60ImageCaptureDecoder* FileNewL(S60ImageCaptureSession *imageSession = 0, + RFs *fileSystemAccess = 0, + const TDesC16 *fileName = 0); + static S60ImageCaptureDecoder* DataNewL(S60ImageCaptureSession *imageSession = 0, + RFs *fileSystemAccess = 0, + const TDesC8 *data = 0); + ~S60ImageCaptureDecoder(); + +public: // Operations + + void decode(CFbsBitmap *destBitmap); + TFrameInfo *frameInfo(); + +protected: // CActive + + void RunL(); + void DoCancel(); + TInt RunError(TInt aError); + +protected: // Protected constructors + + S60ImageCaptureDecoder(S60ImageCaptureSession *imageSession, + RFs *fileSystemAccess, + const TDesC8 *data, + const TDesC16 *fileName); + void ConstructL(const bool fileInput = false); + +private: // Data + + S60ImageCaptureSession *m_imageSession; + CImageDecoder *m_imageDecoder; + RFs *m_fs; + const TDesC8 *m_jpegImageData; + const TDesC16 *m_jpegImageFile; + bool m_fileInput; + TFrameInfo m_frameInfo; + +}; + +//============================================================================= + +/* + * This class implements asynchronous image encoding service for the + * S60ImageCaptureSession. + */ +class S60ImageCaptureEncoder : public CActive +{ +public: // Static Contructor & Destructor + + static S60ImageCaptureEncoder* NewL(S60ImageCaptureSession *imageSession = 0, + RFs *fileSystemAccess = 0, + const TDesC16 *fileName = 0, + TInt jpegQuality = KDefaultImageQuality); + ~S60ImageCaptureEncoder(); + +public: // Operations + + void encode(CFbsBitmap *sourceBitmap); + +protected: // CActive + + void RunL(); + void DoCancel(); + TInt RunError(TInt aError); + +protected: // Protected constructors + + S60ImageCaptureEncoder(S60ImageCaptureSession *imageSession, + RFs *fileSystemAccess, + const TDesC16 *fileName, + TInt jpegQuality); + void ConstructL(); + +private: // Data + + S60ImageCaptureSession *m_imageSession; + CImageEncoder *m_imageEncoder; + RFs *m_fileSystemAccess; + const TDesC16 *m_fileName; + CFrameImageData *m_frameImageData; + TInt m_jpegQuality; + +}; + +//============================================================================= + +/* + * Session handling all image capture activities. + */ +class S60ImageCaptureSession : public QObject, +#ifdef ECAM_PREVIEW_API + public MCameraPreviewObserver, +#endif // ECAM_PREVIEW_API + public MCameraEngineImageCaptureObserver +{ + Q_OBJECT + +public: // Enums + + enum ImageCaptureState { + EImageCaptureNotPrepared = 0, // 0 - ImageCapture has not been prepared + EImageCapturePrepared, // 1 - ImageCapture has been prepared + EImageCaptureCapturing, // 2 - Image capture ongoing + EImageCaptureWritingImage // 3 - Image captured and image writing to file ongoing + }; + +public: // Constructor & Destructor + + S60ImageCaptureSession(QObject *parent = 0); + ~S60ImageCaptureSession(); + +public: // Methods + + void setError(const TInt error, const QString &description, const bool captureError = false); + int currentImageId() const; + + bool isDeviceReady(); + void setCameraHandle(CCameraEngine* camerahandle); + void setCurrentDevice(TInt deviceindex); + void notifySettingsSet(); + + // Ecam Advanced Settings + S60CameraSettings* advancedSettings(); + void deleteAdvancedSettings(); + + // Controls + int prepareImageCapture(); + void releaseImageCapture(); + int capture(const QString &fileName); + void cancelCapture(); + void releaseImageBuffer(); + + // Image Resolution + QSize captureSize() const; + QSize minimumCaptureSize(); + QSize maximumCaptureSize(); + QList<QSize> supportedCaptureSizesForCodec(const QString &codecName); + void setCaptureSize(const QSize &size); + + // Image Codec + QStringList supportedImageCaptureCodecs(); + QString imageCaptureCodec(); + void setImageCaptureCodec(const QString &codecName); + QString imageCaptureCodecDescription(const QString &codecName); + + // Image Quality + QtMultimediaKit::EncodingQuality captureQuality() const; + void setCaptureQuality(const QtMultimediaKit::EncodingQuality &quality); + + // S60 3.1 Focus Control (S60 3.2 and later via S60CameraSettings class) + bool isFocusSupported() const; + void startFocus(); + void cancelFocus(); + + // Zoom Control + qreal maximumZoom(); + qreal minZoom(); + qreal maxDigitalZoom(); + void doSetZoomFactorL(qreal optical, qreal digital); + qreal opticalZoomFactor(); + qreal digitalZoomFactor(); + + // Exposure Mode Control + QCameraExposure::ExposureMode exposureMode(); + void setExposureMode(QCameraExposure::ExposureMode mode); + bool isExposureModeSupported(QCameraExposure::ExposureMode mode) const; + + // Flash Mode Control + QCameraExposure::FlashMode flashMode(); + void setFlashMode(QCameraExposure::FlashModes mode); + QCameraExposure::FlashModes supportedFlashModes(); + + // Contrast Control + int contrast() const; + void setContrast(int value); + + // Brightness Control + int brightness() const; + void setBrightness(int value); + + // White Balance Mode Control + QCameraImageProcessing::WhiteBalanceMode whiteBalanceMode(); + void setWhiteBalanceMode(QCameraImageProcessing::WhiteBalanceMode mode); + bool isWhiteBalanceModeSupported(QCameraImageProcessing::WhiteBalanceMode mode) const; + +public: // Image Decoding & Encoding Notifications + + void handleImageDecoded(int error); + void handleImageEncoded(int error); + +protected: // MCameraEngineObserver + + void MceoFocusComplete(); + void MceoCapturedDataReady(TDesC8* aData); + void MceoCapturedBitmapReady(CFbsBitmap* aBitmap); + void MceoHandleError(TCameraEngineError aErrorType, TInt aError); + +#ifdef ECAM_PREVIEW_API +protected: // MCameraPreviewObserver + + void MceoPreviewReady(CFbsBitmap& aPreview); +#endif // ECAM_PREVIEW_API + +private: // Internal + + QCameraImageCapture::Error fromSymbianErrorToQtMultimediaError(int aError); + + void initializeImageCaptureSettings(); + void resetSession(bool errorHandling = false); + + CCamera::TFormat selectFormatForCodec(const QString &codec); + CCamera::TFormat defaultImageFormat(); + bool queryCurrentCameraInfo(); + QMap<QString, int> formatMap(); + QMap<QString, QString> codecDescriptionMap(); + void updateImageCaptureFormats(); + + void doSetWhiteBalanceModeL(QCameraImageProcessing::WhiteBalanceMode mode); + + void doSetFlashModeL(QCameraExposure::FlashModes mode); + void doSetExposureModeL(QCameraExposure::ExposureMode mode); + + void saveImageL(TDesC8 *aData, TFileName &aPath); + void processFileName(const QString &fileName); + TFileName convertImagePath(); + +signals: // Notifications + + void stateChanged(QCamera::State); + void advancedSettingChanged(); + void captureSizeChanged(const QSize&); + + // Error signals + void cameraError(int, const QString&); // For QCamera::error + void captureError(int, int, const QString&); // For QCameraImageCapture::error + + // Capture notifications + void readyForCaptureChanged(bool); + void imageExposed(int); + void imageCaptured(const int, const QImage&); + void imageSaved(const int, const QString&); + + // Focus notifications + void focusStatusChanged(QCamera::LockStatus, QCamera::LockChangeReason); + +private slots: // Internal Slots + + void cameraStatusChanged(QCamera::Status); + +private: // Data + + CCameraEngine *m_cameraEngine; + S60CameraSettings *m_advancedSettings; + mutable TCameraInfo *m_cameraInfo; + CFbsBitmap *m_previewBitmap; + CActiveScheduler *m_activeScheduler; + RFs *m_fileSystemAccess; + S60ImageCaptureDecoder *m_imageDecoder; + S60ImageCaptureEncoder *m_imageEncoder; + mutable int m_error; // Symbian ErrorCode + TInt m_activeDeviceIndex; + bool m_cameraStarted; + ImageCaptureState m_icState; + QStringList m_supportedImageCodecs; + QString m_currentCodec; + CCamera::TFormat m_currentFormat; + QSize m_captureSize; + int m_symbianImageQuality; + bool m_captureSettingsSet; + QString m_stillCaptureFileName; + QString m_requestedStillCaptureFileName; + mutable int m_currentImageId; + QList<uint> m_formats; + // This indicates that image capture should be triggered right after + // camera and image setting initialization has completed + bool m_captureWhenReady; + bool m_previewDecodingOngoing; + bool m_previewInWaitLoop; +}; + +#endif // S60IMAGECAPTURESESSION_H diff --git a/src/plugins/symbian/ecam/s60imageencodercontrol.cpp b/src/plugins/symbian/ecam/s60imageencodercontrol.cpp new file mode 100644 index 000000000..bfbf8d36b --- /dev/null +++ b/src/plugins/symbian/ecam/s60imageencodercontrol.cpp @@ -0,0 +1,128 @@ +/**************************************************************************** +** +** 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 "s60imageencodercontrol.h" +#include "s60imagecapturesession.h" + +S60ImageEncoderControl::S60ImageEncoderControl(QObject *parent) : + QImageEncoderControl(parent) +{ +} + +S60ImageEncoderControl::S60ImageEncoderControl(S60ImageCaptureSession *session, QObject *parent) : + QImageEncoderControl(parent) +{ + m_session = session; +} + +S60ImageEncoderControl::~S60ImageEncoderControl() +{ +} + +QList<QSize> S60ImageEncoderControl::supportedResolutions( + const QImageEncoderSettings &settings, bool *continuous) const +{ + QList<QSize> resolutions = m_session->supportedCaptureSizesForCodec(settings.codec()); + + // Discrete resolutions are returned + if (continuous) + *continuous = false; + + return resolutions; +} +QStringList S60ImageEncoderControl::supportedImageCodecs() const +{ + return m_session->supportedImageCaptureCodecs(); +} + +QString S60ImageEncoderControl::imageCodecDescription(const QString &codec) const +{ + return m_session->imageCaptureCodecDescription(codec); +} + +QImageEncoderSettings S60ImageEncoderControl::imageSettings() const +{ + // Update setting values from session + QImageEncoderSettings settings; + settings.setCodec(m_session->imageCaptureCodec()); + settings.setResolution(m_session->captureSize()); + settings.setQuality(m_session->captureQuality()); + + return settings; +} +void S60ImageEncoderControl::setImageSettings(const QImageEncoderSettings &settings) +{ + // Notify that settings have been implicitly set and there's no need to + // initialize them in case camera is changed + m_session->notifySettingsSet(); + + if (!settings.isNull()) { + if (!settings.codec().isEmpty()) { + if (settings.resolution() != QSize(-1,-1)) { // Codec, Resolution & Quality + m_session->setImageCaptureCodec(settings.codec()); + m_session->setCaptureSize(settings.resolution()); + m_session->setCaptureQuality(settings.quality()); + } else { // Codec and Quality + m_session->setImageCaptureCodec(settings.codec()); + m_session->setCaptureQuality(settings.quality()); + } + } else { + if (settings.resolution() != QSize(-1,-1)) { // Resolution & Quality + m_session->setCaptureSize(settings.resolution()); + m_session->setCaptureQuality(settings.quality()); + } + else // Only Quality + m_session->setCaptureQuality(settings.quality()); + } + + // Prepare ImageCapture with the settings and set error if needed + int prepareSuccess = m_session->prepareImageCapture(); + + // Preparation fails with KErrNotReady if camera has not been started. + // That can be ignored since settings are set internally in that case. + if (prepareSuccess != KErrNotReady && prepareSuccess != KErrNone) + m_session->setError(prepareSuccess, tr("Failure in preparation of image capture.")); + } +} + +// End of file diff --git a/src/plugins/symbian/ecam/s60imageencodercontrol.h b/src/plugins/symbian/ecam/s60imageencodercontrol.h new file mode 100644 index 000000000..99a308286 --- /dev/null +++ b/src/plugins/symbian/ecam/s60imageencodercontrol.h @@ -0,0 +1,84 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef S60IMAGEENCODERCONTROL_H +#define S60IMAGEENCODERCONTROL_H + +#include <QtCore/qobject.h> +#include "qimageencodercontrol.h" + +QT_USE_NAMESPACE + +class S60ImageCaptureSession; + +/* + * Control for setting encoding settings for the captured image. + */ +class S60ImageEncoderControl : public QImageEncoderControl +{ + Q_OBJECT + +public: // Contructors & Destructor + + S60ImageEncoderControl(QObject *parent = 0); + S60ImageEncoderControl(S60ImageCaptureSession *session, QObject *parent = 0); + ~S60ImageEncoderControl(); + +public: // QImageEncoderControl + + // Codec + QStringList supportedImageCodecs() const; + QString imageCodecDescription(const QString &codec) const; + + // Resolution + QList<QSize> supportedResolutions(const QImageEncoderSettings &settings, + bool *continuous = 0) const; + + // Settings + QImageEncoderSettings imageSettings() const; + void setImageSettings(const QImageEncoderSettings &settings); + +private: // Data + + S60ImageCaptureSession *m_session; +}; + +#endif // S60IMAGEENCODERCONTROL_H diff --git a/src/plugins/symbian/ecam/s60mediacontainercontrol.cpp b/src/plugins/symbian/ecam/s60mediacontainercontrol.cpp new file mode 100644 index 000000000..f0d20f4e3 --- /dev/null +++ b/src/plugins/symbian/ecam/s60mediacontainercontrol.cpp @@ -0,0 +1,97 @@ +/**************************************************************************** +** +** 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 "s60mediacontainercontrol.h" +#include "s60videocapturesession.h" +#include "s60cameraconstants.h" + +S60MediaContainerControl::S60MediaContainerControl(QObject *parent): + QMediaContainerControl(parent) +{ +} + +S60MediaContainerControl::S60MediaContainerControl(S60VideoCaptureSession *session, QObject *parent): + QMediaContainerControl(parent) +{ + m_session = session; + + // Set default video container + m_supportedContainers = m_session->supportedVideoContainers(); + + if (!m_supportedContainers.isEmpty()) { + // Check if default container is supported + if (m_supportedContainers.indexOf(KMimeTypeDefaultContainer) != -1) + setContainerMimeType(KMimeTypeDefaultContainer); + // Otherwise use first in the list + else + setContainerMimeType(m_supportedContainers[0]); // First as default + } else { + m_session->setError(KErrGeneral, tr("No supported video containers found.")); + } +} + +S60MediaContainerControl::~S60MediaContainerControl() +{ + m_supportedContainers.clear(); + m_containerDescriptions.clear(); +} + +QStringList S60MediaContainerControl::supportedContainers() const +{ + return m_session->supportedVideoContainers(); +} + +QString S60MediaContainerControl::containerMimeType() const +{ + return m_session->videoContainer(); +} + +void S60MediaContainerControl::setContainerMimeType(const QString &containerMimeType) +{ + m_session->setVideoContainer(containerMimeType); +} + +QString S60MediaContainerControl::containerDescription(const QString &containerMimeType) const +{ + return m_session->videoContainerDescription(containerMimeType); +} + +// End of file diff --git a/src/plugins/symbian/ecam/s60mediacontainercontrol.h b/src/plugins/symbian/ecam/s60mediacontainercontrol.h new file mode 100644 index 000000000..057b4bc43 --- /dev/null +++ b/src/plugins/symbian/ecam/s60mediacontainercontrol.h @@ -0,0 +1,82 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef S60MEDIACONTAINERCONTROL_H +#define S60MEDIACONTAINERCONTROL_H + +#include <QtCore/qstringlist.h> +#include <QtCore/qmap.h> +#include <qmediacontainercontrol.h> + +QT_USE_NAMESPACE + +class S60VideoCaptureSession; + +/* + * Control for setting container (file format) for video recorded using + * QMediaRecorder. + */ +class S60MediaContainerControl : public QMediaContainerControl +{ + Q_OBJECT + +public: // Contructors & Destructor + + S60MediaContainerControl(QObject *parent = 0); + S60MediaContainerControl(S60VideoCaptureSession *session, QObject *parent = 0); + virtual ~S60MediaContainerControl(); + +public: // QMediaContainerControl + + QStringList supportedContainers() const; + QString containerMimeType() const; + void setContainerMimeType(const QString &containerMimeType); + + QString containerDescription(const QString &containerMimeType) const; + +private: // Data + + S60VideoCaptureSession *m_session; + QStringList m_supportedContainers; + QMap<QString, QString> m_containerDescriptions; +}; + +#endif // S60MEDIACONTAINERCONTROL_H diff --git a/src/plugins/symbian/ecam/s60mediarecordercontrol.cpp b/src/plugins/symbian/ecam/s60mediarecordercontrol.cpp new file mode 100644 index 000000000..2a1394fa5 --- /dev/null +++ b/src/plugins/symbian/ecam/s60mediarecordercontrol.cpp @@ -0,0 +1,187 @@ +/**************************************************************************** +** +** 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 "s60cameraservice.h" +#include "s60mediarecordercontrol.h" +#include "s60cameracontrol.h" +#include "s60videocapturesession.h" + +S60MediaRecorderControl::S60MediaRecorderControl(QObject *parent) : + QMediaRecorderControl(parent) +{ +} + +S60MediaRecorderControl::S60MediaRecorderControl(S60CameraService *service, + S60VideoCaptureSession *session, + QObject *parent): + QMediaRecorderControl(parent), + m_state(QMediaRecorder::StoppedState) // Default RecorderState +{ + m_session = session; + m_service = service; + m_cameraControl = qobject_cast<S60CameraControl *>(m_service->requestControl(QCameraControl_iid)); + + // Connect signals + connect(m_session, SIGNAL(stateChanged(S60VideoCaptureSession::TVideoCaptureState)), + this, SLOT(updateState(S60VideoCaptureSession::TVideoCaptureState))); + connect(m_session, SIGNAL(positionChanged(qint64)), this, SIGNAL(durationChanged(qint64))); + connect(m_session, SIGNAL(mutedChanged(bool)), this, SIGNAL(mutedChanged(bool))); + connect(m_session, SIGNAL(error(int,const QString &)), this, SIGNAL(error(int,const QString &))); +} + +S60MediaRecorderControl::~S60MediaRecorderControl() +{ + // Release requested control + if (m_cameraControl) + m_service->releaseControl(m_cameraControl); +} + +QUrl S60MediaRecorderControl::outputLocation() const +{ + return m_session->outputLocation(); +} + +bool S60MediaRecorderControl::setOutputLocation(const QUrl& sink) +{ + // Output location can only be set in StoppedState + if (m_state == QMediaRecorder::StoppedState) + return m_session->setOutputLocation(sink); + + // Do not signal error, but notify that setting was not effective + return false; +} + +QMediaRecorder::State S60MediaRecorderControl::convertInternalStateToQtState(S60VideoCaptureSession::TVideoCaptureState aState) const +{ + QMediaRecorder::State state; + + switch (aState) { + case S60VideoCaptureSession::ERecording: + state = QMediaRecorder::RecordingState; + break; + case S60VideoCaptureSession::EPaused: + state = QMediaRecorder::PausedState; + break; + + default: + // All others + state = QMediaRecorder::StoppedState; + break; + } + + return state; +} + +void S60MediaRecorderControl::updateState(S60VideoCaptureSession::TVideoCaptureState state) +{ + QMediaRecorder::State newState = convertInternalStateToQtState(state); + + if (m_state != newState) { + m_state = newState; + emit stateChanged(m_state); + } +} + +QMediaRecorder::State S60MediaRecorderControl::state() const +{ + return m_state; +} + +qint64 S60MediaRecorderControl::duration() const +{ + return m_session->position(); +} + +/* +This method is called after encoder configuration is done. +Encoder can load necessary resources at this point, +to reduce delay before recording is started. Calling this method reduces the +latency when calling record() to start video recording. +*/ +void S60MediaRecorderControl::applySettings() +{ + m_session->applyAllSettings(); +} + +void S60MediaRecorderControl::record() +{ + if (m_state == QMediaRecorder::RecordingState) + return; + + if (m_cameraControl && m_cameraControl->captureMode() != QCamera::CaptureVideo) { + emit error(QCamera::CameraError, tr("Video capture mode is not selected.")); + return; + } + + m_session->startRecording(); +} + +void S60MediaRecorderControl::pause() +{ + if (m_state != QMediaRecorder::RecordingState) { + // Discard + return; + } + + m_session->pauseRecording(); +} + +void S60MediaRecorderControl::stop() +{ + if (m_state == QMediaRecorder::StoppedState) { + // Ignore + return; + } + + m_session->stopRecording(); +} + +bool S60MediaRecorderControl::isMuted() const +{ + return m_session->isMuted(); +} + +void S60MediaRecorderControl::setMuted(bool muted) +{ + m_session->setMuted(muted); +} + +// End of file diff --git a/src/plugins/symbian/ecam/s60mediarecordercontrol.h b/src/plugins/symbian/ecam/s60mediarecordercontrol.h new file mode 100644 index 000000000..5db7477bd --- /dev/null +++ b/src/plugins/symbian/ecam/s60mediarecordercontrol.h @@ -0,0 +1,118 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef S60MEDIARECORDERCONTROL_H +#define S60MEDIARECORDERCONTROL_H + +#include <QtCore/qurl.h> +#include <qmediarecorder.h> +#include <qmediarecordercontrol.h> + +#include "s60videocapturesession.h" + +QT_USE_NAMESPACE + +class S60VideoCaptureSession; +class S60CameraService; +class S60CameraControl; + +/* + * Control for video recording operations. + */ +class S60MediaRecorderControl : public QMediaRecorderControl +{ + Q_OBJECT + +public: // Contructors & Destructor + + S60MediaRecorderControl(QObject *parent = 0); + S60MediaRecorderControl(S60CameraService *service, + S60VideoCaptureSession *session, + QObject *parent = 0); + ~S60MediaRecorderControl(); + +public: // QMediaRecorderControl + + QUrl outputLocation() const; + bool setOutputLocation(const QUrl &sink); + + QMediaRecorder::State state() const; + + qint64 duration() const; + + bool isMuted() const; + + void applySettings(); + +/* +Q_SIGNALS: // QMediaRecorderControl + void stateChanged(QMediaRecorder::State state); + void durationChanged(qint64 position); + void mutedChanged(bool muted); + void error(int error, const QString &errorString); +*/ + +public slots: // QMediaRecorderControl + + void record(); + void pause(); + void stop(); + void setMuted(bool); + +private: + + QMediaRecorder::State convertInternalStateToQtState( + S60VideoCaptureSession::TVideoCaptureState aState) const; + +private slots: + + void updateState(S60VideoCaptureSession::TVideoCaptureState state); + +private: // Data + + S60VideoCaptureSession *m_session; + S60CameraService *m_service; + S60CameraControl *m_cameraControl; + QMediaRecorder::State m_state; + +}; + +#endif // S60MEDIARECORDERCONTROL_H 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 diff --git a/src/plugins/symbian/ecam/s60videocapturesession.h b/src/plugins/symbian/ecam/s60videocapturesession.h new file mode 100644 index 000000000..cfa101f57 --- /dev/null +++ b/src/plugins/symbian/ecam/s60videocapturesession.h @@ -0,0 +1,414 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef S60VIDEOCAPTURESESSION_H +#define S60VIDEOCAPTURESESSION_H + +#include <QtCore/qurl.h> +#include <QtCore/qhash.h> + +#include <qmediaencodersettings.h> +#include <qcamera.h> +#include <qmediarecorder.h> + +#include "s60cameraengine.h" + +#include <e32base.h> +#include <videorecorder.h> // CVideoRecorderUtility +#ifdef S60_DEVVIDEO_RECORDING_SUPPORTED +#include <mmf/devvideo/devvideorecord.h> +#endif // S60_DEVVIDEO_RECORDING_SUPPORTED + +QT_USE_NAMESPACE + +class QTimer; + +/* + * VideoSession is the main class handling all video recording related + * operations. It uses mainly CVideoRecorderUtility to do it's tasks, but if + * DevVideoRecord is available it is used to provide more detailed + * information of the supported video settings. + */ +class S60VideoCaptureSession : public QObject, + public MVideoRecorderUtilityObserver +#ifdef S60_DEVVIDEO_RECORDING_SUPPORTED + ,public MMMFDevVideoRecordObserver +#endif // S60_DEVVIDEO_RECORDING_SUPPORTED +{ + Q_OBJECT + Q_ENUMS(Error) + Q_ENUMS(EcamErrors) + Q_ENUMS(TVideoCaptureState) + +public: // Enums + + enum TVideoCaptureState + { + ENotInitialized = 0, // 0 - VideoRecording is not initialized, instance may or may not be created + EInitializing, // 1 - Initialization is ongoing + EInitialized, // 2 - VideoRecording is initialized, OpenFile is called with dummy file + EOpening, // 3 - OpenFile called with actual output location, waiting completion + EOpenComplete, // 4 - OpenFile completed with the actual output location + EPreparing, // 5 - Preparing VideoRecording to use set video settings + EPrepared, // 6 - VideoRecording is prepared with the set settings, ready to record + ERecording, // 7 - Video recording is ongoing + EPaused // 8 - Video recording has been started and paused + }; + + enum AudioQualityDefinition + { + ENoAudioQuality = 0, // 0 - Both BitRate and SampleRate settings available + EOnlyAudioQuality, // 1 - No BitRate or SampleRate settings available, use Quality to set them + EAudioQualityAndBitRate, // 2 - BitRate setting available, use Quality to set SampleRate + EAudioQualityAndSampleRate, // 3 - SampleRate setting available, use Quality to set BitRate + }; + + enum VideoQualityDefinition + { + ENoVideoQuality = 0, // 0 - All, Resolution, FrameRate and BitRate available + EOnlyVideoQuality, // 1 - None available, use Quality to set Resolution, FrameRate and BitRate + EVideoQualityAndResolution, // 2 - Only Resolution available, use Quality to set FrameRate and BitRate + EVideoQualityAndFrameRate, // 3 - Only FrameRate available, use Quality to set Resolution and BitRate + EVideoQualityAndBitRate, // 4 - Only BitRate available, use Quality to set Resolution and FrameRate + EVideoQualityAndResolutionAndBitRate, // 5 - No FrameRate available, use Quality to set it + EVideoQualityAndResolutionAndFrameRate, // 6 - No BitRate available, use Quality to set it + EVideoQualityAndFrameRateAndBitRate // 7 - No Resolution available, use Quality to set it + }; + +public: // Constructor & Destructor + + S60VideoCaptureSession(QObject *parent = 0); + ~S60VideoCaptureSession(); + +public: // MVideoRecorderUtilityObserver + + void MvruoOpenComplete(TInt aError); + void MvruoPrepareComplete(TInt aError); + void MvruoRecordComplete(TInt aError); + void MvruoEvent(const TMMFEvent& aEvent); + +#ifdef S60_DEVVIDEO_RECORDING_SUPPORTED +public: // MMMFDevVideoRecordObserver + void MdvroReturnPicture(TVideoPicture *aPicture); + void MdvroSupplementalInfoSent(); + void MdvroNewBuffers(); + void MdvroFatalError(TInt aError); + void MdvroInitializeComplete(TInt aError); + void MdvroStreamEnd(); +#endif // S60_DEVVIDEO_RECORDING_SUPPORTED + +public: // Methods + + void setError(const TInt error, const QString &description); + void setCameraHandle(CCameraEngine* cameraHandle); + void notifySettingsSet(); + + qint64 position(); + TVideoCaptureState state() const; + bool isMuted() const; + + // Controls + int initializeVideoRecording(); + void releaseVideoRecording(); + void applyAllSettings(); + + void startRecording(); + void pauseRecording(); + void stopRecording(const bool reInitialize = true); + void setMuted(const bool muted); + + // Output Location + bool setOutputLocation(const QUrl &sink); + QUrl outputLocation() const; + + // Resolution + void setVideoResolution(const QSize &resolution); + QList<QSize> supportedVideoResolutions(bool *continuous); + QList<QSize> supportedVideoResolutions(const QVideoEncoderSettings &settings, bool *continuous); + + // Framerate + void setFrameRate(const qreal rate); + QList<qreal> supportedVideoFrameRates(bool *continuous); + QList<qreal> supportedVideoFrameRates(const QVideoEncoderSettings &settings, bool *continuous); + + // Other Video Settings + void setBitrate(const int bitrate); + void setVideoEncodingMode(const QtMultimediaKit::EncodingMode mode); + + // Video Codecs + void setVideoCaptureCodec(const QString &codecName); + QStringList supportedVideoCaptureCodecs(); + QString videoCaptureCodecDescription(const QString &codecName); + + // Audio Codecs + void setAudioCaptureCodec(const QString &codecName); + QStringList supportedAudioCaptureCodecs(); + + // Encoder Settings + void videoEncoderSettings(QVideoEncoderSettings &videoSettings); + void audioEncoderSettings(QAudioEncoderSettings &audioSettings); + + // Quality + void setVideoCaptureQuality(const QtMultimediaKit::EncodingQuality quality, + const VideoQualityDefinition mode); + void setAudioCaptureQuality(const QtMultimediaKit::EncodingQuality quality, + const AudioQualityDefinition mode); + + // Video Containers + QString videoContainer() const; + void setVideoContainer(const QString &containerName); + QStringList supportedVideoContainers(); + bool isSupportedVideoContainer(const QString &containerName); + QString videoContainerDescription(const QString &containerName); + + // Audio Settings + QList<int> supportedSampleRates(const QAudioEncoderSettings &settings, bool *continuous); + void setAudioSampleRate(const int sampleRate); + void setAudioBitRate(const int bitRate); + void setAudioChannelCount(const int channelCount); + void setAudioEncodingMode(const QtMultimediaKit::EncodingMode mode); + + // Video Options + QSize pixelAspectRatio(); + void setPixelAspectRatio(const QSize par); + int gain(); + void setGain(const int gain); + int maxClipSizeInBytes() const; + void setMaxClipSizeInBytes(const int size); + +private: // Internal + + QMediaRecorder::Error fromSymbianErrorToQtMultimediaError(int aError); + + void initializeVideoCaptureSettings(); + void doInitializeVideoRecorderL(); + void commitVideoEncoderSettings(); + void queryAudioEncoderSettings(); + void queryVideoEncoderSettings(); + void validateRequestedCodecs(); + void resetSession(bool errorHandling = false); + + void doSetCodecsL(); + QString determineProfileAndLevel(); + void doSetVideoResolution(const QSize &resolution); + void doSetFrameRate(qreal rate); + void doSetBitrate(const int &bitrate); + + void updateVideoCaptureContainers(); + void doUpdateVideoCaptureContainersL(); + void selectController(const QString &format, + TUid &controllerUid, + TUid &formatUid); + + void doPopulateVideoCodecsDataL(); + void doPopulateVideoCodecsL(); +#ifndef S60_DEVVIDEO_RECORDING_SUPPORTED + void doPopulateMaxVideoParameters(); +#endif // S60_DEVVIDEO_RECORDING_SUPPORTED + void doPopulateAudioCodecsL(); + + QList<int> doGetSupportedSampleRatesL(const QAudioEncoderSettings &settings, + bool *continuous); + QSize maximumResolutionForMimeType(const QString &mimeType) const; + qreal maximumFrameRateForMimeType(const QString &mimeType) const; + int maximumBitRateForMimeType(const QString &mimeType) const; + +signals: // Notification Signals + + void stateChanged(S60VideoCaptureSession::TVideoCaptureState); + void positionChanged(qint64); + void mutedChanged(bool); + void captureSizeChanged(const QSize&); + void error(int, const QString&); + +private slots: // Internal Slots + + void cameraStatusChanged(QCamera::Status); + void durationTimerTriggered(); + +private: // Structs + + /* + * This structure holds the information of supported video mime types for + * the format and also description for it. + */ + struct VideoFormatData { + QString description; + QStringList supportedMimeTypes; + }; + + /* + * This structure is used to define supported resolutions and framerate + * (depending on each other) for each supported encoder mime type (defining + * encoder, profile and level) + */ + struct SupportedFrameRatePictureSize { + SupportedFrameRatePictureSize() {} + SupportedFrameRatePictureSize(qreal rate, QSize size): + frameRate(rate), + frameSize(size) {} + qreal frameRate; + QSize frameSize; + }; + + /* + * This structure defines supported resolution/framerate pairs and maximum + * bitrate for a single encodec device. It also the supported mime types + * (codec, profile and level) of the encoder device. + * + * Structure defines 2 contructors: + * - First with no attributes + * - Second, which will construct the sructure appending one + * resolution/framerate pair to the list of + * SupportedFrameRatePictureSizes and setting the given bitrate as + * maximum. This second constructor is for convenience. + * + * This struct is used in m_videoParametersForEncoder (QList). + * + * Here's a visualization of an example strcuture: + * STRUCT: + * |-- Resolution/FrameRate Pairs: + * | |- VGA / 30fps + * | |- 720p / 25fps + * | |- Etc. + * | + * |-- MimeTypes: + * | |- video/mp4v-es; profile-level-id=1 + * | |- video/mp4v-es; profile-level-id=2 + * | |- Etc. + * | + * |-- Max BitRate: 1Mbps + */ + struct MaxResolutionRatesAndTypes { + MaxResolutionRatesAndTypes() {} + MaxResolutionRatesAndTypes(QSize size, qreal fRate, int bRate): + bitRate(bRate) + { + frameRatePictureSizePair.append(SupportedFrameRatePictureSize(fRate,size)); + } + QList<SupportedFrameRatePictureSize> frameRatePictureSizePair; + QStringList mimeTypes; + int bitRate; + }; + +private: // Data + + CCameraEngine *m_cameraEngine; + CVideoRecorderUtility *m_videoRecorder; + QTimer *m_durationTimer; + qint64 m_position; + // Symbian ErrorCode + mutable int m_error; + // This defines whether Camera is in ActiveStatus or not + bool m_cameraStarted; + // Internal state of the video recorder + TVideoCaptureState m_captureState; + // Actual output file name/path + QUrl m_sink; + // Requested output file name/path, this may be different from m_sink if + // asynchronous operation was ongoing in the CVideoRecorderUtility when new + // outputLocation was set. + QUrl m_requestedSink; + // Requested videoSettings. The may not be active settings before those are + // committed (with commitVideoEncoderSettings()) + QVideoEncoderSettings m_videoSettings; + // Requested audioSettings. The may not be active settings before those are + // committed (with commitVideoEncoderSettings()) + QAudioEncoderSettings m_audioSettings; + // Tells whether settings should be initialized when changing the camera + bool m_captureSettingsSet; + // Active container + QString m_container; + // Requested container, this may be different from m_container if + // asynchronous operation was ongoing in the CVideoRecorderUtility when new + // container was set. + QString m_requestedContainer; + // Requested muted value. This may not be active value before settings are + // committed (with commitVideoEncoderSettings()) + bool m_muted; + // Maximum ClipSize in Bytes + int m_maxClipSize; + // List of supported video codec mime types + QStringList m_videoCodecList; + // Hash of supported video codec mime types and corresponding FourCC codes + QHash<QString, TFourCC> m_audioCodecList; + // Map of video capture controllers information. It is populated during + // doUpdateVideoCaptureContainersL(). + // + // Here's a visualization of an example strcuture: + // m_videoControllerMap(HASH): + // | + // |-- Controller 1 : HASH + // | |- Container 1 (UID) : FormatData + // | | |- Description + // | | |- List of supported MimeTypes + // | |- Container 2 (UID) : FormatData + // | | |- Description + // | | |- List of supported MimeTypes + // | |- Etc. + // | + // |-- Controller 2: HASH + // | |- Container 1 (UID) : FormatData + // | | |- Description + // | | |- List of supported MimeTypes + // | |- Etc. + // + QHash<TInt, QHash<TInt,VideoFormatData> > m_videoControllerMap; + // List of Encoder information. If DevVideoRecord is available info is + // gathered during doPopulateVideoCodecsDataL() for each encoder (hw + // accelerated and supporting camera input) found. If DevVideoRecord is not + // available, the info is set in doPopulateMaxVideoParameters() based on + // supported codec list received from CVideoRecorderUtility. + QList<MaxResolutionRatesAndTypes> m_videoParametersForEncoder; + // Set if OpenFileL should be executed when currently ongoing operation + // is completed. + bool m_openWhenReady; + // Set if video capture should be prepared after OpenFileL has completed + bool m_prepareAfterOpenComplete; + // Set if video capture should be started when Prepare has completed + bool m_startAfterPrepareComplete; + // Tells if settings have been set after last Prepare() + bool m_uncommittedSettings; + // Tells if settings need to be applied after ongoing operation has finished + bool m_commitSettingsWhenReady; +}; + +#endif // S60VIDEOCAPTURESESSION_H diff --git a/src/plugins/symbian/ecam/s60videodevicecontrol.cpp b/src/plugins/symbian/ecam/s60videodevicecontrol.cpp new file mode 100644 index 000000000..3d55d3110 --- /dev/null +++ b/src/plugins/symbian/ecam/s60videodevicecontrol.cpp @@ -0,0 +1,108 @@ +/**************************************************************************** +** +** 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 <QtGui/qicon.h> + +#include "s60videodevicecontrol.h" +#include "s60cameracontrol.h" +#include "s60cameraconstants.h" + +S60VideoDeviceControl::S60VideoDeviceControl(QObject *parent) : + QVideoDeviceControl(parent) +{ +} + +S60VideoDeviceControl::S60VideoDeviceControl(S60CameraControl *control, QObject *parent) : + QVideoDeviceControl(parent), + m_selectedDevice(KDefaultCameraDevice) +{ + m_control = control; + connect(m_control, SIGNAL(devicesChanged()), this, SIGNAL(devicesChanged())); +} + +S60VideoDeviceControl::~S60VideoDeviceControl() +{ +} + +int S60VideoDeviceControl::deviceCount() const +{ + return S60CameraControl::deviceCount(); +} + +QString S60VideoDeviceControl::deviceName(int index) const +{ + return S60CameraControl::name(index); +} + +QString S60VideoDeviceControl::deviceDescription(int index) const +{ + return S60CameraControl::description(index); +} + +QIcon S60VideoDeviceControl::deviceIcon(int index) const +{ + Q_UNUSED(index); + return QIcon(); +} + +int S60VideoDeviceControl::defaultDevice() const +{ + return KDefaultCameraDevice; +} + +int S60VideoDeviceControl::selectedDevice() const +{ + return m_selectedDevice; +} + +void S60VideoDeviceControl::setSelectedDevice(int index) +{ + // Inform that we selected new device + if (m_selectedDevice != index) { + m_control->setSelectedDevice(index); + m_selectedDevice = index; + emit selectedDeviceChanged(m_selectedDevice); + emit selectedDeviceChanged(deviceName(m_selectedDevice)); + } +} + +// End of file diff --git a/src/plugins/symbian/ecam/s60videodevicecontrol.h b/src/plugins/symbian/ecam/s60videodevicecontrol.h new file mode 100644 index 000000000..03249441a --- /dev/null +++ b/src/plugins/symbian/ecam/s60videodevicecontrol.h @@ -0,0 +1,95 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef S60VIDEODEVICECONTROL_H +#define S60VIDEODEVICECONTROL_H + +#include "qvideodevicecontrol.h" + +QT_USE_NAMESPACE + +class S60CameraControl; +class QString; +class QIcon; + +/* + * Control for providing information of the video device (r. camera) and to + * enable other camera device (e.g. secondary camera if one exists). + */ +class S60VideoDeviceControl : public QVideoDeviceControl +{ + Q_OBJECT + +public: // Constructors & Destructor + + S60VideoDeviceControl(QObject *parent); + S60VideoDeviceControl(S60CameraControl *control, QObject *parent = 0); + virtual ~S60VideoDeviceControl(); + +public: // QVideoDeviceControl + + int deviceCount() const; + + QString deviceName(int index) const; + QString deviceDescription(int index) const; + QIcon deviceIcon(int index) const; + + int defaultDevice() const; + int selectedDevice() const; + +public slots: // QVideoDeviceControl + + void setSelectedDevice(int index); + +/* +Q_SIGNALS: +void selectedDeviceChanged(int index); +void selectedDeviceChanged(const QString &deviceName); +void devicesChanged(); +*/ + +private: // Data + + S60CameraControl *m_control; + int m_selectedDevice; +}; + +#endif // S60VIDEODEVICECONTROL_H diff --git a/src/plugins/symbian/ecam/s60videoencodercontrol.cpp b/src/plugins/symbian/ecam/s60videoencodercontrol.cpp new file mode 100644 index 000000000..34b28e28e --- /dev/null +++ b/src/plugins/symbian/ecam/s60videoencodercontrol.cpp @@ -0,0 +1,204 @@ +/**************************************************************************** +** +** 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 "s60videoencodercontrol.h" +#include "s60videocapturesession.h" + +S60VideoEncoderControl::S60VideoEncoderControl(QObject *parent) : + QVideoEncoderControl(parent) +{ +} + +S60VideoEncoderControl::S60VideoEncoderControl(S60VideoCaptureSession *session, QObject *parent) : + QVideoEncoderControl(parent) +{ + m_session = session; +} + +S60VideoEncoderControl::~S60VideoEncoderControl() +{ +} + +QStringList S60VideoEncoderControl::supportedVideoCodecs() const +{ + return m_session->supportedVideoCaptureCodecs(); +} + +QString S60VideoEncoderControl::videoCodecDescription(const QString &codecName) const +{ + return m_session->videoCaptureCodecDescription(codecName); +} + +QList<qreal> S60VideoEncoderControl::supportedFrameRates(const QVideoEncoderSettings &settings, bool *continuous) const +{ + if (!settings.isNull()) + return m_session->supportedVideoFrameRates(settings, continuous); + return m_session->supportedVideoFrameRates(continuous); +} + +QList<QSize> S60VideoEncoderControl::supportedResolutions(const QVideoEncoderSettings &settings, bool *continuous) const +{ + if (!settings.isNull()) + return m_session->supportedVideoResolutions(settings, continuous); + return m_session->supportedVideoResolutions(continuous); +} + +QStringList S60VideoEncoderControl::supportedEncodingOptions(const QString &codec) const +{ + // Possible settings: EncodingMode, Codec, Resolution, FrameRate, BitRate, Quality + // Possible (codec specific) options: PixelAspectRatio, Gain, MaxClipSizeInBytes + + // Following options are valid for all codecs + Q_UNUSED(codec); + + QStringList options; + options.append("pixelAspectRatio"); + options.append("gain"); + options.append("maxClipSizeInBytes"); + + return options; +} + +QVariant S60VideoEncoderControl::encodingOption(const QString &codec, const QString &name) const +{ + Q_UNUSED(codec); + + // Possible settings: EncodingMode, Codec, Resolution, FrameRate, BitRate, Quality + // Possible (codec specific) options: PixelAspectRatio, Gain, MaxClipSizeInBytes + + QVariant returnValue; + + if (qstrcmp(name.toLocal8Bit().constData(), "pixelAspectRatio") == 0) + returnValue.setValue(m_session->pixelAspectRatio()); + else if (qstrcmp(name.toLocal8Bit().constData(), "gain") == 0) + returnValue.setValue((int)m_session->gain()); + else if (qstrcmp(name.toLocal8Bit().constData(), "maxClipSizeInBytes") == 0) + returnValue.setValue(m_session->maxClipSizeInBytes()); + + return returnValue; +} + +void S60VideoEncoderControl::setEncodingOption( + const QString &codec, const QString &name, const QVariant &value) +{ + // Set the codec first if not already set + m_session->setVideoCaptureCodec(codec); + + if (qstrcmp(name.toLocal8Bit().constData(), "pixelAspectRatio") == 0) + m_session->setPixelAspectRatio(value.toSize()); + else if (qstrcmp(name.toLocal8Bit().constData(), "gain") == 0) + m_session->setGain(value.toInt()); + else if (qstrcmp(name.toLocal8Bit().constData(), "maxClipSizeInBytes") == 0) + m_session->setMaxClipSizeInBytes(value.toInt()); + else + m_session->setError(KErrNotSupported, tr("Requested encoding option is not supported")); +} + +QVideoEncoderSettings S60VideoEncoderControl::videoSettings() const +{ + QVideoEncoderSettings settings; + m_session->videoEncoderSettings(settings); + + return settings; +} + +void S60VideoEncoderControl::setVideoSettings(const QVideoEncoderSettings &settings) +{ + // Notify that settings have been implicitly set and there's no need to + // initialize them in case camera is changed + m_session->notifySettingsSet(); + + if (settings.codec().isEmpty() + || (settings.resolution() == QSize(-1,-1) && settings.frameRate() == 0 && settings.bitRate() == -1)) { + if (!settings.codec().isEmpty()) + m_session->setVideoCaptureCodec(settings.codec()); + m_session->setVideoEncodingMode(settings.encodingMode()); + m_session->setVideoCaptureQuality(settings.quality(), S60VideoCaptureSession::EOnlyVideoQuality); + } else if (settings.resolution() != QSize(-1,-1) && settings.frameRate() == 0 && settings.bitRate() == -1) { // Only Resolution + m_session->setVideoCaptureCodec(settings.codec()); + m_session->setVideoEncodingMode(settings.encodingMode()); + m_session->setVideoResolution(settings.resolution()); + m_session->setVideoCaptureQuality(settings.quality(), S60VideoCaptureSession::EVideoQualityAndResolution); + + } else if (settings.resolution() == QSize(-1,-1) && settings.frameRate() != 0 && settings.bitRate() == -1) { // Only Framerate + m_session->setVideoCaptureCodec(settings.codec()); + m_session->setVideoEncodingMode(settings.encodingMode()); + m_session->setFrameRate(settings.frameRate()); + m_session->setVideoCaptureQuality(settings.quality(), S60VideoCaptureSession::EVideoQualityAndFrameRate); + + } else if (settings.resolution() == QSize(-1,-1) && settings.frameRate() == 0 && settings.bitRate() != -1) { // Only BitRate + m_session->setVideoCaptureCodec(settings.codec()); + m_session->setVideoEncodingMode(settings.encodingMode()); + m_session->setBitrate(settings.bitRate()); + m_session->setVideoCaptureQuality(settings.quality(), S60VideoCaptureSession::EVideoQualityAndBitRate); + + } else if (settings.resolution() != QSize(-1,-1) && settings.frameRate() != 0 && settings.bitRate() == -1) { // Resolution and FrameRate + m_session->setVideoCaptureCodec(settings.codec()); + m_session->setVideoEncodingMode(settings.encodingMode()); + m_session->setVideoResolution(settings.resolution()); + m_session->setFrameRate(settings.frameRate()); + m_session->setVideoCaptureQuality(settings.quality(), S60VideoCaptureSession::EVideoQualityAndResolutionAndFrameRate); + + } else if (settings.resolution() != QSize(-1,-1) && settings.frameRate() == 0 && settings.bitRate() != -1) { // Resolution and BitRate + m_session->setVideoCaptureCodec(settings.codec()); + m_session->setVideoEncodingMode(settings.encodingMode()); + m_session->setVideoResolution(settings.resolution()); + m_session->setBitrate(settings.bitRate()); + m_session->setVideoCaptureQuality(settings.quality(), S60VideoCaptureSession::EVideoQualityAndResolutionAndBitRate); + + } else if (settings.resolution() == QSize(-1,-1) && settings.frameRate() != 0 && settings.bitRate() != -1) { // FrameRate and BitRate + m_session->setVideoCaptureCodec(settings.codec()); + m_session->setVideoEncodingMode(settings.encodingMode()); + m_session->setFrameRate(settings.frameRate()); + m_session->setBitrate(settings.bitRate()); + m_session->setVideoCaptureQuality(settings.quality(), S60VideoCaptureSession::EVideoQualityAndFrameRateAndBitRate); + + } else { // All: Resolution, BitRate and FrameRate + m_session->setVideoCaptureCodec(settings.codec()); + m_session->setVideoEncodingMode(settings.encodingMode()); + m_session->setVideoResolution(settings.resolution()); + m_session->setFrameRate(settings.frameRate()); + m_session->setBitrate(settings.bitRate()); + m_session->setVideoCaptureQuality(settings.quality(), S60VideoCaptureSession::ENoVideoQuality); + } +} + +// End of file diff --git a/src/plugins/symbian/ecam/s60videoencodercontrol.h b/src/plugins/symbian/ecam/s60videoencodercontrol.h new file mode 100644 index 000000000..4554d9291 --- /dev/null +++ b/src/plugins/symbian/ecam/s60videoencodercontrol.h @@ -0,0 +1,94 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef S60VIDEOENCODERCONTROL_H +#define S60VIDEOENCODERCONTROL_H + +#include <QtCore/qstringlist.h> +#include <QtCore/qmap.h> + +#include "qvideoencodercontrol.h" + +QT_USE_NAMESPACE + +class S60VideoCaptureSession; + +/* + * Control for video settings when recording video using QMediaRecorder. + */ +class S60VideoEncoderControl : public QVideoEncoderControl +{ + Q_OBJECT + +public: // Contructors & Destructor + + S60VideoEncoderControl(QObject *parent = 0); + S60VideoEncoderControl(S60VideoCaptureSession *session, QObject *parent = 0); + virtual ~S60VideoEncoderControl(); + +public: // QVideoEncoderControl + + // Resolution + QList<QSize> supportedResolutions(const QVideoEncoderSettings &settings, bool *continuous = 0) const; + + // Framerate + QList<qreal> supportedFrameRates(const QVideoEncoderSettings &settings, bool *continuous = 0) const; + + // Video Codec + QStringList supportedVideoCodecs() const; + QString videoCodecDescription(const QString &codecName) const; + + // Video Settings + QVideoEncoderSettings videoSettings() const; + void setVideoSettings(const QVideoEncoderSettings &settings); + + // Encoding Options + QStringList supportedEncodingOptions(const QString &codec) const; + QVariant encodingOption(const QString &codec, const QString &name) const; + void setEncodingOption(const QString &codec, const QString &name, const QVariant &value); + +private: // Data + + S60VideoCaptureSession* m_session; + +}; + +#endif // S60VIDEOENCODERCONTROL_H diff --git a/src/plugins/symbian/ecam/s60videorenderercontrol.cpp b/src/plugins/symbian/ecam/s60videorenderercontrol.cpp new file mode 100644 index 000000000..8cc3546b5 --- /dev/null +++ b/src/plugins/symbian/ecam/s60videorenderercontrol.cpp @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** 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 <qabstractvideosurface.h> + +#include "s60videorenderercontrol.h" + +S60VideoRendererControl::S60VideoRendererControl(QObject *parent) : + QVideoRendererControl(parent), + m_surface(0) +{ +} + +S60VideoRendererControl::~S60VideoRendererControl() +{ + // Stop surface if still active + if (m_surface) + if (m_surface->isActive()) + m_surface->stop(); +} + +QAbstractVideoSurface *S60VideoRendererControl::surface() const +{ + return m_surface; +} + +void S60VideoRendererControl::setSurface(QAbstractVideoSurface *surface) +{ + if (surface == 0) { + // Stop current surface if needed + if (m_surface) + if (m_surface->isActive()) + m_surface->stop(); + } + + m_surface = surface; + emit viewFinderSurfaceSet(); +} + +// End of file diff --git a/src/plugins/symbian/ecam/s60videorenderercontrol.h b/src/plugins/symbian/ecam/s60videorenderercontrol.h new file mode 100644 index 000000000..b35433f86 --- /dev/null +++ b/src/plugins/symbian/ecam/s60videorenderercontrol.h @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef S60VIDEORENDERERCONTROL_H +#define S60VIDEORENDERERCONTROL_H + +#include <qvideorenderercontrol.h> + +/* + * Control for QGraphicsVideoItem. Viewfinder frames are streamed to a surface + * which is drawn to the display by the Qt Graphics Vide Framework. + * VideoRendererControl uses only Bitmap Viewfinder. + */ +class S60VideoRendererControl : public QVideoRendererControl +{ + Q_OBJECT + +public: // Constructor & Destructor + + S60VideoRendererControl(QObject *parent = 0); + virtual ~S60VideoRendererControl(); + +public: // S60VideoRendererControl + + QAbstractVideoSurface *surface() const; + void setSurface(QAbstractVideoSurface *surface); + +signals: // Internal Signals + + void viewFinderSurfaceSet(); + +private: // Data + + QAbstractVideoSurface *m_surface; + +}; + +#endif // S60VIDEORENDERERCONTROL_H diff --git a/src/plugins/symbian/mmf/audiosource/audiosource_s60.pri b/src/plugins/symbian/mmf/audiosource/audiosource_s60.pri new file mode 100644 index 000000000..7732600fa --- /dev/null +++ b/src/plugins/symbian/mmf/audiosource/audiosource_s60.pri @@ -0,0 +1,31 @@ +INCLUDEPATH += $$PWD + +DEFINES += AUDIOSOURCEUSED + +symbian:LIBS += -lmediaclientaudio \ + -lmmfcontrollerframework \ + -lefsrv \ + -lbafl \ + +!contains(S60_VERSION, 3.1) { + contains(audiorouting_s60_enabled,yes) { + #We use audioinputrouting.lib for recording audio from different sources -lmediaclientaudioinputstream \ -lcone \ + DEFINES += AUDIOINPUT_ROUTING + message("Audio Input Routing enabled onwards 3.2 SDK") + LIBS += -laudioinputrouting + } +} + +HEADERS += $$PWD/s60audioencodercontrol.h \ + $$PWD/s60audiomediarecordercontrol.h \ + $$PWD/s60audioendpointselector.h \ + $$PWD/s60audiocaptureservice.h \ + $$PWD/s60audiocapturesession.h \ + $$PWD/S60audiocontainercontrol.h + +SOURCES += $$PWD/s60audioencodercontrol.cpp \ + $$PWD/s60audiomediarecordercontrol.cpp \ + $$PWD/s60audioendpointselector.cpp \ + $$PWD/s60audiocaptureservice.cpp \ + $$PWD/s60audiocapturesession.cpp \ + $$PWD/S60audiocontainercontrol.cpp diff --git a/src/plugins/symbian/mmf/audiosource/s60audiocaptureservice.cpp b/src/plugins/symbian/mmf/audiosource/s60audiocaptureservice.cpp new file mode 100644 index 000000000..742ac8f82 --- /dev/null +++ b/src/plugins/symbian/mmf/audiosource/s60audiocaptureservice.cpp @@ -0,0 +1,98 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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 "DebugMacros.h" +#include <QDebug> + +#include "s60audiocaptureservice.h" +#include "s60audiocapturesession.h" +#include "s60audioendpointselector.h" +#include "s60audioencodercontrol.h" +#include "s60audiomediarecordercontrol.h" +#include "s60audiocontainercontrol.h" + +S60AudioCaptureService::S60AudioCaptureService(QObject *parent): + QMediaService(parent) +{ + DP0("S60AudioCaptureService::S60AudioCaptureService +++"); + + m_session = new S60AudioCaptureSession(this); + m_encoderControl = new S60AudioEncoderControl(m_session,this); + m_recorderControl = new S60AudioMediaRecorderControl(m_session,this); + m_endpointSelector = new S60AudioEndpointSelector(m_session,this); + m_containerControl = new S60AudioContainerControl(m_session, this); + + DP0("S60AudioCaptureService::S60AudioCaptureService ---"); +} + +S60AudioCaptureService::~S60AudioCaptureService() +{ + DP0("S60AudioCaptureService::~S60AudioCaptureService +++"); + DP0("S60AudioCaptureService::~S60AudioCaptureService ---"); +} + +QMediaControl *S60AudioCaptureService::requestControl(const char *name) +{ + DP0("S60AudioCaptureService::requestControl"); + + if (qstrcmp(name,QMediaRecorderControl_iid) == 0) + return m_recorderControl; + + if (qstrcmp(name,QAudioEncoderControl_iid) == 0) + return m_encoderControl; + + if (qstrcmp(name,QAudioEndpointSelector_iid) == 0) + return m_endpointSelector; + + if (qstrcmp(name,QMediaContainerControl_iid) == 0) + return m_containerControl; + + return 0; +} + +void S60AudioCaptureService::releaseControl(QMediaControl *control) +{ + DP0("S60AudioCaptureService::releaseControl +++"); + + Q_UNUSED(control) + + DP0("S60AudioCaptureService::releaseControl ---"); +} diff --git a/src/plugins/symbian/mmf/audiosource/s60audiocaptureservice.h b/src/plugins/symbian/mmf/audiosource/s60audiocaptureservice.h new file mode 100644 index 000000000..86d71a994 --- /dev/null +++ b/src/plugins/symbian/mmf/audiosource/s60audiocaptureservice.h @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** +****************************************************************************/ + +#ifndef S60AUDIOCAPTURESERVICE_H +#define S60AUDIOCAPTURESERVICE_H + +#include <QtCore/qobject.h> + +#include <qmediaservice.h> + +QT_USE_NAMESPACE + +class S60AudioCaptureSession; +class S60AudioEncoderControl; +class S60AudioMediaRecorderControl; +class S60AudioEndpointSelector; +class S60AudioContainerControl; + + +class S60AudioCaptureService : public QMediaService +{ + Q_OBJECT +public: + S60AudioCaptureService(QObject *parent = 0); + ~S60AudioCaptureService(); + + QMediaControl *requestControl(const char *name); + void releaseControl(QMediaControl *control); +private: + S60AudioCaptureSession *m_session; + S60AudioEncoderControl *m_encoderControl; + S60AudioEndpointSelector *m_endpointSelector; + S60AudioMediaRecorderControl *m_recorderControl; + S60AudioContainerControl *m_containerControl; +}; + +#endif // S60AUDIOCAPTURESERVICE_H diff --git a/src/plugins/symbian/mmf/audiosource/s60audiocapturesession.cpp b/src/plugins/symbian/mmf/audiosource/s60audiocapturesession.cpp new file mode 100644 index 000000000..79b6a53a0 --- /dev/null +++ b/src/plugins/symbian/mmf/audiosource/s60audiocapturesession.cpp @@ -0,0 +1,937 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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 "DebugMacros.h" + +#include "s60audiocapturesession.h" +#include <QtCore/qdebug.h> +#include <QtCore/qurl.h> +#include <QDir> + +#include <mda/common/audio.h> +#include <mda/common/resource.h> +#include <mda/client/utility.h> +#include <mdaaudiosampleeditor.h> +#include <mmf/common/mmfcontrollerpluginresolver.h> +#include <mmf/common/mmfcontroller.h> +#include <badesca.h> +#include <bautils.h> +#include <f32file.h> + +#ifdef AUDIOINPUT_ROUTING +const QString S60AudioCaptureSession::microPhone("Microphone"); +const QString S60AudioCaptureSession::voiceCall("Voice Call"); +const QString S60AudioCaptureSession::fmRadio("FM Radio"); +#endif + +S60AudioCaptureSession::S60AudioCaptureSession(QObject *parent): + QObject(parent) + , m_recorderUtility(NULL) + , m_captureState(ENotInitialized) + , m_controllerIdMap(QHash<QString, ControllerData>()) + , m_audioCodeclist(QHash<QString, CodecData>()) + , m_error(QMediaRecorder::NoError) + , m_isMuted(false) +{ + DP0("S60AudioCaptureSession::S60AudioCaptureSession +++"); +#ifdef AUDIOINPUT_ROUTING + m_audioInput = NULL; + m_setActiveEndPoint = FALSE; + m_audioEndpoint = S60AudioCaptureSession::microPhone; +#endif //AUDIOINPUT_ROUTING + TRAPD(err, initializeSessionL()); + setError(err); + + DP0("S60AudioCaptureSession::S60AudioCaptureSession ---"); +} + +void S60AudioCaptureSession::initializeSessionL() +{ + DP0("S60AudioCaptureSession::initializeSessionL +++"); + + m_recorderUtility = CMdaAudioRecorderUtility::NewL(*this, 0, EMdaPriorityNormal, EMdaPriorityPreferenceTimeAndQuality); + updateAudioContainersL(); + populateAudioCodecsDataL(); + setDefaultSettings(); +#ifdef AUDIOINPUT_ROUTING + initAudioInputs(); +#endif + User::LeaveIfError(m_fsSession.Connect()); + m_captureState = EInitialized; + emit stateChanged(m_captureState); + + DP0("S60AudioCaptureSession::initializeSessionL ---"); +} + +void S60AudioCaptureSession::setError(TInt aError) +{ + DP0("S60AudioCaptureSession::setError +++"); + + DP1("S60AudioCaptureSession::setError:", aError); + + if (aError == KErrNone) + return; + + m_error = aError; + QMediaRecorder::Error recorderError = fromSymbianErrorToMultimediaError(m_error); + + // TODO: fix to user friendly string at some point + // These error string are only dev usable + QString symbianError; + symbianError.append("Symbian:"); + symbianError.append(QString::number(m_error)); + stop(); + emit error(recorderError, symbianError); + + DP0("S60AudioCaptureSession::setError ---"); +} + +QMediaRecorder::Error S60AudioCaptureSession::fromSymbianErrorToMultimediaError(int error) +{ + DP0("S60AudioCaptureSession::fromSymbianErrorToMultimediaError +++"); + + DP1("S60AudioCaptureSession::fromSymbianErrorToMultimediaError:", error); + + switch(error) { + case KErrNoMemory: + case KErrNotFound: + case KErrBadHandle: + case KErrAbort: + case KErrCorrupt: + case KErrGeneral: + case KErrPathNotFound: + case KErrUnknown: + case KErrNotReady: + case KErrInUse: + case KErrAccessDenied: + case KErrLocked: + case KErrPermissionDenied: + case KErrAlreadyExists: + return QMediaRecorder::ResourceError; + case KErrNotSupported: + case KErrArgument: + return QMediaRecorder::FormatError; + case KErrNone: + default: + DP0("S60AudioCaptureSession::fromSymbianErrorToMultimediaError: ---"); + return QMediaRecorder::NoError; + } +} + +S60AudioCaptureSession::~S60AudioCaptureSession() +{ + DP0("S60AudioCaptureSession::~S60AudioCaptureSession +++"); + //stop the utility before deleting it + stop(); + if (m_recorderUtility) + delete m_recorderUtility; + m_fsSession.Close(); + DP0("S60AudioCaptureSession::~S60AudioCaptureSession ---"); +} + +QAudioFormat S60AudioCaptureSession::format() const +{ + DP0("S60AudioCaptureSession::format"); + + return m_format; +} + +bool S60AudioCaptureSession::setFormat(const QAudioFormat &format) +{ + DP0("S60AudioCaptureSession::setFormat +++"); + + m_format = format; + + DP0("S60AudioCaptureSession::setFormat ---"); + + return true; +} + +QAudioEncoderSettings S60AudioCaptureSession::settings() const +{ + DP0("S60AudioCaptureSession::settings"); + + return m_audioEncoderSettings; +} + +bool S60AudioCaptureSession::setEncoderSettings(const QAudioEncoderSettings &setting) +{ + DP0("S60AudioCaptureSession::setEncoderSettings +++"); + + m_audioEncoderSettings = setting; + + DP0("S60AudioCaptureSession::setEncoderSettings ---"); + + return true; +} + +QStringList S60AudioCaptureSession::supportedAudioCodecs() const +{ + DP0("S60AudioCaptureSession::supportedAudioCodecs"); + + return m_audioCodeclist.keys(); +} + +QStringList S60AudioCaptureSession::supportedAudioContainers() const +{ + DP0("S60AudioCaptureSession::supportedAudioContainers"); + + return m_controllerIdMap.keys(); +} + +QString S60AudioCaptureSession::codecDescription(const QString &codecName) +{ + DP0("S60AudioCaptureSession::codecDescription +++"); + + if (m_audioCodeclist.keys().contains(codecName)) { + + DP0("S60AudioCaptureSession::codecDescription ---"); + return m_audioCodeclist.value(codecName).codecDescription; + } + else { + DP0("S60AudioCaptureSession::codecDescription ---"); + + return QString(); + } +} + +QString S60AudioCaptureSession::audioContainerDescription(const QString &containerName) +{ + DP0("S60AudioCaptureSession::audioContainerDescription +++"); + + if (m_controllerIdMap.keys().contains(containerName)) { + DP0("S60AudioCaptureSession::audioContainerDescription ---"); + + return m_controllerIdMap.value(containerName).destinationFormatDescription; + } + else { + DP0("S60AudioCaptureSession::audioContainerDescription ---"); + + return QString(); + } +} + +bool S60AudioCaptureSession::setAudioCodec(const QString &codecName) +{ + DP0("S60AudioCaptureSession::setAudioCodec"); + + QStringList codecs = supportedAudioCodecs(); + if(codecs.contains(codecName)) { + m_format.setCodec(codecName); + return true; + } + return false; +} + +bool S60AudioCaptureSession::setAudioContainer(const QString &containerMimeType) +{ + DP0("S60AudioCaptureSession::setAudioContainer"); + + QStringList containers = supportedAudioContainers(); + if (containerMimeType == "audio/mpeg") + { + m_container = "audio/mp4"; + return true; + } + if(containers.contains(containerMimeType)) { + m_container = containerMimeType; + return true; + } + return false; +} + +QString S60AudioCaptureSession::audioCodec() const +{ + DP0("S60AudioCaptureSession::audioCodec"); + + return m_format.codec(); +} + +QString S60AudioCaptureSession::audioContainer() const +{ + DP0("S60AudioCaptureSession::audioContainer"); + + return m_container; +} + +QUrl S60AudioCaptureSession::outputLocation() const +{ + DP0("S60AudioCaptureSession::outputLocation"); + + return m_sink; +} + +bool S60AudioCaptureSession::setOutputLocation(const QUrl& sink) +{ + DP0("S60AudioCaptureSession::setOutputLocation"); + + QString filename = QDir::toNativeSeparators(sink.toString()); + TPtrC16 path(reinterpret_cast<const TUint16*>(filename.utf16())); + TRAPD(err, BaflUtils::EnsurePathExistsL(m_fsSession,path)); + if (err == KErrNone) { + m_sink = sink; + setError(err); + return true; + }else { + setError(err); + return false; + } +} + +qint64 S60AudioCaptureSession::position() const +{ + DP0("S60AudioCaptureSession::position"); + + if ((m_captureState != ERecording) || !m_recorderUtility) + return 0; + + return m_recorderUtility->Duration().Int64() / 1000; +} + +void S60AudioCaptureSession::prepareSinkL() +{ + DP0("S60AudioCaptureSession::prepareSinkL +++"); + + /* If m_outputLocation is null, set a default location */ + if (m_sink.isEmpty()) { + QDir outputDir(QDir::rootPath()); + int lastImage = 0; + int fileCount = 0; + foreach(QString fileName, outputDir.entryList(QStringList() << "recordclip_*")) { + int imgNumber = fileName.mid(5, fileName.size() - 9).toInt(); + lastImage = qMax(lastImage, imgNumber); + if (outputDir.exists(fileName)) + fileCount += 1; + } + lastImage += fileCount; + m_sink = QUrl(QDir::toNativeSeparators(outputDir.canonicalPath() + QString("/recordclip_%1").arg(lastImage + 1, 4, 10, QLatin1Char('0')))); + } + + QString sink = QDir::toNativeSeparators(m_sink.toString()); + TPtrC16 path(reinterpret_cast<const TUint16*>(sink.utf16())); + if (BaflUtils::FileExists(m_fsSession, path)) + BaflUtils::DeleteFile(m_fsSession, path); + + int index = sink.lastIndexOf('.'); + if (index != -1) + sink.chop(sink.length()-index); + + sink.append(m_controllerIdMap.value(m_container).fileExtension); + m_sink.setUrl(sink); + + DP0("S60AudioCaptureSession::prepareSinkL ---"); +} + +void S60AudioCaptureSession::record() +{ + DP0("S60AudioCaptureSession::record +++"); + + if (!m_recorderUtility) + return; + + if (m_captureState == EInitialized || m_captureState == ERecordComplete) { + prepareSinkL(); + QString filename = m_sink.toString(); + TPtrC16 sink(reinterpret_cast<const TUint16*>(filename.utf16())); + TUid controllerUid(TUid::Uid(m_controllerIdMap.value(m_container).controllerUid)); + TUid formatUid(TUid::Uid(m_controllerIdMap.value(m_container).destinationFormatUid)); + + TRAPD(err,m_recorderUtility->OpenFileL(sink)); + setError(err); + }else if (m_captureState == EPaused) { + m_recorderUtility->SetPosition(m_pausedPosition); + TRAPD(error, m_recorderUtility->RecordL()); + setError(error); + m_captureState = ERecording; + emit stateChanged(m_captureState); + } + + DP0("S60AudioCaptureSession::record ---"); +} + +void S60AudioCaptureSession::mute(bool muted) +{ + DP0("S60AudioCaptureSession::mute +++"); + + if (!m_recorderUtility) + return; + + if (muted) + m_recorderUtility->SetGain(0); + else + m_recorderUtility->SetGain(m_recorderUtility->MaxGain()); + + m_isMuted = muted; + + DP0("S60AudioCaptureSession::mute ---"); +} + +bool S60AudioCaptureSession::muted() +{ + DP0("S60AudioCaptureSession::muted"); + + return m_isMuted; +} + +void S60AudioCaptureSession::setDefaultSettings() +{ + DP0("S60AudioCaptureSession::setDefaultSettings +++"); + + // Setting AMR to default format if supported + if (m_controllerIdMap.count() > 0) { + if ( m_controllerIdMap.contains("audio/amr")) + m_container = QString("audio/amr"); + else + m_container = m_controllerIdMap.keys()[0]; + } + if (m_audioCodeclist.keys().count() > 0) { + if (m_audioCodeclist.keys().contains("AMR")) { + m_format.setSampleSize(8); + m_format.setChannels(1); + m_format.setFrequency(8000); + m_format.setSampleType(QAudioFormat::SignedInt); + m_format.setCodec("AMR"); + }else + m_format.setCodec(m_audioCodeclist.keys()[0]); + } + + DP0("S60AudioCaptureSession::setDefaultSettings ---"); +} + +void S60AudioCaptureSession::pause() +{ + DP0("S60AudioCaptureSession::pause +++"); + + if (!m_recorderUtility) + return; + + m_pausedPosition = m_recorderUtility->Position(); + m_recorderUtility->Stop(); + m_captureState = EPaused; + emit stateChanged(m_captureState); + + DP0("S60AudioCaptureSession::pause ---"); +} + +void S60AudioCaptureSession::stop() +{ + DP0("S60AudioCaptureSession::stop +++"); + + if (!m_recorderUtility) + return; + + m_recorderUtility->Stop(); + +#ifdef AUDIOINPUT_ROUTING + //delete audio input instance before closing the utility. + if (m_audioInput) + { + delete m_audioInput; + m_audioInput = NULL; + } +#endif //AUDIOINPUT_ROUTING + + m_recorderUtility->Close(); + m_captureState = ERecordComplete; + emit stateChanged(m_captureState); +} + +#ifdef AUDIOINPUT_ROUTING + +void S60AudioCaptureSession::initAudioInputs() +{ + DP0(" S60AudioCaptureSession::initAudioInputs +++"); + + m_audioInputs[S60AudioCaptureSession::microPhone] = QString("Microphone associated with the currently active speaker."); + m_audioInputs[S60AudioCaptureSession::voiceCall] = QString("Audio stream associated with the current phone call."); + m_audioInputs[S60AudioCaptureSession::fmRadio] = QString("Audio of the currently tuned FM radio station."); + + DP0(" S60AudioCaptureSession::initAudioInputs ---"); +} + +#endif //AUDIOINPUT_ROUTING + +void S60AudioCaptureSession::setActiveEndpoint(const QString& audioEndpoint) +{ + DP0(" S60AudioCaptureSession::setActiveEndpoint +++"); + + if (!m_audioInputs.keys().contains(audioEndpoint)) + return; + + if (activeEndpoint().compare(audioEndpoint) != 0) { + m_audioEndpoint = audioEndpoint; +#ifdef AUDIOINPUT_ROUTING + m_setActiveEndPoint = TRUE; +#endif + } + + DP0(" S60AudioCaptureSession::setActiveEndpoint ---"); +} + +QList<QString> S60AudioCaptureSession::availableEndpoints() const +{ + DP0(" S60AudioCaptureSession::availableEndpoints"); + + return m_audioInputs.keys(); +} + +QString S60AudioCaptureSession::endpointDescription(const QString& name) const +{ + DP0(" S60AudioCaptureSession::endpointDescription +++"); + + if (m_audioInputs.keys().contains(name)) + return m_audioInputs.value(name); + return QString(); +} + +QString S60AudioCaptureSession::activeEndpoint() const +{ + DP0(" S60AudioCaptureSession::activeEndpoint"); + + QString inputSourceName = NULL; +#ifdef AUDIOINPUT_ROUTING + if (m_audioInput) { + CAudioInput::TAudioInputArray input = m_audioInput->AudioInput(); + inputSourceName = qStringFromTAudioInputPreference(input[0]); + } +#endif //AUDIOINPUT_ROUTING + return inputSourceName; +} + +QString S60AudioCaptureSession::defaultEndpoint() const +{ + DP0(" S60AudioCaptureSession::defaultEndpoint"); + +#ifdef AUDIOINPUT_ROUTING + return QString(S60AudioCaptureSession::microPhone); +#else + return NULL; +#endif +} + +#ifdef AUDIOINPUT_ROUTING + +void S60AudioCaptureSession::doSetAudioInputL(const QString& name) +{ + DP0(" S60AudioCaptureSession::doSetAudioInputL +++"); + DP1(" S60AudioCaptureSession::doSetAudioInputL:", name); + TInt err(KErrNone); + + if (!m_recorderUtility) + return; + + CAudioInput::TAudioInputPreference input = CAudioInput::EDefaultMic; + + if (name.compare(S60AudioCaptureSession::voiceCall) == 0) + input = CAudioInput::EVoiceCall; +// commented because they are not supported on 9.2 + else if (name.compare(S60AudioCaptureSession::fmRadio) == 0) + input = CAudioInput::EFMRadio; + else // S60AudioCaptureSession::microPhone + input = CAudioInput::EDefaultMic; + + RArray<CAudioInput::TAudioInputPreference> inputArray; + inputArray.Append(input); + + if (m_audioInput){ + TRAP(err,m_audioInput->SetAudioInputL(inputArray.Array())); + + if (err == KErrNone) { + emit activeEndpointChanged(name); + } + else{ + setError(err); + } + } + inputArray.Close(); + + DP0(" S60AudioCaptureSession::doSetAudioInputL ---"); +} + + +QString S60AudioCaptureSession::qStringFromTAudioInputPreference(CAudioInput::TAudioInputPreference input) const +{ + DP0(" S60AudioCaptureSession::qStringFromTAudioInputPreference"); + + if (input == CAudioInput::EVoiceCall) + return S60AudioCaptureSession::voiceCall; + else if (input == CAudioInput::EFMRadio) + return S60AudioCaptureSession::fmRadio; + else + return S60AudioCaptureSession::microPhone; // CAudioInput::EDefaultMic +} +#endif //AUDIOINPUT_ROUTING + + +void S60AudioCaptureSession::MoscoStateChangeEvent(CBase* aObject, + TInt aPreviousState, TInt aCurrentState, TInt aErrorCode) +{ + DP0("S60AudioCaptureSession::MoscoStateChangeEvent +++"); + + if (aErrorCode==KErrNone) { + TRAPD(err, MoscoStateChangeEventL(aObject, aPreviousState, aCurrentState, NULL)); + setError(err); + } + else { + setError(aErrorCode); + } + DP1("S60AudioCaptureSession::MoscoStateChangeEvent, aErrorCode:", aErrorCode); + DP0("S60AudioCaptureSession::MoscoStateChangeEvent ---"); +} + +void S60AudioCaptureSession::MoscoStateChangeEventL(CBase* aObject, + TInt aPreviousState, TInt aCurrentState, TInt aErrorCode) +{ + DP0("S60AudioCaptureSession::MoscoStateChangeEventL +++"); + + DP5("S60AudioCaptureSession::MoscoStateChangeEventL - aPreviousState:", aPreviousState, + "aCurrentState:", aCurrentState, "aErrorCode:", aErrorCode); + if (aObject != m_recorderUtility) + return; + + switch(aCurrentState) { + case CMdaAudioClipUtility::EOpen: { + if(aPreviousState == CMdaAudioClipUtility::ENotReady) { + applyAudioSettingsL(); + m_recorderUtility->SetGain(m_recorderUtility->MaxGain()); + TRAPD(err, m_recorderUtility->RecordL()); + setError(err); + m_captureState = EOpenCompelete; + emit stateChanged(m_captureState); + } + break; + } + case CMdaAudioClipUtility::ENotReady: { + m_captureState = EInitialized; + emit stateChanged(m_captureState); + break; + } + case CMdaAudioClipUtility::ERecording: { + m_captureState = ERecording; + emit stateChanged(m_captureState); + break; + } + default: { + break; + } + } + + DP0("S60AudioCaptureSession::MoscoStateChangeEventL ---"); +} + +void S60AudioCaptureSession::updateAudioContainersL() +{ + DP0("S60AudioCaptureSession::updateAudioContainersL +++"); + + CMMFControllerPluginSelectionParameters* pluginParameters = + CMMFControllerPluginSelectionParameters::NewLC(); + CMMFFormatSelectionParameters* formatParameters = + CMMFFormatSelectionParameters::NewLC(); + + pluginParameters->SetRequiredRecordFormatSupportL(*formatParameters); + + RArray<TUid> ids; + CleanupClosePushL(ids); + User::LeaveIfError(ids.Append(KUidMediaTypeAudio)); + + pluginParameters->SetMediaIdsL(ids, + CMMFPluginSelectionParameters::EAllowOnlySuppliedMediaIds); + + RMMFControllerImplInfoArray controllers; + CleanupResetAndDestroyPushL(controllers); + + //Get all audio record controllers/formats that are supported + pluginParameters->ListImplementationsL(controllers); + + for (TInt index=0; index<controllers.Count(); index++) { + const RMMFFormatImplInfoArray& recordFormats = + controllers[index]->RecordFormats(); + for (TInt j=0; j<recordFormats.Count(); j++) { + const CDesC8Array& mimeTypes = recordFormats[j]->SupportedMimeTypes(); + const CDesC8Array& fileExtensions = recordFormats[j]->SupportedFileExtensions(); + TInt mimeCount = mimeTypes.Count(); + TInt fileExtCount = fileExtensions.Count(); + + if (mimeCount > 0 && fileExtCount > 0) { + TPtrC8 extension = fileExtensions[0]; + TPtrC8 mimeType = mimeTypes[0]; + QString type = QString::fromUtf8((char *)mimeType.Ptr(), mimeType.Length()); + + if (type != "audio/basic") { + ControllerData data; + data.controllerUid = controllers[index]->Uid().iUid; + data.destinationFormatUid = recordFormats[j]->Uid().iUid; + data.destinationFormatDescription = QString::fromUtf16( + recordFormats[j]->DisplayName().Ptr(), + recordFormats[j]->DisplayName().Length()); + data.fileExtension = QString::fromUtf8((char *)extension.Ptr(), extension.Length()); + m_controllerIdMap[type] = data; + } + } + } + } + CleanupStack::PopAndDestroy(4);//controllers, ids, formatParameters, pluginParameters + + DP0("S60AudioCaptureSession::updateAudioContainersL ---"); +} + +void S60AudioCaptureSession::retrieveSupportedAudioSampleRatesL() +{ + DP0("S60AudioCaptureSession::retrieveSupportedAudioSampleRatesL +++"); + + if (!m_recorderUtility) { + DP0("No RecorderUtility"); + return; + } + + m_supportedSampleRates.clear(); + + RArray<TUint> supportedSampleRates; + CleanupClosePushL(supportedSampleRates); + m_recorderUtility->GetSupportedSampleRatesL(supportedSampleRates); + for (TInt j = 0; j < supportedSampleRates.Count(); j++ ) + m_supportedSampleRates.append(supportedSampleRates[j]); + + CleanupStack::PopAndDestroy(&supportedSampleRates); + + DP0("S60AudioCaptureSession::retrieveSupportedAudioSampleRatesL ---"); +} + +QList<int> S60AudioCaptureSession::supportedAudioSampleRates(const QAudioEncoderSettings &settings) const +{ + DP0("S60AudioCaptureSession::supportedAudioSampleRates +++"); + + QList<int> supportedSampleRates; + + if (!settings.codec().isEmpty()) { + if (settings.codec() == "AMR") + supportedSampleRates.append(8000); + else + supportedSampleRates = m_supportedSampleRates; + }else + supportedSampleRates = m_supportedSampleRates; + + DP0("S60AudioCaptureSession::supportedAudioSampleRates ---"); + + return supportedSampleRates; +} + +void S60AudioCaptureSession::populateAudioCodecsDataL() +{ + DP0("S60AudioCaptureSession::populateAudioCodecsDataL +++"); + + if (!m_recorderUtility) { + DP0("No RecorderUtility"); + + return; + } + + if (m_controllerIdMap.contains("audio/amr")) { + CodecData data; + data.codecDescription = QString("GSM AMR Codec"); + m_audioCodeclist[QString("AMR")]=data; + } + if (m_controllerIdMap.contains("audio/basic")) { + CodecData data; + data.fourCC = KMMFFourCCCodeALAW; + data.codecDescription = QString("Sun/Next ""Au"" audio codec"); + m_audioCodeclist[QString("AULAW")]=data; + } + if (m_controllerIdMap.contains("audio/wav")) { + CodecData data; + data.fourCC = KMMFFourCCCodePCM16; + data.codecDescription = QString("Pulse code modulation"); + m_audioCodeclist[QString("PCM")]=data; + } + if (m_controllerIdMap.contains("audio/mp4")) { + CodecData data; + data.fourCC = KMMFFourCCCodeAAC; + data.codecDescription = QString("Advanced Audio Codec"); + m_audioCodeclist[QString("AAC")]=data; + } + + // default samplerates + m_supportedSampleRates << 96000 << 88200 << 64000 << 48000 << 44100 << 32000 << 24000 << 22050 << 16000 << 12000 << 11025 << 8000; + + DP0("S60AudioCaptureSession::populateAudioCodecsDataL ---"); +} + +void S60AudioCaptureSession::applyAudioSettingsL() +{ + DP0("S60AudioCaptureSession::applyAudioSettingsL +++"); + + if (!m_recorderUtility) + return; + +#ifdef AUDIOINPUT_ROUTING + //CAudioInput needs to be re-initialized every time recording starts + if (m_audioInput) { + delete m_audioInput; + m_audioInput = NULL; + } + + if (m_setActiveEndPoint) { + m_audioInput = CAudioInput::NewL(*m_recorderUtility); + doSetAudioInputL(m_audioEndpoint); + } +#endif //AUDIOINPUT_ROUTING + + if (m_format.codec() == "AMR") + return; + + TFourCC fourCC = m_audioCodeclist.value(m_format.codec()).fourCC; + + if (m_format.codec() == "PCM") + fourCC = determinePCMFormat(); + + RArray<TFourCC> supportedDataTypes; + CleanupClosePushL(supportedDataTypes); + TRAPD(err,m_recorderUtility->GetSupportedDestinationDataTypesL(supportedDataTypes)); + TInt num = supportedDataTypes.Count(); + if (num > 0 ) { + supportedDataTypes.SortUnsigned(); + int index = supportedDataTypes.Find(fourCC.FourCC()); + if (index != KErrNotFound) { + TRAPD(err,m_recorderUtility->SetDestinationDataTypeL(supportedDataTypes[index])); + } + } + + supportedDataTypes.Reset(); + CleanupStack::PopAndDestroy(&supportedDataTypes); + + if (m_recorderUtility->DestinationSampleRateL() != m_format.frequency()) { + + RArray<TUint> supportedSampleRates; + CleanupClosePushL(supportedSampleRates); + m_recorderUtility->GetSupportedSampleRatesL(supportedSampleRates); + for (TInt i = 0; i < supportedSampleRates.Count(); i++ ) { + TUint supportedSampleRate = supportedSampleRates[i]; + if (supportedSampleRate == m_format.frequency()) { + m_recorderUtility->SetDestinationSampleRateL(m_format.frequency()); + break; + } + } + supportedSampleRates.Reset(); + CleanupStack::PopAndDestroy(&supportedSampleRates); + } + + /* If requested channel setting is different than current one */ + if (m_recorderUtility->DestinationNumberOfChannelsL() != m_format.channels()) { + RArray<TUint> supportedChannels; + CleanupClosePushL(supportedChannels); + m_recorderUtility->GetSupportedNumberOfChannelsL(supportedChannels); + for (TInt l = 0; l < supportedChannels.Count(); l++ ) { + if (supportedChannels[l] == m_format.channels()) { + m_recorderUtility->SetDestinationNumberOfChannelsL(m_format.channels()); + break; + } + } + supportedChannels.Reset(); + CleanupStack::PopAndDestroy(&supportedChannels); + } + + if (!(m_format.codec().compare("pcm",Qt::CaseInsensitive) == 0)) { + if (m_recorderUtility->DestinationBitRateL() != m_audioEncoderSettings.bitRate()) { + RArray<TUint> supportedBitRates; + CleanupClosePushL(supportedBitRates); + m_recorderUtility->GetSupportedBitRatesL(supportedBitRates); + for (TInt l = 0; l < supportedBitRates.Count(); l++ ) { + if (supportedBitRates[l] == m_audioEncoderSettings.bitRate()) { + m_recorderUtility->SetDestinationBitRateL(m_audioEncoderSettings.bitRate()); + break; + } + } + supportedBitRates.Reset(); + CleanupStack::PopAndDestroy(&supportedBitRates); + } + } + + DP0("S60AudioCaptureSession::applyAudioSettingsL ---"); +} + +TFourCC S60AudioCaptureSession::determinePCMFormat() +{ + DP0("S60AudioCaptureSession::determinePCMFormat +++"); + + TFourCC fourCC; + + if (m_format.sampleSize() == 8) { + // 8 bit + switch (m_format.sampleType()) { + case QAudioFormat::SignedInt: { + fourCC.Set(KMMFFourCCCodePCM8); + break; + } + case QAudioFormat::UnSignedInt: { + fourCC.Set(KMMFFourCCCodePCMU8); + break; + } + case QAudioFormat::Float: + case QAudioFormat::Unknown: + default: { + fourCC.Set(KMMFFourCCCodePCM8); + break; + } + } + } else if (m_format.sampleSize() == 16) { + // 16 bit + switch (m_format.sampleType()) { + case QAudioFormat::SignedInt: { + fourCC.Set(m_format.byteOrder()==QAudioFormat::BigEndian? + KMMFFourCCCodePCM16B:KMMFFourCCCodePCM16); + break; + } + case QAudioFormat::UnSignedInt: { + fourCC.Set(m_format.byteOrder()==QAudioFormat::BigEndian? + KMMFFourCCCodePCMU16B:KMMFFourCCCodePCMU16); + break; + } + default: { + fourCC.Set(KMMFFourCCCodePCM16); + break; + } + } + } + + DP0("S60AudioCaptureSession::determinePCMFormat ---"); + + return fourCC; +} diff --git a/src/plugins/symbian/mmf/audiosource/s60audiocapturesession.h b/src/plugins/symbian/mmf/audiosource/s60audiocapturesession.h new file mode 100644 index 000000000..a541446e9 --- /dev/null +++ b/src/plugins/symbian/mmf/audiosource/s60audiocapturesession.h @@ -0,0 +1,193 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** +****************************************************************************/ + +#ifndef S60AUDIOCAPTURESESSION_H +#define S60AUDIOCAPTURESESSION_H + +#include <qmobilityglobal.h> +#include <QtCore/qobject.h> +#include <QFile> +#include <QUrl> +#include <QList> +#include <QHash> +#include <QMap> +#include "qaudioformat.h" +#include <qmediarecorder.h> + +#include <mda/common/audio.h> +#include <mda/common/resource.h> +#include <mda/client/utility.h> +#include <mdaaudiosampleeditor.h> +#include <mmf/common/mmfutilities.h> + +#ifdef AUDIOINPUT_ROUTING +#include <audioinput.h> +#endif //AUDIOINPUT_ROUTING + +QT_BEGIN_NAMESPACE +struct ControllerData +{ + int controllerUid; + int destinationFormatUid; + QString destinationFormatDescription; + QString fileExtension; +}; + +struct CodecData +{ + TFourCC fourCC; + QString codecDescription; +}; +QT_END_NAMESPACE + +QT_USE_NAMESPACE + +class S60AudioCaptureSession : public QObject, public MMdaObjectStateChangeObserver +{ + Q_OBJECT + Q_PROPERTY(qint64 position READ position NOTIFY positionChanged) + Q_ENUMS(TAudioCaptureState) +public: + + enum TAudioCaptureState + { + ENotInitialized = 0, + EInitialized, + EOpenCompelete, + ERecording, + EPaused, + ERecordComplete + }; + + S60AudioCaptureSession(QObject *parent = 0); + ~S60AudioCaptureSession(); + + QAudioFormat format() const; + bool setFormat(const QAudioFormat &format); + QAudioEncoderSettings settings() const; + bool setEncoderSettings(const QAudioEncoderSettings &setting); + QStringList supportedAudioCodecs() const; + QString codecDescription(const QString &codecName); + bool setAudioCodec(const QString &codecName); + QString audioCodec() const; + QString audioContainer() const; + QStringList supportedAudioContainers() const; + bool setAudioContainer(const QString &containerMimeType); + QString audioContainerDescription(const QString &containerName); + QList<int> supportedAudioSampleRates(const QAudioEncoderSettings &settings) const; + QUrl outputLocation() const; + bool setOutputLocation(const QUrl& sink); + qint64 position() const; + void record(); + void pause(); + void stop(); + void mute(bool muted); + bool muted(); + + QString activeEndpoint() const; + QString defaultEndpoint() const; + QList<QString> availableEndpoints() const; + QString endpointDescription(const QString& name) const; + +#ifdef AUDIOINPUT_ROUTING + static const QString microPhone; + static const QString voiceCall; + static const QString fmRadio; +#endif //AUDIOINPUT_ROUTING +private: + void initializeSessionL(); + void setError(TInt aError); + QMediaRecorder::Error fromSymbianErrorToMultimediaError(int error); + void prepareSinkL(); + void updateAudioContainersL(); + void populateAudioCodecsDataL(); + void retrieveSupportedAudioSampleRatesL(); + void applyAudioSettingsL(); + TFourCC determinePCMFormat(); + void setDefaultSettings(); + // MMdaObjectStateChangeObserver + void MoscoStateChangeEvent(CBase* aObject, TInt aPreviousState, + TInt aCurrentState, TInt aErrorCode); + void MoscoStateChangeEventL(CBase* aObject, TInt aPreviousState, + TInt aCurrentState, TInt aErrorCode); + +#ifdef AUDIOINPUT_ROUTING + QString qStringFromTAudioInputPreference(CAudioInput::TAudioInputPreference input) const; + void initAudioInputs(); + void doSetAudioInputL(const QString& name); +#endif //AUDIOINPUT_ROUTING + +public Q_SLOTS: + void setActiveEndpoint(const QString& audioEndpoint); + + +Q_SIGNALS: + void stateChanged(S60AudioCaptureSession::TAudioCaptureState); + void positionChanged(qint64 position); + void error(int error, const QString &errorString); + void activeEndpointChanged(const QString &audioEndpoint); +private: + QString m_container; + QUrl m_sink; + TTimeIntervalMicroSeconds m_pausedPosition; + CMdaAudioRecorderUtility *m_recorderUtility; + TAudioCaptureState m_captureState; + QAudioFormat m_format; + QAudioEncoderSettings m_audioEncoderSettings; + QHash<QString, ControllerData> m_controllerIdMap; + QHash<QString, CodecData> m_audioCodeclist; + QList<int> m_supportedSampleRates; + int m_error; + bool m_isMuted; + RFs m_fsSession; + +#ifdef AUDIOINPUT_ROUTING + bool m_setActiveEndPoint; + CAudioInput *m_audioInput; + +#endif //AUDIOINPUT_ROUTING + QMap<QString, QString> m_audioInputs; + QString m_audioEndpoint; + + +}; + +#endif // S60AUDIOCAPTURESESSION_H diff --git a/src/plugins/symbian/mmf/audiosource/s60audiocontainercontrol.cpp b/src/plugins/symbian/mmf/audiosource/s60audiocontainercontrol.cpp new file mode 100644 index 000000000..d6c2d5db2 --- /dev/null +++ b/src/plugins/symbian/mmf/audiosource/s60audiocontainercontrol.cpp @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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 "DebugMacros.h" + +#include "s60audiocontainercontrol.h" +#include "s60audiocapturesession.h" +#include <QtCore/qdebug.h> + +S60AudioContainerControl::S60AudioContainerControl(QObject *parent) + : QMediaContainerControl(parent) +{ + DP0("S60AudioContainerControl::S60AudioContainerControl(QObject *parent) +++"); + + DP0("S60AudioContainerControl::S60AudioContainerControl(QObject *parent) ---"); + +} + +S60AudioContainerControl::S60AudioContainerControl(QObject *session, QObject *parent) + : QMediaContainerControl(parent) +{ + DP0("S60AudioContainerControl::S60AudioContainerControl(QObject *session, QObject *parent) +++"); + + m_session = qobject_cast<S60AudioCaptureSession*>(session); + + DP0("S60AudioContainerControl::S60AudioContainerControl(QObject *session, QObject *parent) ---"); +} + +QStringList S60AudioContainerControl::supportedContainers() const +{ + DP0("S60AudioContainerControl::supportedContainers"); + + return m_session->supportedAudioContainers(); +} + +QString S60AudioContainerControl::containerMimeType() const +{ + DP0("S60AudioContainerControl::containerMimeType"); + + return m_session->audioContainer(); +} + +void S60AudioContainerControl::setContainerMimeType(const QString &containerMimeType) +{ + DP0("S60AudioContainerControl::setContainerMimeType +++"); + + m_session->setAudioContainer(containerMimeType); + + DP0("S60AudioContainerControl::setContainerMimeType ---"); +} + +QString S60AudioContainerControl::containerDescription(const QString &containerMimeType) const +{ + DP0("S60AudioContainerControl::containerDescription"); + + return m_session->audioContainerDescription(containerMimeType); +} + diff --git a/src/plugins/symbian/mmf/audiosource/s60audiocontainercontrol.h b/src/plugins/symbian/mmf/audiosource/s60audiocontainercontrol.h new file mode 100644 index 000000000..4c3498d0f --- /dev/null +++ b/src/plugins/symbian/mmf/audiosource/s60audiocontainercontrol.h @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** +****************************************************************************/ + +#ifndef S60AUDIOFORMATCONTROL_H +#define S60AUDIOFORMATCONTROL_H + +#include "qmediacontainercontrol.h" +#include <QtCore/qstringlist.h> + + +QT_USE_NAMESPACE + +class S60AudioCaptureSession; + +class S60AudioContainerControl : public QMediaContainerControl +{ +Q_OBJECT +public: + S60AudioContainerControl(QObject *parent = 0); + S60AudioContainerControl(QObject *session, QObject *parent = 0); + virtual ~S60AudioContainerControl() {}; + + QStringList supportedContainers() const; + QString containerMimeType() const; + void setContainerMimeType(const QString &containerMimeType); + QString containerDescription(const QString &containerMimeType) const; + +private: + S60AudioCaptureSession* m_session; +}; + +#endif // S60AUDIOFORMATCONTROL_H diff --git a/src/plugins/symbian/mmf/audiosource/s60audioencodercontrol.cpp b/src/plugins/symbian/mmf/audiosource/s60audioencodercontrol.cpp new file mode 100644 index 000000000..b3d02a94a --- /dev/null +++ b/src/plugins/symbian/mmf/audiosource/s60audioencodercontrol.cpp @@ -0,0 +1,235 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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 "DebugMacros.h" + +#include "s60audioencodercontrol.h" +#include "s60audiocapturesession.h" + +#include "qaudioformat.h" + +#include <QtCore/qdebug.h> + +S60AudioEncoderControl::S60AudioEncoderControl(QObject *session, QObject *parent) + :QAudioEncoderControl(parent), m_quality(QtMultimediaKit::NormalQuality) +{ + DP0("S60AudioEncoderControl::S60AudioEncoderControl +++"); + + m_session = qobject_cast<S60AudioCaptureSession*>(session); + QAudioFormat fmt = m_session->format(); + // medium, 22050Hz mono S16 + fmt.setSampleType(QAudioFormat::SignedInt); + if (fmt.codec().compare("PCM", Qt::CaseInsensitive) == 0) { + fmt.setSampleSize(16); + fmt.setFrequency(22050); + } + fmt.setChannels(1); + m_session->setFormat(fmt); + m_settings.setChannelCount(fmt.channels()); + m_settings.setCodec(fmt.codec()); + m_settings.setSampleRate(fmt.sampleRate()); + + DP0("S60AudioEncoderControl::S60AudioEncoderControl ---"); +} + +S60AudioEncoderControl::~S60AudioEncoderControl() +{ + DP0("S60AudioEncoderControl::~S60AudioEncoderControl +++"); + + DP0("S60AudioEncoderControl::~S60AudioEncoderControl ---"); +} + +QStringList S60AudioEncoderControl::supportedAudioCodecs() const +{ + DP0("S60AudioEncoderControl::supportedAudioCodecs"); + + return m_session->supportedAudioCodecs(); +} + +QString S60AudioEncoderControl::codecDescription(const QString &codecName) const +{ + DP0("S60AudioEncoderControl::codecDescription"); + + return m_session->codecDescription(codecName); +} + +QtMultimediaKit::EncodingQuality S60AudioEncoderControl::quality() const +{ + DP0("S60AudioEncoderControl::quality"); + + return m_quality; +} + +void S60AudioEncoderControl::setQuality(QtMultimediaKit::EncodingQuality value, QAudioFormat &fmt) +{ + DP0("S60AudioEncoderControl::setQuality +++"); + + switch (value) { + case QtMultimediaKit::VeryLowQuality: + case QtMultimediaKit::LowQuality: + // low, 8000Hz mono U8 + fmt.setSampleType(QAudioFormat::UnSignedInt); + fmt.setSampleSize(8); + fmt.setFrequency(8000); + fmt.setChannels(1); + break; + case QtMultimediaKit::NormalQuality: + // medium, 22050Hz mono S16 + fmt.setSampleType(QAudioFormat::SignedInt); + fmt.setSampleSize(16); + fmt.setFrequency(22050); + fmt.setChannels(1); + break; + case QtMultimediaKit::HighQuality: + case QtMultimediaKit::VeryHighQuality: + // high, 44100Hz mono S16 + fmt.setSampleType(QAudioFormat::SignedInt); + fmt.setSampleSize(16); + fmt.setFrequency(44100); + fmt.setChannels(2); + break; + default: + break; + } + + DP0("S60AudioEncoderControl::setQuality ---"); +} + +QStringList S60AudioEncoderControl::supportedEncodingOptions(const QString &codec) const +{ + DP0("S60AudioEncoderControl::supportedEncodingOptions"); + + Q_UNUSED(codec) + QStringList list; + if (codec == "PCM") + list << "quality" << "channels" << "samplerate"; + return list; +} + +QVariant S60AudioEncoderControl::encodingOption(const QString &codec, const QString &name) const +{ + DP0("S60AudioEncoderControl::encodingOption"); + + if (codec == "PCM") { + QAudioFormat fmt = m_session->format(); + + if(qstrcmp(name.toLocal8Bit().constData(), "quality") == 0) { + return QVariant(quality()); + } + else if(qstrcmp(name.toLocal8Bit().constData(), "channels") == 0) { + return QVariant(fmt.channels()); + } + else if(qstrcmp(name.toLocal8Bit().constData(), "samplerate") == 0) { + return QVariant(fmt.frequency()); + } + } + return QVariant(); +} + +void S60AudioEncoderControl::setEncodingOption( + const QString &codec, const QString &name, const QVariant &value) +{ + DP0("S60AudioEncoderControl::setEncodingOption +++"); + + if (codec == "PCM") { + QAudioFormat fmt = m_session->format(); + + if(qstrcmp(name.toLocal8Bit().constData(), "quality") == 0) { + setQuality((QtMultimediaKit::EncodingQuality)value.toInt(), fmt); + } else if(qstrcmp(name.toLocal8Bit().constData(), "channels") == 0) { + fmt.setChannels(value.toInt()); + } else if(qstrcmp(name.toLocal8Bit().constData(), "samplerate") == 0) { + fmt.setFrequency(value.toInt()); + } + m_session->setFormat(fmt); + } + + DP0("S60AudioEncoderControl::setEncodingOption ---"); +} + +QList<int> S60AudioEncoderControl::supportedSampleRates(const QAudioEncoderSettings &settings, bool *continuous) const +{ + DP0("S60AudioEncoderControl::supportedSampleRates"); + + if (continuous) + *continuous = false; + + return m_session->supportedAudioSampleRates(settings); +} + +QAudioEncoderSettings S60AudioEncoderControl::audioSettings() const +{ + DP0("S60AudioEncoderControl::audioSettings"); + + return m_settings; +} + +void S60AudioEncoderControl::setAudioSettings(const QAudioEncoderSettings &settings) +{ + DP0("S60AudioEncoderControl::setAudioSettings +++"); + + QAudioFormat fmt = m_session->format(); + if (settings.encodingMode() == QtMultimediaKit::ConstantQualityEncoding) { + fmt.setCodec(settings.codec()); + setQuality(settings.quality(), fmt); + if (settings.sampleRate() > 0) { + fmt.setFrequency(settings.sampleRate()); + } + if (settings.channelCount() > 0) + fmt.setChannels(settings.channelCount()); + }else { + if (settings.sampleRate() == 8000) { + fmt.setSampleType(QAudioFormat::UnSignedInt); + fmt.setSampleSize(8); + } else { + fmt.setSampleType(QAudioFormat::SignedInt); + fmt.setSampleSize(16); + } + fmt.setCodec(settings.codec()); + fmt.setFrequency(settings.sampleRate()); + fmt.setChannels(settings.channelCount()); + } + m_session->setFormat(fmt); + m_session->setEncoderSettings(settings); + m_settings = settings; + + DP0("S60AudioEncoderControl::setAudioSettings ---"); +} diff --git a/src/plugins/symbian/mmf/audiosource/s60audioencodercontrol.h b/src/plugins/symbian/mmf/audiosource/s60audioencodercontrol.h new file mode 100644 index 000000000..236d7d522 --- /dev/null +++ b/src/plugins/symbian/mmf/audiosource/s60audioencodercontrol.h @@ -0,0 +1,82 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** +****************************************************************************/ + +#ifndef AUDIOENCODERCONTROL_H +#define AUDIOENCODERCONTROL_H + +#include <qaudioencodercontrol.h> +#include <QtCore/qstringlist.h> +#include "qaudioformat.h" + +QT_USE_NAMESPACE + +class S60AudioCaptureSession; + +class S60AudioEncoderControl : public QAudioEncoderControl +{ + Q_OBJECT +public: + S60AudioEncoderControl(QObject *session, QObject *parent = 0); + virtual ~S60AudioEncoderControl(); + + QStringList supportedAudioCodecs() const; + QString codecDescription(const QString &codecName) const; + + QList<int> supportedSampleRates(const QAudioEncoderSettings &settings, bool *continuous = 0) const; + + QAudioEncoderSettings audioSettings() const; + void setAudioSettings(const QAudioEncoderSettings&); + + QStringList supportedEncodingOptions(const QString &codec) const; + QVariant encodingOption(const QString &codec, const QString &name) const; + void setEncodingOption(const QString &codec, const QString &name, const QVariant &value); + +private: + QtMultimediaKit::EncodingQuality quality() const; + void setQuality(QtMultimediaKit::EncodingQuality, QAudioFormat &format); + +private: + S60AudioCaptureSession* m_session; + QAudioEncoderSettings m_settings; + QtMultimediaKit::EncodingQuality m_quality; +}; + +#endif diff --git a/src/plugins/symbian/mmf/audiosource/s60audioendpointselector.cpp b/src/plugins/symbian/mmf/audiosource/s60audioendpointselector.cpp new file mode 100644 index 000000000..a2f909316 --- /dev/null +++ b/src/plugins/symbian/mmf/audiosource/s60audioendpointselector.cpp @@ -0,0 +1,100 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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 "DebugMacros.h" + +#include "s60audiocapturesession.h" +#include "s60audioendpointselector.h" + +#include <qaudiodeviceinfo.h> + +S60AudioEndpointSelector::S60AudioEndpointSelector(QObject *session, QObject *parent) + :QAudioEndpointSelector(parent) +{ + DP0("S60AudioEndpointSelector::S60AudioEndpointSelector +++"); + m_session = qobject_cast<S60AudioCaptureSession*>(session); + + connect(m_session, SIGNAL(activeEndpointChanged(const QString &)), this, SIGNAL(activeEndpointChanged(const QString &))); + + DP0("S60AudioEndpointSelector::S60AudioEndpointSelector ---"); +} + +S60AudioEndpointSelector::~S60AudioEndpointSelector() +{ + DP0("S60AudioEndpointSelector::~S60AudioEndpointSelector +++"); + + DP0("S60AudioEndpointSelector::~S60AudioEndpointSelector ---"); +} + +QList<QString> S60AudioEndpointSelector::availableEndpoints() const +{ + DP0("S60AudioEndpointSelector::availableEndpoints"); + + return m_session->availableEndpoints(); +} + +QString S60AudioEndpointSelector::endpointDescription(const QString& name) const +{ + DP0("S60AudioEndpointSelector::endpointDescription"); + + return m_session->endpointDescription(name); +} + +QString S60AudioEndpointSelector::defaultEndpoint() const +{ + DP0("S60AudioEndpointSelector::defaultEndpoint"); + + return m_session->defaultEndpoint(); +} + +QString S60AudioEndpointSelector::activeEndpoint() const +{ + DP0("S60AudioEndpointSelector::activeEndpoint"); + + return m_session->activeEndpoint(); +} + +void S60AudioEndpointSelector::setActiveEndpoint(const QString& name) +{ + DP0("S60AudioEndpointSelector::setActiveEndpoint +++"); + m_session->setActiveEndpoint(name); + DP0("S60AudioEndpointSelector::setActiveEndpoint ---"); +} diff --git a/src/plugins/symbian/mmf/audiosource/s60audioendpointselector.h b/src/plugins/symbian/mmf/audiosource/s60audioendpointselector.h new file mode 100644 index 000000000..d89ce8765 --- /dev/null +++ b/src/plugins/symbian/mmf/audiosource/s60audioendpointselector.h @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** +****************************************************************************/ + +#ifndef S60AUDIOENDPOINTSELECTOR_H +#define S60AUDIOENDPOINTSELECTOR_H + +#include <QStringList> + +#include <qaudioendpointselector.h> + +QT_USE_NAMESPACE + +class S60AudioCaptureSession; + +class S60AudioEndpointSelector : public QAudioEndpointSelector +{ + +Q_OBJECT + +public: + S60AudioEndpointSelector(QObject *session, QObject *parent = 0); + ~S60AudioEndpointSelector(); + + QList<QString> availableEndpoints() const; + QString endpointDescription(const QString& name) const; + QString defaultEndpoint() const; + QString activeEndpoint() const; + + +public Q_SLOTS: + void setActiveEndpoint(const QString& name); + +private: + + S60AudioCaptureSession* m_session; +}; + +#endif // S60AUDIOENDPOINTSELECTOR_H diff --git a/src/plugins/symbian/mmf/audiosource/s60audiomediarecordercontrol.cpp b/src/plugins/symbian/mmf/audiosource/s60audiomediarecordercontrol.cpp new file mode 100644 index 000000000..5d80033b3 --- /dev/null +++ b/src/plugins/symbian/mmf/audiosource/s60audiomediarecordercontrol.cpp @@ -0,0 +1,180 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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 "DebugMacros.h" + +#include "s60audiomediarecordercontrol.h" +#include "s60audiocapturesession.h" + +#include <QtCore/qdebug.h> + +S60AudioMediaRecorderControl::S60AudioMediaRecorderControl(QObject *session, QObject *parent) + :QMediaRecorderControl(parent), m_state(QMediaRecorder::StoppedState) +{ + DP0("S60AudioMediaRecorderControl::S60AudioMediaRecorderControl +++"); + + m_session = qobject_cast<S60AudioCaptureSession*>(session); + connect(m_session, SIGNAL(positionChanged(qint64)), this, SIGNAL(durationChanged(qint64))); + connect(m_session, SIGNAL(stateChanged(S60AudioCaptureSession::TAudioCaptureState)), this, SLOT(updateState(S60AudioCaptureSession::TAudioCaptureState))); + connect(m_session,SIGNAL(error(int,const QString &)),this,SIGNAL(error(int,const QString &))); + + DP0("S60AudioMediaRecorderControl::S60AudioMediaRecorderControl ---"); +} + +S60AudioMediaRecorderControl::~S60AudioMediaRecorderControl() +{ + DP0("S60AudioMediaRecorderControl::~S60AudioMediaRecorderControl +++"); + + DP0("S60AudioMediaRecorderControl::~S60AudioMediaRecorderControl - - "); +} + +QUrl S60AudioMediaRecorderControl::outputLocation() const +{ + DP0("S60AudioMediaRecorderControl::outputLocation"); + + return m_session->outputLocation(); +} + +bool S60AudioMediaRecorderControl::setOutputLocation(const QUrl& sink) +{ + DP0("S60AudioMediaRecorderControl::setOutputLocation"); + + return m_session->setOutputLocation(sink); +} + +QMediaRecorder::State S60AudioMediaRecorderControl::convertState(S60AudioCaptureSession::TAudioCaptureState aState) const +{ + DP0("S60AudioMediaRecorderControl::convertState +++"); + + QMediaRecorder::State state = QMediaRecorder::StoppedState;; + switch (aState) { + case S60AudioCaptureSession::ERecording: + state = QMediaRecorder::RecordingState; + break; + case S60AudioCaptureSession::EPaused: + state = QMediaRecorder::PausedState; + break; + case S60AudioCaptureSession::ERecordComplete: + case S60AudioCaptureSession::ENotInitialized: + case S60AudioCaptureSession::EOpenCompelete: + case S60AudioCaptureSession::EInitialized: + state = QMediaRecorder::StoppedState; + break; + } + + DP1("S60AudioMediaRecorderControl::convertState:", state); + + DP0("S60AudioMediaRecorderControl::convertState ---"); + + return state; +} + +void S60AudioMediaRecorderControl::updateState(S60AudioCaptureSession::TAudioCaptureState aState) +{ + DP0("S60AudioMediaRecorderControl::updateState +++"); + + QMediaRecorder::State newState = convertState(aState); + if (m_state != newState) { + m_state = newState; + emit stateChanged(m_state); + } + + DP0("S60AudioMediaRecorderControl::updateState ---"); +} + +QMediaRecorder::State S60AudioMediaRecorderControl::state() const +{ + DP0("S60AudioMediaRecorderControl::state"); + + return m_state; +} + +qint64 S60AudioMediaRecorderControl::duration() const +{ + // DP0("S60AudioMediaRecorderControl::duration +++"); + + return m_session->position(); +} + +void S60AudioMediaRecorderControl::record() +{ + DP0("S60AudioMediaRecorderControl::record +++"); + + m_session->record(); + + DP0("S60AudioMediaRecorderControl::record ---"); +} + +void S60AudioMediaRecorderControl::pause() +{ + DP0("S60AudioMediaRecorderControl::pause +++"); + + m_session->pause(); + + DP0("S60AudioMediaRecorderControl::pause ---"); +} + +void S60AudioMediaRecorderControl::stop() +{ + DP0("S60AudioMediaRecorderControl::stop +++"); + + m_session->stop(); + + DP0("S60AudioMediaRecorderControl::stop ---"); +} + +bool S60AudioMediaRecorderControl::isMuted() const +{ + DP0("S60AudioMediaRecorderControl::isMuted"); + + return m_session->muted(); +} + +void S60AudioMediaRecorderControl::setMuted(bool muted) +{ + DP0("S60AudioMediaRecorderControl::setMuted +++"); + + DP1("S60AudioMediaRecorderControl::setMuted:", muted); + + m_session->mute(muted); + + DP0("S60AudioMediaRecorderControl::setMuted +++"); +} diff --git a/src/plugins/symbian/mmf/audiosource/s60audiomediarecordercontrol.h b/src/plugins/symbian/mmf/audiosource/s60audiomediarecordercontrol.h new file mode 100644 index 000000000..78e8f4870 --- /dev/null +++ b/src/plugins/symbian/mmf/audiosource/s60audiomediarecordercontrol.h @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** +****************************************************************************/ + +#ifndef S60AUDIOMEDIARECORDERCONTROL_H +#define S60AUDIOMEDIARECORDERCONTROL_H + +#include <QtCore/qobject.h> +#include <QUrl> + +#include "qmediarecorder.h" +#include "qmediarecordercontrol.h" + +#include "s60audiocapturesession.h" + +QT_USE_NAMESPACE + +//class S60AudioCaptureSession; + +class S60AudioMediaRecorderControl : public QMediaRecorderControl +{ + Q_OBJECT +public: + S60AudioMediaRecorderControl(QObject *session,QObject *parent = 0); + ~S60AudioMediaRecorderControl(); + + QUrl outputLocation() const; + bool setOutputLocation(const QUrl &sink); + + QMediaRecorder::State state() const; + + qint64 duration() const; + + bool isMuted() const; + + void applySettings() {} + +private: + QMediaRecorder::State convertState(S60AudioCaptureSession::TAudioCaptureState aState) const; + +public slots: + void record(); + void pause(); + void stop(); + void setMuted(bool); + +private slots: + void updateState(S60AudioCaptureSession::TAudioCaptureState aState); + +private: + S60AudioCaptureSession* m_session; + QMediaRecorder::State m_state; +}; + +#endif diff --git a/src/plugins/symbian/mmf/inc/DebugMacros.h b/src/plugins/symbian/mmf/inc/DebugMacros.h new file mode 100644 index 000000000..449bef088 --- /dev/null +++ b/src/plugins/symbian/mmf/inc/DebugMacros.h @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** Copyright (C) 2011 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/qdebug.h> + +#ifndef __DEBUGMACROS_H__ +#define __DEBUGMACROS_H__ + +// MACROS +#ifdef _DEBUG +#define DP0(string) qDebug()<<string +#define DP1(string,arg1) qDebug()<<string<<arg1 +#define DP2(string,arg1,arg2) qDebug()<<string<<arg1<<arg2 +#define DP3(string,arg1,arg2,arg3) qDebug()<<string<<arg1<<arg2<<arg3 +#define DP4(string,arg1,arg2,arg3,arg4) qDebug()<<string<<arg1<<arg2<<arg3<<arg4 +#define DP5(string,arg1,arg2,arg3,arg4,arg5) qDebug()<<string<<arg1<<arg2<<arg3<<arg4<<arg5 +#define DP6(string,arg1,arg2,arg3,arg4,arg5,arg6) qDebug()<<string<<arg1<<arg2<<arg3<<arg4<<arg5<<arg6 +#else +#define DP0(string) +#define DP1(string,arg1) +#define DP2(string,arg1,arg2) +#define DP3(string,arg1,arg2,arg3) +#define DP4(string,arg1,arg2,arg3,arg4) +#define DP5(string,arg1,arg2,arg3,arg4,arg5) +#define DP6(string,arg1,arg2,arg3,arg4,arg5,arg6) +#endif + +#endif //__DEBUGMACROS_H__ diff --git a/src/plugins/symbian/mmf/mediaplayer/mediaplayer_s60.pri b/src/plugins/symbian/mmf/mediaplayer/mediaplayer_s60.pri new file mode 100644 index 000000000..6ec64e2b6 --- /dev/null +++ b/src/plugins/symbian/mmf/mediaplayer/mediaplayer_s60.pri @@ -0,0 +1,92 @@ +INCLUDEPATH += $$PWD + +include (../../videooutput/videooutput.pri) + +LIBS *= -lmediaclientvideo \ + -lmediaclientaudio \ + -lws32 \ + -lfbscli \ + -lcone \ + -lmmfcontrollerframework \ + -lefsrv \ + -lbitgdi \ + -lapgrfx \ + -lapmime \ + -lcommdb \ + -lbafl + +# If support to DRM is wanted then comment out the following line +#CONFIG += drm_supported + +# We are building Symbian backend with media player support +DEFINES += HAS_MEDIA_PLAYER +# We are building media player with QVideoRendererControl support +#DEFINES += HAS_VIDEORENDERERCONTROL_IN_VIDEOPLAYER + +drm_supported { + LIBS += -ldrmaudioplayutility + DEFINES += S60_DRM_SUPPORTED +} + +HEADERS += \ + $$PWD/s60mediaplayercontrol.h \ + $$PWD/s60mediaplayerservice.h \ + $$PWD/s60mediaplayersession.h \ + $$PWD/s60mediametadataprovider.h \ + $$PWD/s60videoplayersession.h \ + $$PWD/s60videosurface.h \ + $$PWD/s60mediarecognizer.h \ + $$PWD/s60audioplayersession.h \ + $$PWD/ms60mediaplayerresolver.h \ + $$PWD/s60mediaplayeraudioendpointselector.h \ + $$PWD/s60mediastreamcontrol.h \ + $$PWD/s60medianetworkaccesscontrol.h + +SOURCES += \ + $$PWD/s60mediaplayercontrol.cpp \ + $$PWD/s60mediaplayerservice.cpp \ + $$PWD/s60mediaplayersession.cpp \ + $$PWD/s60mediametadataprovider.cpp \ + $$PWD/s60videoplayersession.cpp \ + $$PWD/s60videosurface.cpp \ + $$PWD/s60mediarecognizer.cpp \ + $$PWD/s60audioplayersession.cpp \ + $$PWD/s60mediaplayeraudioendpointselector.cpp \ + $$PWD/s60mediastreamcontrol.cpp \ + $$PWD/s60medianetworkaccesscontrol.cpp + +contains(DEFINES, HAS_VIDEORENDERERCONTROL_IN_VIDEOPLAYER) { + HEADERS += $$PWD/s60videorenderer.h + SOURCES += $$PWD/s60videorenderer.cpp +} + +contains(S60_VERSION, 3.1) { + #3.1 doesn't provide audio routing in videoplayer + contains(audiorouting_s60_enabled,yes) { + MMP_RULES += "$${LITERAL_HASH}ifndef WINSCW" \ + "MACRO HAS_AUDIOROUTING" \ + "LIBRARY audiooutputrouting.lib" \ + "$${LITERAL_HASH}endif" + message("Note: AudioOutput Routing API not supported for 3.1 winscw target and in videoplayer") + } + +} else { + contains(audiorouting_s60_enabled,yes) { + #We use audiooutputrouting.lib for directing audio output to speaker/earspeaker + DEFINES += HAS_AUDIOROUTING_IN_VIDEOPLAYER + DEFINES += HAS_AUDIOROUTING + message("Audiorouting_s60 enabled for post 3.1 sdk") + LIBS += -laudiooutputrouting + } + +} + +contains(S60_VERSION, 3.1) { + DEFINES += PLAY_RATE_NOT_SUPPORTED + message("S60 version 3.1 does not support setplaybackrate") +} +contains(S60_VERSION, 3.2) { + DEFINES += PLAY_RATE_NOT_SUPPORTED + message("S60 version 3.2 does not support setplaybackrate") +} + diff --git a/src/plugins/symbian/mmf/mediaplayer/ms60mediaplayerresolver.h b/src/plugins/symbian/mmf/mediaplayer/ms60mediaplayerresolver.h new file mode 100644 index 000000000..d836dae3e --- /dev/null +++ b/src/plugins/symbian/mmf/mediaplayer/ms60mediaplayerresolver.h @@ -0,0 +1,54 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** +****************************************************************************/ +#ifndef MS60MEDIAPLAYERRESOLVER_H +#define MS60MEDIAPLAYERRESOLVER_H + +class S60MediaPlayerSession; + +class MS60MediaPlayerResolver +{ + public: + virtual S60MediaPlayerSession* PlayerSession() = 0; + virtual S60MediaPlayerSession* VideoPlayerSession() = 0; + virtual S60MediaPlayerSession* AudioPlayerSession() = 0; +}; + +#endif diff --git a/src/plugins/symbian/mmf/mediaplayer/s60audioplayersession.cpp b/src/plugins/symbian/mmf/mediaplayer/s60audioplayersession.cpp new file mode 100644 index 000000000..3a5386ce1 --- /dev/null +++ b/src/plugins/symbian/mmf/mediaplayer/s60audioplayersession.cpp @@ -0,0 +1,577 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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 "DebugMacros.h" + +#include "s60audioplayersession.h" +#include <QtCore/qdebug.h> +#include <QtCore/qvariant.h> + +/*! + Constructs the CMdaAudioPlayerUtility object with given \a parent QObject. + + And Registers for Audio Loading Notifications. + +*/ + +S60AudioPlayerSession::S60AudioPlayerSession(QObject *parent) + : S60MediaPlayerSession(parent) + , m_player(0) + , m_audioEndpoint("Default") +{ + DP0("S60AudioPlayerSession::S60AudioPlayerSession +++"); + +#ifdef HAS_AUDIOROUTING + m_audioOutput = 0; +#endif //HAS_AUDIOROUTING + QT_TRAP_THROWING(m_player = CAudioPlayer::NewL(*this, 0, EMdaPriorityPreferenceNone)); + m_player->RegisterForAudioLoadingNotification(*this); + + DP0("S60AudioPlayerSession::S60AudioPlayerSession ---"); +} + + +/*! + Destroys the CMdaAudioPlayerUtility object. + + And Unregister the observer. + +*/ + +S60AudioPlayerSession::~S60AudioPlayerSession() +{ + DP0("S60AudioPlayerSession::~S60AudioPlayerSession +++"); +#ifdef HAS_AUDIOROUTING + if (m_audioOutput) + m_audioOutput->UnregisterObserver(*this); + delete m_audioOutput; +#endif + m_player->Close(); + delete m_player; + + DP0("S60AudioPlayerSession::~S60AudioPlayerSession ---"); +} + +/*! + + Opens the a file from \a path. + +*/ + +void S60AudioPlayerSession::doLoadL(const TDesC &path) +{ + DP0("S60AudioPlayerSession::doLoadL +++"); + +#ifdef HAS_AUDIOROUTING + // m_audioOutput needs to be reinitialized after MapcInitComplete + if (m_audioOutput) + m_audioOutput->UnregisterObserver(*this); + delete m_audioOutput; + m_audioOutput = NULL; +#endif //HAS_AUDIOROUTING + m_player->OpenFileL(path); + + DP0("S60AudioPlayerSession::doLoadL ---"); +} + +/*! + + Returns the duration of the audio sample in microseconds. + +*/ + +qint64 S60AudioPlayerSession::doGetDurationL() const +{ + // DP0("S60AudioPlayerSession::doGetDurationL"); + + return m_player->Duration().Int64() / qint64(1000); +} + +/*! + * Returns the current playback position in microseconds from the start of the clip. + +*/ + +qint64 S60AudioPlayerSession::doGetPositionL() const +{ + // DP0("S60AudioPlayerSession::doGetPositionL"); + + TTimeIntervalMicroSeconds ms = 0; + m_player->GetPosition(ms); + return ms.Int64() / qint64(1000); +} + +/*! + Returns TRUE if Video available or else FALSE + */ + +bool S60AudioPlayerSession::isVideoAvailable() +{ + DP0("S60AudioPlayerSession::isVideoAvailable"); + + return false; +} + +/*! + Returns TRUE if Audio available or else FALSE + */ +bool S60AudioPlayerSession::isAudioAvailable() +{ + DP0("S60AudioPlayerSession::isAudioAvailable"); + + return true; // this is a bit happy scenario, but we do emit error that we can't play +} + +/*! + Starts loading Media and sets media status to Buffering. + + */ + +void S60AudioPlayerSession::MaloLoadingStarted() +{ + DP0("S60AudioPlayerSession::MaloLoadingStarted +++"); + + buffering(); + + DP0("S60AudioPlayerSession::MaloLoadingStarted ---"); +} + + +/*! + Indicates loading Media is completed. + + And sets media status to Buffered. + + */ + +void S60AudioPlayerSession::MaloLoadingComplete() +{ + DP0("S60AudioPlayerSession::MaloLoadingComplete +++"); + + buffered(); + + DP0("S60AudioPlayerSession::MaloLoadingComplete ---"); +} + +/*! + Start or resume playing the current source. +*/ + +void S60AudioPlayerSession::doPlay() +{ + DP0("S60AudioPlayerSession::doPlay +++"); + + // For some reason loading progress callback are not called on emulator + // Same is the case with hardware. Will be fixed as part of QTMOBILITY-782. + + //#ifdef __WINSCW__ + buffering(); + //#endif + m_player->Play(); + //#ifdef __WINSCW__ + buffered(); + //#endif + + DP0("S60AudioPlayerSession::doPlay ---"); +} + + +/*! + Pause playing the current source. +*/ + + +void S60AudioPlayerSession::doPauseL() +{ + DP0("S60AudioPlayerSession::doPauseL +++"); + + m_player->Pause(); + + DP0("S60AudioPlayerSession::doPauseL ---"); +} + + +/*! + + Stop playing, and reset the play position to the beginning. +*/ + +void S60AudioPlayerSession::doStop() +{ + DP0("S60AudioPlayerSession::doStop +++"); + + m_player->Stop(); + + DP0("S60AudioPlayerSession::doStop ---"); +} + +/*! + Closes the current audio clip (allowing another clip to be opened) +*/ + +void S60AudioPlayerSession::doClose() +{ + DP0("S60AudioPlayerSession::doClose +++"); + +#ifdef HAS_AUDIOROUTING + if (m_audioOutput) { + m_audioOutput->UnregisterObserver(*this); + delete m_audioOutput; + m_audioOutput = NULL; + } +#endif + m_player->Close(); + + DP0("S60AudioPlayerSession::doClose ---"); +} + +/*! + + Changes the current playback volume to specified \a value. +*/ + +void S60AudioPlayerSession::doSetVolumeL(int volume) +{ + DP0("S60AudioPlayerSession::doSetVolumeL +++"); + + DP1("S60AudioPlayerSession::doSetVolumeL, Volume:", volume); + + m_player->SetVolume(volume * m_player->MaxVolume() / 100); + + DP0("S60AudioPlayerSession::doSetVolumeL ---"); +} + +/*! + Sets the current playback position to \a microSeconds from the start of the clip. +*/ + +void S60AudioPlayerSession::doSetPositionL(qint64 microSeconds) +{ + DP0("S60AudioPlayerSession::doSetPositionL +++"); + + DP1("S60AudioPlayerSession::doSetPositionL, Microseconds:", microSeconds); + + m_player->SetPosition(TTimeIntervalMicroSeconds(microSeconds)); + + DP0("S60AudioPlayerSession::doSetPositionL ---"); +} + +/*! + + Updates meta data entries in the current audio clip. +*/ + +void S60AudioPlayerSession::updateMetaDataEntriesL() +{ + DP0("S60AudioPlayerSession::updateMetaDataEntriesL +++"); + + metaDataEntries().clear(); + int numberOfMetaDataEntries = 0; + + //User::LeaveIfError(m_player->GetNumberOfMetaDataEntries(numberOfMetaDataEntries)); + m_player->GetNumberOfMetaDataEntries(numberOfMetaDataEntries); + + for (int i = 0; i < numberOfMetaDataEntries; i++) { + CMMFMetaDataEntry *entry = NULL; + entry = m_player->GetMetaDataEntryL(i); + metaDataEntries().insert(QString::fromUtf16(entry->Name().Ptr(), entry->Name().Length()), QString::fromUtf16(entry->Value().Ptr(), entry->Value().Length())); + delete entry; + } + emit metaDataChanged(); + + DP0("S60AudioPlayerSession::updateMetaDataEntriesL ---"); +} + +/*! + Sets the playbackRate with \a rate. +*/ + +void S60AudioPlayerSession::setPlaybackRate(qreal rate) +{ + DP0("S60AudioPlayerSession::setPlaybackRate +++"); + DP1("S60AudioPlayerSession::setPlaybackRate, Rate:", rate); + /*Since AudioPlayerUtility doesn't support set playback rate hence + * setPlaybackRate emits playbackRateChanged signal for 1.0x ie normal playback. + * For all other playBackRates it sets and emits error signal. + */ + if (rate == 1.0) { + emit playbackRateChanged(rate); + return; + } else { + int err = KErrNotSupported; + setAndEmitError(err); + } + DP0("S60AudioPlayerSession::setPlaybackRate ---"); +} + +/*! + + Returns the percentage of the audio clip loaded. +*/ + +int S60AudioPlayerSession::doGetBufferStatusL() const +{ + DP0("S60AudioPlayerSession::doGetBufferStatusL +++"); + + int progress = 0; + m_player->GetAudioLoadingProgressL(progress); + + DP0("S60AudioPlayerSession::doGetBufferStatusL ---"); + + return progress; +} + +/*! + + Defines required client behaviour when an attempt to open and initialise an audio sample has completed, + successfully or not. + + \a aError if KErrNone the sample is ready to play or else system wide error. + + \a aDuration The duration of the audio sample. +*/ + +#ifdef S60_DRM_SUPPORTED +void S60AudioPlayerSession::MdapcInitComplete(TInt aError, const TTimeIntervalMicroSeconds& aDuration) +#else +void S60AudioPlayerSession::MapcInitComplete(TInt aError, const TTimeIntervalMicroSeconds& aDuration) +#endif +{ + DP0("S60AudioPlayerSession::MdapcInitComplete +++"); + + DP1("S60AudioPlayerSession::MdapcInitComplete - aError", aError); + + Q_UNUSED(aDuration); + setError(aError); + if (KErrNone != aError) + return; +#ifdef HAS_AUDIOROUTING + TRAPD(err, + m_audioOutput = CAudioOutput::NewL(*m_player); + m_audioOutput->RegisterObserverL(*this); + ); + setActiveEndpoint(m_audioEndpoint); + setError(err); +#endif //HAS_AUDIOROUTING + if (KErrNone == aError) + loaded(); + + DP0("S60AudioPlayerSession::MdapcInitComplete ---"); +} + +/*! + Defines required client behaviour when an attempt to playback an audio sample has completed, + successfully or not. + + \a aError if KErrNone the playback completed or else system wide error. +*/ + + +#ifdef S60_DRM_SUPPORTED +void S60AudioPlayerSession::MdapcPlayComplete(TInt aError) +#else +void S60AudioPlayerSession::MapcPlayComplete(TInt aError) +#endif +{ + DP0("S60AudioPlayerSession::MdapcPlayComplete +++"); + + DP1("S60AudioPlayerSession::MdapcPlayComplete", aError); + + if (KErrNone == aError) + endOfMedia(); + else + setError(aError); + + DP0("S60AudioPlayerSession::MdapcPlayComplete ---"); +} + +/*! + Defiens which Audio End point to use. + + \a audioEndpoint audioEndpoint name. +*/ + +void S60AudioPlayerSession::doSetAudioEndpoint(const QString& audioEndpoint) +{ + DP0("S60AudioPlayerSession::doSetAudioEndpoint +++"); + + DP1("S60AudioPlayerSession::doSetAudioEndpoint - ", audioEndpoint); + + m_audioEndpoint = audioEndpoint; + + DP0("S60AudioPlayerSession::doSetAudioEndpoint ---"); +} + +/*! + + Returns audioEndpoint name. +*/ + +QString S60AudioPlayerSession::activeEndpoint() const +{ + DP0("S60AudioPlayerSession::activeEndpoint +++"); + + QString outputName = QString("Default"); +#ifdef HAS_AUDIOROUTING + if (m_audioOutput) { + CAudioOutput::TAudioOutputPreference output = m_audioOutput->AudioOutput(); + outputName = qStringFromTAudioOutputPreference(output); + } +#endif + DP1("S60AudioPlayerSession::activeEndpoint is :", outputName); + + DP0("S60AudioPlayerSession::activeEndpoint ---"); + return outputName; +} + +/*! + * Returns default Audio End point in use. +*/ + +QString S60AudioPlayerSession::defaultEndpoint() const +{ + DP0("S60AudioPlayerSession::defaultEndpoint +++"); + + QString outputName = QString("Default"); +#ifdef HAS_AUDIOROUTING + if (m_audioOutput) { + CAudioOutput::TAudioOutputPreference output = m_audioOutput->DefaultAudioOutput(); + outputName = qStringFromTAudioOutputPreference(output); + } +#endif + DP1("S60AudioPlayerSession::defaultEndpoint is :", outputName); + + DP0("S60AudioPlayerSession::defaultEndpoint ---"); + return outputName; +} + +/*! + Sets active end \a name as an Audio End point. +*/ + +void S60AudioPlayerSession::setActiveEndpoint(const QString& name) +{ + DP0("S60AudioPlayerSession::setActiveEndpoint +++"); + + DP1("S60AudioPlayerSession::setActiveEndpoint - ", name); + +#ifdef HAS_AUDIOROUTING + CAudioOutput::TAudioOutputPreference output = CAudioOutput::ENoPreference; + + if (name == QString("Default")) + output = CAudioOutput::ENoPreference; + else if (name == QString("All")) + output = CAudioOutput::EAll; + else if (name == QString("None")) + output = CAudioOutput::ENoOutput; + else if (name == QString("Earphone")) + output = CAudioOutput::EPrivate; + else if (name == QString("Speaker")) + output = CAudioOutput::EPublic; + + if (m_audioOutput) { + TRAPD(err, m_audioOutput->SetAudioOutputL(output)); + setError(err); + } +#endif + + DP0("S60AudioPlayerSession::setActiveEndpoint ---"); +} + +/*! + The default audio output has been changed. + + \a aAudioOutput Audio Output object. + + \a aNewDefault is CAudioOutput::TAudioOutputPreference. +*/ + + +#ifdef HAS_AUDIOROUTING +void S60AudioPlayerSession::DefaultAudioOutputChanged(CAudioOutput& aAudioOutput, + CAudioOutput::TAudioOutputPreference aNewDefault) +{ + DP0("S60AudioPlayerSession::DefaultAudioOutputChanged +++"); + + // Emit already implemented in setActiveEndpoint function + Q_UNUSED(aAudioOutput) + Q_UNUSED(aNewDefault) + + DP0("S60AudioPlayerSession::DefaultAudioOutputChanged ---"); +} + + +/*! + Converts CAudioOutput::TAudioOutputPreference enum to QString. + + \a output is CAudioOutput::TAudioOutputPreference enum value. + +*/ + +QString S60AudioPlayerSession::qStringFromTAudioOutputPreference(CAudioOutput::TAudioOutputPreference output) const +{ + DP0("S60AudioPlayerSession::qStringFromTAudioOutputPreference"); + + if (output == CAudioOutput::ENoPreference) + return QString("Default"); + else if (output == CAudioOutput::EAll) + return QString("All"); + else if (output == CAudioOutput::ENoOutput) + return QString("None"); + else if (output == CAudioOutput::EPrivate) + return QString("Earphone"); + else if (output == CAudioOutput::EPublic) + return QString("Speaker"); + return QString("Default"); +} +#endif + +/*! + Return True if its Seekable or else False. +*/ + +bool S60AudioPlayerSession::getIsSeekable() const +{ + DP0("S60AudioPlayerSession::getIsSeekable"); + + return ETrue; +} + diff --git a/src/plugins/symbian/mmf/mediaplayer/s60audioplayersession.h b/src/plugins/symbian/mmf/mediaplayer/s60audioplayersession.h new file mode 100644 index 000000000..80228ef0a --- /dev/null +++ b/src/plugins/symbian/mmf/mediaplayer/s60audioplayersession.h @@ -0,0 +1,136 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** +****************************************************************************/ + +#ifndef S60AUDIOPLAYERSESSION_H +#define S60AUDIOPLAYERSESSION_H + +#include <QtCore/qobject.h> +#include "s60mediaplayersession.h" + +#ifdef S60_DRM_SUPPORTED +#include <drmaudiosampleplayer.h> +typedef CDrmPlayerUtility CAudioPlayer; +typedef MDrmAudioPlayerCallback MAudioPlayerObserver; +#else +#include <mdaaudiosampleplayer.h> +typedef CMdaAudioPlayerUtility CAudioPlayer; +typedef MMdaAudioPlayerCallback MAudioPlayerObserver; +#endif + +#ifdef HAS_AUDIOROUTING +#include <AudioOutput.h> +#include <MAudioOutputObserver.h> +#endif //HAS_AUDIOROUTING + +class S60AudioPlayerSession : public S60MediaPlayerSession + , public MAudioPlayerObserver + , public MAudioLoadingObserver +#ifdef HAS_AUDIOROUTING + , public MAudioOutputObserver +#endif +{ + Q_OBJECT +public: + S60AudioPlayerSession(QObject *parent); + ~S60AudioPlayerSession(); + + //From S60MediaPlayerSession + bool isVideoAvailable(); + bool isAudioAvailable(); + + // From MAudioLoadingObserver + void MaloLoadingStarted(); + void MaloLoadingComplete(); + +#ifdef HAS_AUDIOROUTING + // From MAudioOutputObserver + void DefaultAudioOutputChanged( CAudioOutput& aAudioOutput, + CAudioOutput::TAudioOutputPreference aNewDefault ); +#endif //HAS_AUDIOROUTING + +public: + // From S60MediaPlayerAudioEndpointSelector + QString activeEndpoint() const; + QString defaultEndpoint() const; + void setPlaybackRate(qreal rate); +public Q_SLOTS: + void setActiveEndpoint(const QString& name); + +protected: + //From S60MediaPlayerSession + void doLoadL(const TDesC &path); + void doLoadUrlL(const TDesC &path){Q_UNUSED(path)/*empty implementation*/} + void doPlay(); + void doStop(); + void doClose(); + void doPauseL(); + void doSetVolumeL(int volume); + qint64 doGetPositionL() const; + void doSetPositionL(qint64 microSeconds); + void updateMetaDataEntriesL(); + int doGetBufferStatusL() const; + qint64 doGetDurationL() const; + void doSetAudioEndpoint(const QString& audioEndpoint); + bool getIsSeekable() const; +private: +#ifdef S60_DRM_SUPPORTED + // From MMdaAudioPlayerCallback + void MdapcInitComplete(TInt aError, const TTimeIntervalMicroSeconds& aDuration); + void MdapcPlayComplete(TInt aError); +#else + // From MDrmAudioPlayerCallback + void MapcInitComplete(TInt aError, const TTimeIntervalMicroSeconds& aDuration); + void MapcPlayComplete(TInt aError); +#endif + +#ifdef HAS_AUDIOROUTING + QString qStringFromTAudioOutputPreference(CAudioOutput::TAudioOutputPreference output) const; +#endif //HAS_AUDIOROUTING + +private: + CAudioPlayer *m_player; +#ifdef HAS_AUDIOROUTING + CAudioOutput *m_audioOutput; +#endif //HAS_AUDIOROUTING + QString m_audioEndpoint; +}; + +#endif diff --git a/src/plugins/symbian/mmf/mediaplayer/s60mediametadataprovider.cpp b/src/plugins/symbian/mmf/mediaplayer/s60mediametadataprovider.cpp new file mode 100644 index 000000000..85bfe65a3 --- /dev/null +++ b/src/plugins/symbian/mmf/mediaplayer/s60mediametadataprovider.cpp @@ -0,0 +1,146 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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 "DebugMacros.h" + +#include "s60mediametadataprovider.h" +#include "s60mediaplayercontrol.h" +#include "s60mediaplayersession.h" +#include <QtCore/qdebug.h> + +/*! + * Typecasts the \a control object to S60MediaPlayerControl object. +*/ +S60MediaMetaDataProvider::S60MediaMetaDataProvider(QObject *control, QObject *parent) + : QMetaDataReaderControl(parent) + , m_control(NULL) +{ + DP0("S60MediaMetaDataProvider::S60MediaMetaDataProvider +++"); + + m_control = qobject_cast<S60MediaPlayerControl*>(control); + + DP0("S60MediaMetaDataProvider::S60MediaMetaDataProvider ---"); +} + +/*! + * Destructor +*/ + +S60MediaMetaDataProvider::~S60MediaMetaDataProvider() +{ + DP0("S60MediaMetaDataProvider::~S60MediaMetaDataProvider +++"); + DP0("S60MediaMetaDataProvider::~S60MediaMetaDataProvider ---"); +} + +/*! + * Returns TRUE if MetaData is Available or else FALSE. +*/ + +bool S60MediaMetaDataProvider::isMetaDataAvailable() const +{ + DP0("S60MediaMetaDataProvider::isMetaDataAvailable"); + + if (m_control->session()) + return m_control->session()->isMetadataAvailable(); + return false; +} + +/*! + * Always returns FLASE. +*/ +bool S60MediaMetaDataProvider::isWritable() const +{ + DP0("S60MediaMetaDataProvider::isWritable"); + + return false; +} + +/*! + * Returns when \a key meta data is found in metaData. +*/ + +QVariant S60MediaMetaDataProvider::metaData(QtMultimediaKit::MetaData key) const +{ + DP0("S60MediaMetaDataProvider::metaData"); + + if (m_control->session()) + return m_control->session()->metaData(key); + return QVariant(); +} + +/*! + * Returns available metaData. +*/ + +QList<QtMultimediaKit::MetaData> S60MediaMetaDataProvider::availableMetaData() const +{ + DP0("S60MediaMetaDataProvider::availableMetaData"); + + if (m_control->session()) + return m_control->session()->availableMetaData(); + return QList<QtMultimediaKit::MetaData>(); +} + +/*! + * Returns when \a key string is found in extended metaData. +*/ + +QVariant S60MediaMetaDataProvider::extendedMetaData(const QString &key) const +{ + DP0("S60MediaMetaDataProvider::extendedMetaData"); + + if (m_control->session()) + return m_control->session()->metaData(key); + return QVariant(); +} + +/*! + * Returns available Extended MetaData. +*/ + +QStringList S60MediaMetaDataProvider::availableExtendedMetaData() const +{ + DP0("S60MediaMetaDataProvider::availableExtendedMetaData"); + + if (m_control->session()) + return m_control->session()->availableExtendedMetaData(); + return QStringList(); +} diff --git a/src/plugins/symbian/mmf/mediaplayer/s60mediametadataprovider.h b/src/plugins/symbian/mmf/mediaplayer/s60mediametadataprovider.h new file mode 100644 index 000000000..eb995080d --- /dev/null +++ b/src/plugins/symbian/mmf/mediaplayer/s60mediametadataprovider.h @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** +****************************************************************************/ + +#ifndef S60MEDIAMETADATAPROVIDER_H +#define S60MEDIAMETADATAPROVIDER_H + +#include <qmetadatareadercontrol.h> +#include "s60mediaplayercontrol.h" + +QT_USE_NAMESPACE + +class S60MediaPlayerControl; + +class S60MediaMetaDataProvider : public QMetaDataReaderControl +{ + Q_OBJECT + +public: + S60MediaMetaDataProvider(QObject *control, QObject *parent = 0); + ~S60MediaMetaDataProvider(); + + bool isMetaDataAvailable() const; + bool isWritable() const; + + QVariant metaData(QtMultimediaKit::MetaData key) const; + QList<QtMultimediaKit::MetaData> availableMetaData() const; + QVariant extendedMetaData(const QString &key) const ; + QStringList availableExtendedMetaData() const; + +private: + S60MediaPlayerControl *m_control; +}; + +#endif // S60VIDEOMETADATAPROVIDER_H diff --git a/src/plugins/symbian/mmf/mediaplayer/s60medianetworkaccesscontrol.cpp b/src/plugins/symbian/mmf/mediaplayer/s60medianetworkaccesscontrol.cpp new file mode 100644 index 000000000..dad69a691 --- /dev/null +++ b/src/plugins/symbian/mmf/mediaplayer/s60medianetworkaccesscontrol.cpp @@ -0,0 +1,144 @@ +/**************************************************************************** +** +** Copyright (C) 2011 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 "s60medianetworkaccesscontrol.h" + +#define KBuffersize 512 + +S60MediaNetworkAccessControl::S60MediaNetworkAccessControl(QObject *parent) + : QMediaNetworkAccessControl(parent) + , m_iapId(KUseDefaultIap) + , m_currentIndex(0) +{ +} + +void S60MediaNetworkAccessControl::accessPointChanged(int id) +{ + if (!m_IapIdList.isEmpty()) + m_NetworkObject = m_NetworkObjectList.at(m_IapIdList.indexOf(id)); + emit configurationChanged(m_NetworkObject); +} + +S60MediaNetworkAccessControl::~S60MediaNetworkAccessControl() +{ + m_NetworkObjectList.clear(); + m_IapIdList.clear(); +} + +void S60MediaNetworkAccessControl::resetIndex() +{ + m_currentIndex = 0; +} + +void S60MediaNetworkAccessControl::setConfigurations(const QList<QNetworkConfiguration> &configurations) +{ + if (!configurations.isEmpty()) { + m_currentIndex =0; + TRAPD(error, retriveAccesspointIDL(configurations)); + if (error != KErrNone) { + m_NetworkObjectList.clear(); + m_IapIdList.clear(); + } + } +} + +TBool S60MediaNetworkAccessControl::isLastAccessPoint() +{ + if (m_currentIndex == m_NetworkObjectList.size()) + return TRUE; + else + return FALSE; +} + +int S60MediaNetworkAccessControl::accessPointId() +{ + if (m_IapIdList.isEmpty()) + return m_iapId; + + m_iapId = m_IapIdList.at(m_currentIndex); + + if (isLastAccessPoint()) + m_currentIndex = 0; + else + m_currentIndex ++; + + return m_iapId; +} + +QNetworkConfiguration S60MediaNetworkAccessControl::currentConfiguration() const +{ + return m_NetworkObject; +} + +void S60MediaNetworkAccessControl::retriveAccesspointIDL(const QList<QNetworkConfiguration> &configurationList) +{ + m_NetworkObjectList.clear(); + m_IapIdList.clear(); + TBuf<KBuffersize> iapName; + TUint32 iapId; + TInt err; + + // open the IAP communications database + CCommsDatabase* commDB = CCommsDatabase::NewL(); + CleanupStack::PushL(commDB); + + // Open the IAP table + CCommsDbTableView* view = commDB->OpenTableLC(TPtrC(IAP)); + + for (int i=0;i<=configurationList.size()- 1;i++) { + QString accesspointname = configurationList.at(i).name(); + TBuf<KBuffersize> accesspointbuffer(accesspointname.utf16()); + // Point to the first entry + if (view->GotoFirstRecord() == KErrNone) { + do { + view->ReadTextL(TPtrC(COMMDB_NAME), iapName); + view->ReadUintL(TPtrC(COMMDB_ID), iapId); + if (accesspointbuffer == iapName) { + m_NetworkObjectList<<configurationList.at(i); + m_IapIdList<<iapId; + } + // Store name and ID to where you want to + } while (err = view->GotoNextRecord(), err == KErrNone); + } + } + CleanupStack::PopAndDestroy(); // view + CleanupStack::PopAndDestroy(); // commDB +} diff --git a/src/plugins/symbian/mmf/mediaplayer/s60medianetworkaccesscontrol.h b/src/plugins/symbian/mmf/mediaplayer/s60medianetworkaccesscontrol.h new file mode 100644 index 000000000..aea4dcab5 --- /dev/null +++ b/src/plugins/symbian/mmf/mediaplayer/s60medianetworkaccesscontrol.h @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** Copyright (C) 2011 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$ +** +****************************************************************************/ + +#ifndef S60MEDIANETWORKACCESSCONTROL_H_ +#define S60MEDIANETWORKACCESSCONTROL_H_ + + +#include <QtCore/qobject.h> +#include <QtCore/qlist.h> +#include <QtCore/qstring.h> +#include <qmetaobject.h> +#include <QtNetwork/qnetworkconfiguration.h> +#include <commdbconnpref.h> +#include <commdb.h> +#include <mmf/common/mmfcontrollerframeworkbase.h> +#include <qmedianetworkaccesscontrol.h> +#include "s60mediaplayercontrol.h" + +QT_BEGIN_NAMESPACE +class QMediaPlayerControl; +class QMediaNetworkAccessControl; +class QNetworkConfiguration; +QT_END_NAMESPACE + +class S60MediaNetworkAccessControl : public QMediaNetworkAccessControl +{ + Q_OBJECT + +public: + + S60MediaNetworkAccessControl(QObject *parent = 0); + ~S60MediaNetworkAccessControl(); + + virtual void setConfigurations(const QList<QNetworkConfiguration> &configurations); + virtual QNetworkConfiguration currentConfiguration() const; + int accessPointId(); + TBool isLastAccessPoint(); + void resetIndex(); + +public Q_SLOTS: + void accessPointChanged(int); + +private: + void retriveAccesspointIDL(const QList<QNetworkConfiguration> &); + QList<int> m_IapIdList; + QList<QNetworkConfiguration> m_NetworkObjectList; + QNetworkConfiguration m_NetworkObject; + int m_iapId; + int m_currentIndex; +}; +#endif /* S60MEDIANETWORKACCESSCONTROL_H_ */ diff --git a/src/plugins/symbian/mmf/mediaplayer/s60mediaplayeraudioendpointselector.cpp b/src/plugins/symbian/mmf/mediaplayer/s60mediaplayeraudioendpointselector.cpp new file mode 100644 index 000000000..3ad64ef3b --- /dev/null +++ b/src/plugins/symbian/mmf/mediaplayer/s60mediaplayeraudioendpointselector.cpp @@ -0,0 +1,182 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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 "DebugMacros.h" + +#include "s60mediaplayercontrol.h" +#include "s60mediaplayersession.h" +#include "s60mediaplayeraudioendpointselector.h" + +#include <QtGui/QIcon> +#include <QtCore/QDebug> + +/*! + Constructs a new audio endpoint selector with the given \a parent. +*/ + +S60MediaPlayerAudioEndpointSelector::S60MediaPlayerAudioEndpointSelector(QObject *control, QObject *parent) + :QAudioEndpointSelector(parent) + , m_control(0) +{ + DP0("S60MediaPlayerAudioEndpointSelector::S60MediaPlayerAudioEndpointSelector +++"); + + m_control = qobject_cast<S60MediaPlayerControl*>(control); + m_audioEndpointNames.append("Default"); + m_audioEndpointNames.append("All"); + m_audioEndpointNames.append("None"); + m_audioEndpointNames.append("Earphone"); + m_audioEndpointNames.append("Speaker"); + + DP0("S60MediaPlayerAudioEndpointSelector::S60MediaPlayerAudioEndpointSelector ---"); +} + +/*! + Destroys an audio endpoint selector. +*/ + +S60MediaPlayerAudioEndpointSelector::~S60MediaPlayerAudioEndpointSelector() +{ + DP0("S60MediaPlayerAudioEndpointSelector::~S60MediaPlayerAudioEndpointSelector +++"); + DP0("S60MediaPlayerAudioEndpointSelector::~S60MediaPlayerAudioEndpointSelector ---"); +} + +/*! + \return a list of available audio endpoints. +*/ + +QList<QString> S60MediaPlayerAudioEndpointSelector::availableEndpoints() const +{ + DP0("S60MediaPlayerAudioEndpointSelector::availableEndpoints"); + + return m_audioEndpointNames; +} + +/*! + \return the description of the endpoint name. +*/ + +QString S60MediaPlayerAudioEndpointSelector::endpointDescription(const QString& name) const +{ + DP0("S60MediaPlayerAudioEndpointSelector::endpointDescription"); + + if (name == QString("Default")) //ENoPreference + return QString("Used to indicate that the playing audio can be routed to" + "any speaker. This is the default value for audio."); + else if (name == QString("All")) //EAll + return QString("Used to indicate that the playing audio should be routed to all speakers."); + else if (name == QString("None")) //ENoOutput + return QString("Used to indicate that the playing audio should not be routed to any output."); + else if (name == QString("Earphone")) //EPrivate + return QString("Used to indicate that the playing audio should be routed to" + "the default private speaker. A private speaker is one that can only" + "be heard by one person."); + else if (name == QString("Speaker")) //EPublic + return QString("Used to indicate that the playing audio should be routed to" + "the default public speaker. A public speaker is one that can " + "be heard by multiple people."); + + return QString(); +} + +/*! + \return the name of the currently selected audio endpoint. +*/ + +QString S60MediaPlayerAudioEndpointSelector::activeEndpoint() const +{ + DP0("S60MediaPlayerAudioEndpointSelector::activeEndpoint"); + + if (m_control->session()) { + DP1("S60MediaPlayerAudioEndpointSelector::activeEndpoint - ", + m_control->session()->activeEndpoint()); + return m_control->session()->activeEndpoint(); + } + else { + DP1("S60MediaPlayerAudioEndpointSelector::activeEndpoint - ", + m_control->mediaControlSettings().audioEndpoint()); + return m_control->mediaControlSettings().audioEndpoint(); + } +} + +/*! + \return the name of the default audio endpoint. +*/ + +QString S60MediaPlayerAudioEndpointSelector::defaultEndpoint() const +{ + DP0("S60MediaPlayerAudioEndpointSelector::defaultEndpoint"); + + if (m_control->session()) { + DP1("S60MediaPlayerAudioEndpointSelector::defaultEndpoint - ", + m_control->session()->defaultEndpoint()); + return m_control->session()->defaultEndpoint(); + } + else { + DP1("S60MediaPlayerAudioEndpointSelector::defaultEndpoint - ", + m_control->mediaControlSettings().audioEndpoint()); + return m_control->mediaControlSettings().audioEndpoint(); + } +} + +/*! + Set the audio endpoint to \a name. +*/ + +void S60MediaPlayerAudioEndpointSelector::setActiveEndpoint(const QString& name) +{ + DP0("S60MediaPlayerAudioEndpointSelector::setActiveEndpoin +++"); + + DP1("S60MediaPlayerAudioEndpointSelector::setActiveEndpoint - ", name); + + QString oldEndpoint = m_control->mediaControlSettings().audioEndpoint(); + + if (name != oldEndpoint && (name == QString("Default") || name == QString("All") || + name == QString("None") || name == QString("Earphone") || name == QString("Speaker"))) { + + if (m_control->session()) { + m_control->session()->setActiveEndpoint(name); + emit activeEndpointChanged(name); + } + m_control->setAudioEndpoint(name); + } + + DP0("S60MediaPlayerAudioEndpointSelector::setActiveEndpoin ---"); +} diff --git a/src/plugins/symbian/mmf/mediaplayer/s60mediaplayeraudioendpointselector.h b/src/plugins/symbian/mmf/mediaplayer/s60mediaplayeraudioendpointselector.h new file mode 100644 index 000000000..eff49d47a --- /dev/null +++ b/src/plugins/symbian/mmf/mediaplayer/s60mediaplayeraudioendpointselector.h @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** +****************************************************************************/ + +#ifndef S60MEDIAPLAYERAUDIOENDPOINTSELECTOR_H +#define S60MEDIAPLAYERAUDIOENDPOINTSELECTOR_H + +#include <QStringList> + +#include <qaudioendpointselector.h> + +QT_USE_NAMESPACE + +class S60MediaPlayerControl; +class S60MediaPlayerSession; + +class S60MediaPlayerAudioEndpointSelector : public QAudioEndpointSelector +{ + +Q_OBJECT + +public: + S60MediaPlayerAudioEndpointSelector(QObject *control, QObject *parent = 0); + ~S60MediaPlayerAudioEndpointSelector(); + + QList<QString> availableEndpoints() const ; + QString endpointDescription(const QString& name) const; + QString defaultEndpoint() const; + QString activeEndpoint() const; + +public Q_SLOTS: + void setActiveEndpoint(const QString& name); + +private: + S60MediaPlayerControl* m_control; + QString m_audioInput; + QList<QString> m_audioEndpointNames; +}; + +#endif // S60MEDIAPLAYERAUDIOENDPOINTSELECTOR_H diff --git a/src/plugins/symbian/mmf/mediaplayer/s60mediaplayercontrol.cpp b/src/plugins/symbian/mmf/mediaplayer/s60mediaplayercontrol.cpp new file mode 100644 index 000000000..2eeceedd8 --- /dev/null +++ b/src/plugins/symbian/mmf/mediaplayer/s60mediaplayercontrol.cpp @@ -0,0 +1,518 @@ + +/**************************************************************************** +** +** Copyright (C) 2010 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 "DebugMacros.h" + +#include "s60mediaplayercontrol.h" +#include "s60mediaplayersession.h" + +#include <QtCore/qdir.h> +#include <QtCore/qurl.h> +#include <QtCore/qdebug.h> + +/*! + Constructs a new media player control with the given \a parent. +*/ + +S60MediaPlayerControl::S60MediaPlayerControl(MS60MediaPlayerResolver& mediaPlayerResolver, QObject *parent) + : QMediaPlayerControl(parent), + m_mediaPlayerResolver(mediaPlayerResolver), + m_session(NULL), + m_stream(NULL) +{ + DP0("S60MediaPlayerControl::S60MediaPlayerControl +++"); + + DP0("S60MediaPlayerControl::S60MediaPlayerControl ---"); + +} + +/*! + Destroys a media player control. +*/ + +S60MediaPlayerControl::~S60MediaPlayerControl() +{ + DP0("S60MediaPlayerControl::~S60MediaPlayerControl +++"); + DP0("S60MediaPlayerControl::~S60MediaPlayerControl ---"); +} + +/*! + \return the current playback position in milliseconds. +*/ + +qint64 S60MediaPlayerControl::position() const +{ + // DP0("S60MediaPlayerControl::position"); + + if (m_session) + return m_session->position(); + return 0; +} + +/*! + \return the duration of the current media in milliseconds. +*/ + +qint64 S60MediaPlayerControl::duration() const +{ + // DP0("S60MediaPlayerControl::duration"); + + if (m_session) + return m_session->duration(); + return -1; +} + +/*! + \return the state of a player control. +*/ + +QMediaPlayer::State S60MediaPlayerControl::state() const +{ + DP0("S60MediaPlayerControl::state"); + + if (m_session) + return m_session->state(); + return QMediaPlayer::StoppedState; +} + +/*! + \return the status of the current media. +*/ + +QMediaPlayer::MediaStatus S60MediaPlayerControl::mediaStatus() const +{ + DP0("QMediaPlayer::mediaStatus"); + + if (m_session) + return m_session->mediaStatus(); + return m_mediaSettings.mediaStatus(); +} + +/*! + \return the buffering progress of the current media. Progress is measured in the percentage + of the buffer filled. +*/ + +int S60MediaPlayerControl::bufferStatus() const +{ + // DP0("S60MediaPlayerControl::bufferStatus"); + + if (m_session) + return m_session->bufferStatus(); + return 0; +} + +/*! + \return the audio volume of a player control. +*/ + +int S60MediaPlayerControl::volume() const +{ + DP0("S60MediaPlayerControl::volume"); + + if (m_session) + return m_session->volume(); + return m_mediaSettings.volume(); +} + +/*! + \return the mute state of a player control. +*/ + +bool S60MediaPlayerControl::isMuted() const +{ + DP0("S60MediaPlayerControl::isMuted"); + + if (m_session) + return m_session->isMuted(); + return m_mediaSettings.isMuted(); +} + +/*! + Identifies if the current media is seekable. + + \return true if it possible to seek within the current media, and false otherwise. +*/ + +bool S60MediaPlayerControl::isSeekable() const +{ + DP0("S60MediaPlayerControl::isSeekable"); + + if (m_session) + return m_session->isSeekable(); + return false; +} + +/*! + \return a range of times in milliseconds that can be played back. + + Usually for local files this is a continuous interval equal to [0..duration()] + or an empty time range if seeking is not supported, but for network sources + it refers to the buffered parts of the media. +*/ + +QMediaTimeRange S60MediaPlayerControl::availablePlaybackRanges() const +{ + DP0("S60MediaPlayerControl::availablePlaybackRanges"); + + QMediaTimeRange ranges; + + if(m_session && m_session->isSeekable()) + ranges.addInterval(0, m_session->duration()); + + return ranges; +} + +/*! + \return the rate of playback. +*/ + +qreal S60MediaPlayerControl::playbackRate() const +{ + DP0("S60MediaPlayerControl::playbackRate"); + + return m_mediaSettings.playbackRate(); +} + +/*! + Sets the \a rate of playback. +*/ + +void S60MediaPlayerControl::setPlaybackRate(qreal rate) +{ + DP0("S60MediaPlayerControl::setPlaybackRate +++"); + + DP1("S60MediaPlayerControl::setPlaybackRate - ", rate); + + //getting the current playbackrate + qreal currentPBrate = m_mediaSettings.playbackRate(); + //checking if we need to change the Playback rate + if (!qFuzzyCompare(currentPBrate,rate)) + { + if(m_session) + m_session->setPlaybackRate(rate); + + m_mediaSettings.setPlaybackRate(rate); + } + + DP0("S60MediaPlayerControl::setPlaybackRate ---"); +} + +/*! + Sets the playback \a pos of the current media. This will initiate a seek and it may take + some time for playback to reach the position set. +*/ + +void S60MediaPlayerControl::setPosition(qint64 pos) +{ + DP0("S60MediaPlayerControl::setPosition +++"); + + DP1("S60MediaPlayerControl::setPosition, Position:", pos); + + if (m_session) + m_session->setPosition(pos); + + DP0("S60MediaPlayerControl::setPosition ---"); +} + +/*! + Starts playback of the current media. + + If successful the player control will immediately enter the \l {QMediaPlayer::PlayingState} + {playing} state. +*/ + +void S60MediaPlayerControl::play() +{ + DP0("S60MediaPlayerControl::play +++"); + + if (m_session) + m_session->play(); + + DP0("S60MediaPlayerControl::play ---"); +} + +/*! + Pauses playback of the current media. + + If sucessful the player control will immediately enter the \l {QMediaPlayer::PausedState} + {paused} state. +*/ + +void S60MediaPlayerControl::pause() +{ + DP0("S60MediaPlayerControl::pause +++"); + + if (m_session) + m_session->pause(); + + DP0("S60MediaPlayerControl::pause ---"); +} + +/*! + Stops playback of the current media. + + If successful the player control will immediately enter the \l {QMediaPlayer::StoppedState} + {stopped} state. +*/ + +void S60MediaPlayerControl::stop() +{ + DP0("S60MediaPlayerControl::stop +++"); + + if (m_session) + m_session->stop(); + + DP0("S60MediaPlayerControl::stop ---"); +} + +/*! + Sets the audio \a volume of a player control. +*/ + +void S60MediaPlayerControl::setVolume(int volume) +{ + DP0("S60MediaPlayerControl::setVolume +++"); + + DP1("S60MediaPlayerControl::setVolume", volume); + + int boundVolume = qBound(0, volume, 100); + if (boundVolume == m_mediaSettings.volume()) + return; + + m_mediaSettings.setVolume(boundVolume); + + if (m_session) + m_session->setVolume(boundVolume); + + DP0("S60MediaPlayerControl::setVolume ---"); +} + +/*! + Sets the \a muted state of a player control. +*/ + +void S60MediaPlayerControl::setMuted(bool muted) +{ + DP0("S60MediaPlayerControl::setMuted +++"); + + DP1("S60MediaPlayerControl::setMuted - ", muted); + + if (m_mediaSettings.isMuted() == muted) + return; + + m_mediaSettings.setMuted(muted); + + if (m_session) + m_session->setMuted(muted); + + DP0("S60MediaPlayerControl::setMuted ---"); +} + +/*! + * \return the current media source. +*/ + +QMediaContent S60MediaPlayerControl::media() const +{ + DP0("S60MediaPlayerControl::media"); + + return m_currentResource; +} + +/*! + \return the current media stream. This is only a valid if a stream was passed to setMedia(). + + \sa setMedia() +*/ + +const QIODevice *S60MediaPlayerControl::mediaStream() const +{ + DP0("S60MediaPlayerControl::mediaStream"); + + return m_stream; +} + +/*! + Sets the current \a source media source. If a \a stream is supplied; data will be read from that + instead of attempting to resolve the media source. The media source may still be used to + supply media information such as mime type. + + Setting the media to a null QMediaContent will cause the control to discard all + information relating to the current media source and to cease all I/O operations related + to that media. +*/ + +void S60MediaPlayerControl::setMedia(const QMediaContent &source, QIODevice *stream) +{ + DP0("S60MediaPlayerControl::setMedia +++"); + + Q_UNUSED(stream) + + if ((m_session && m_currentResource == source) && m_session->isStreaming()) + { + m_session->load(source); + return; + } + + // we don't want to set & load media again when it is already loaded + if (m_session && m_currentResource == source) + return; + + // store to variable as session is created based on the content type. + m_currentResource = source; + S60MediaPlayerSession *newSession = m_mediaPlayerResolver.PlayerSession(); + m_mediaSettings.setMediaStatus(QMediaPlayer::UnknownMediaStatus); + + if (m_session) + m_session->reset(); + else { + emit mediaStatusChanged(QMediaPlayer::UnknownMediaStatus); + emit error(QMediaPlayer::NoError, QString()); + } + + m_session = newSession; + + if (m_session) + m_session->load(source); + else { + QMediaPlayer::MediaStatus status = (source.isNull()) ? QMediaPlayer::NoMedia : QMediaPlayer::InvalidMedia; + m_mediaSettings.setMediaStatus(status); + emit stateChanged(QMediaPlayer::StoppedState); + emit error((source.isNull()) ? QMediaPlayer::NoError : QMediaPlayer::ResourceError, + (source.isNull()) ? "" : tr("Media couldn't be resolved")); + emit mediaStatusChanged(status); + } + emit mediaChanged(m_currentResource); + + DP0("S60MediaPlayerControl::setMedia ---"); +} + +/*! + * \return media player session. +*/ +S60MediaPlayerSession* S60MediaPlayerControl::session() +{ + DP0("S60MediaPlayerControl::session"); + + return m_session; +} + +/*! + * Sets \a output as a VideoOutput. +*/ + +void S60MediaPlayerControl::setVideoOutput(QObject *output) +{ + DP0("S60MediaPlayerControl::setVideoOutput +++"); + + m_mediaPlayerResolver.VideoPlayerSession()->setVideoRenderer(output); + + DP0("S60MediaPlayerControl::setVideoOutput ---"); +} + +/*! + * \return TRUE if Audio available or else FALSE. +*/ + +bool S60MediaPlayerControl::isAudioAvailable() const +{ + DP0("S60MediaPlayerControl::isAudioAvailable"); + + if (m_session) + return m_session->isAudioAvailable(); + return false; +} + +/*! + * \return TRUE if Video available or else FALSE. +*/ + +bool S60MediaPlayerControl::isVideoAvailable() const +{ + DP0("S60MediaPlayerControl::isVideoAvailable"); + + if (m_session) + return m_session->isVideoAvailable(); + return false; +} + +/*! + * \return media settings. + * + * Media Settings include volume, muted, playbackRate, mediaStatus, audioEndpoint. +*/ +const S60MediaSettings& S60MediaPlayerControl::mediaControlSettings() const +{ + DP0("S60MediaPlayerControl::mediaControlSettings"); + return m_mediaSettings; +} + +/*! + * Set the audio endpoint to \a name. +*/ + +void S60MediaPlayerControl::setAudioEndpoint(const QString& name) +{ + DP0("S60MediaPlayerControl::setAudioEndpoint +++"); + + DP1("S60MediaPlayerControl::setAudioEndpoint - ", name); + + m_mediaSettings.setAudioEndpoint(name); + + DP0("S60MediaPlayerControl::setAudioEndpoint ---"); +} + +/*! + * Sets media type \a type as Unknown, Video, Audio, Data. +*/ + +void S60MediaPlayerControl::setMediaType(S60MediaSettings::TMediaType type) +{ + DP0("S60MediaPlayerControl::setMediaType +++"); + + DP1("S60MediaPlayerControl::setMediaType - ", type); + + m_mediaSettings.setMediaType(type); + + DP0("S60MediaPlayerControl::setMediaType ---"); +} diff --git a/src/plugins/symbian/mmf/mediaplayer/s60mediaplayercontrol.h b/src/plugins/symbian/mmf/mediaplayer/s60mediaplayercontrol.h new file mode 100644 index 000000000..caf6631a8 --- /dev/null +++ b/src/plugins/symbian/mmf/mediaplayer/s60mediaplayercontrol.h @@ -0,0 +1,148 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** +****************************************************************************/ + +#ifndef S60MEDIAPLAYERCONTROL_H +#define S60MEDIAPLAYERCONTROL_H + +#include <QtCore/qobject.h> + +#include <qmediaplayercontrol.h> + +#include "ms60mediaplayerresolver.h" +#include <QtCore/qdebug.h> + +QT_BEGIN_NAMESPACE +class QMediaPlayer; +class QMediaTimeRange; +class QMediaContent; +QT_END_NAMESPACE + +QT_USE_NAMESPACE + +class S60MediaPlayerSession; +class S60MediaPlayerService; + +class S60MediaSettings +{ + +public: + S60MediaSettings() + : m_volume(30) + , m_muted(false) + , m_playbackRate(0) + , m_mediaStatus(QMediaPlayer::NoMedia) + , m_audioEndpoint(QString("Default")) + { + } + + enum TMediaType {Unknown, Video, Audio, Data}; + + void setVolume(int volume) { m_volume = volume; } + void setMuted(bool muted) { m_muted = muted; } + void setPlaybackRate(qreal rate) { m_playbackRate = rate; } + void setMediaStatus(QMediaPlayer::MediaStatus status) {m_mediaStatus=status;} + void setAudioEndpoint(const QString& audioEndpoint) { m_audioEndpoint = audioEndpoint; } + void setMediaType(S60MediaSettings::TMediaType type) { m_mediaType = type; } + + int volume() const { return m_volume; } + bool isMuted() const { return m_muted; } + qreal playbackRate() const { return m_playbackRate; } + QMediaPlayer::MediaStatus mediaStatus() const {return m_mediaStatus;} + QString audioEndpoint() const { return m_audioEndpoint; } + S60MediaSettings::TMediaType mediaType() const { return m_mediaType; } + +private: + int m_volume; + bool m_muted; + qreal m_playbackRate; + QMediaPlayer::MediaStatus m_mediaStatus; + QString m_audioEndpoint; + S60MediaSettings::TMediaType m_mediaType; +}; + +class S60MediaPlayerControl : public QMediaPlayerControl +{ + Q_OBJECT + +public: + S60MediaPlayerControl(MS60MediaPlayerResolver& mediaPlayerResolver, QObject *parent = 0); + ~S60MediaPlayerControl(); + + // from QMediaPlayerControl + virtual QMediaPlayer::State state() const; + virtual QMediaPlayer::MediaStatus mediaStatus() const; + virtual qint64 duration() const; + virtual qint64 position() const; + virtual void setPosition(qint64 pos); + virtual int volume() const; + virtual void setVolume(int volume); + virtual bool isMuted() const; + virtual void setMuted(bool muted); + virtual int bufferStatus() const; + virtual bool isAudioAvailable() const; + virtual bool isVideoAvailable() const; + virtual bool isSeekable() const; + virtual QMediaTimeRange availablePlaybackRanges() const; + virtual qreal playbackRate() const; + virtual void setPlaybackRate(qreal rate); + virtual QMediaContent media() const; + virtual const QIODevice *mediaStream() const; + virtual void setMedia(const QMediaContent&, QIODevice *); + virtual void play(); + virtual void pause(); + virtual void stop(); + + // Own methods + S60MediaPlayerSession* session(); + void setVideoOutput(QObject *output); + const S60MediaSettings& mediaControlSettings() const; + void setAudioEndpoint(const QString& name); + void setMediaType(S60MediaSettings::TMediaType type); + +private: + MS60MediaPlayerResolver &m_mediaPlayerResolver; + S60MediaPlayerSession *m_session; + QMediaContent m_currentResource; + QIODevice *m_stream; + S60MediaSettings m_mediaSettings; +}; + +#endif diff --git a/src/plugins/symbian/mmf/mediaplayer/s60mediaplayerservice.cpp b/src/plugins/symbian/mmf/mediaplayer/s60mediaplayerservice.cpp new file mode 100644 index 000000000..a1aabef90 --- /dev/null +++ b/src/plugins/symbian/mmf/mediaplayer/s60mediaplayerservice.cpp @@ -0,0 +1,326 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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 "DebugMacros.h" + +#include <QtCore/qvariant.h> +#include <QtCore/qdebug.h> +#include <QtGui/qwidget.h> + +#include "s60mediaplayerservice.h" +#include "s60mediaplayercontrol.h" +#include "s60videoplayersession.h" +#include "s60audioplayersession.h" +#include "s60mediametadataprovider.h" +#include "s60mediarecognizer.h" +#include "s60videowidgetcontrol.h" +#include "s60videowindowcontrol.h" +#ifdef HAS_VIDEORENDERERCONTROL_IN_VIDEOPLAYER +#include "s60videorenderer.h" +#endif +#include "s60mediaplayeraudioendpointselector.h" +#include "s60medianetworkaccesscontrol.h" +#include "s60mediastreamcontrol.h" + +#include <qmediaplaylistnavigator.h> +#include <qmediaplaylist.h> + +/*! + Construct a media service with the given \a parent. +*/ + +S60MediaPlayerService::S60MediaPlayerService(QObject *parent) + : QMediaService(parent) + , m_control(NULL) + , m_videoPlayerSession(NULL) + , m_audioPlayerSession(NULL) + , m_metaData(NULL) + , m_audioEndpointSelector(NULL) + , m_streamControl(NULL) + , m_networkAccessControl(NULL) + , m_videoOutput(NULL) +{ + DP0("S60MediaPlayerService::S60MediaPlayerService +++"); + + m_control = new S60MediaPlayerControl(*this, this); + m_metaData = new S60MediaMetaDataProvider(m_control, this); + m_audioEndpointSelector = new S60MediaPlayerAudioEndpointSelector(m_control, this); + m_streamControl = new S60MediaStreamControl(m_control, this); + m_networkAccessControl = new S60MediaNetworkAccessControl(this); + + DP0("S60MediaPlayerService::S60MediaPlayerService ---"); +} + +/*! + Destroys a media service. +*/ + +S60MediaPlayerService::~S60MediaPlayerService() +{ + DP0("S60MediaPlayerService::~S60MediaPlayerService +++"); + DP0("S60MediaPlayerService::~S60MediaPlayerService ---"); +} + +/*! + \return a pointer to the media control, which matches the controller \a name. + + If the service does not implement the control, or if it is unavailable a + null pointer is returned instead. + + Controls must be returned to the service when no longer needed using the + releaseControl() function. +*/ + +QMediaControl *S60MediaPlayerService::requestControl(const char *name) +{ + DP0("S60MediaPlayerService::requestControl"); + + if (qstrcmp(name, QMediaPlayerControl_iid) == 0) + return m_control; + + if (qstrcmp(name, QMediaNetworkAccessControl_iid) == 0) + return m_networkAccessControl; + + if (qstrcmp(name, QMetaDataReaderControl_iid) == 0) + return m_metaData; + + if (qstrcmp(name, QAudioEndpointSelector_iid) == 0) + return m_audioEndpointSelector; + + if (qstrcmp(name, QMediaStreamsControl_iid) == 0) + return m_streamControl; + + if (!m_videoOutput) { + if (qstrcmp(name, QVideoWidgetControl_iid) == 0) { + m_videoOutput = new S60VideoWidgetControl(this); + } +#ifdef HAS_VIDEORENDERERCONTROL_IN_VIDEOPLAYER + else if (qstrcmp(name, QVideoRendererControl_iid) == 0) { + m_videoOutput = new S60VideoRenderer(this); + } +#endif /* HAS_VIDEORENDERERCONTROL_IN_VIDEOPLAYER */ + else if (qstrcmp(name, QVideoWindowControl_iid) == 0) { + m_videoOutput = new S60VideoWindowControl(this); + } + + if (m_videoOutput) { + m_control->setVideoOutput(m_videoOutput); + return m_videoOutput; + } + }else { + if (qstrcmp(name, QVideoWidgetControl_iid) == 0 || +#ifdef HAS_VIDEORENDERERCONTROL_IN_VIDEOPLAYER + qstrcmp(name, QVideoRendererControl_iid) == 0 || +#endif /* HAS_VIDEORENDERERCONTROL_IN_VIDEOPLAYER */ + qstrcmp(name, QVideoWindowControl_iid) == 0){ + return m_videoOutput; + } + } + return 0; +} + +/*! + Releases a \a control back to the service. +*/ + +void S60MediaPlayerService::releaseControl(QMediaControl *control) +{ + DP0("S60MediaPlayerService::releaseControl ++"); + + if (control == m_videoOutput) { + m_videoOutput = 0; + m_control->setVideoOutput(m_videoOutput); + } + + DP0("S60MediaPlayerService::releaseControl --"); +} + +/*! + * \return media player session(audio playersesion/video playersession) + * by recognizing whether media is audio or video and sets it on media type. +*/ +S60MediaPlayerSession* S60MediaPlayerService::PlayerSession() +{ + DP0("S60MediaPlayerService::PlayerSession"); + + QUrl url = m_control->media().canonicalUrl(); + + if (url.isEmpty() == true) { + return NULL; + } + + QScopedPointer<S60MediaRecognizer> mediaRecognizer(new S60MediaRecognizer); + S60MediaRecognizer::MediaType mediaType = mediaRecognizer->mediaType(url); + mediaRecognizer.reset(); + + switch (mediaType) { + case S60MediaRecognizer::Video: + case S60MediaRecognizer::Url: { + m_control->setMediaType(S60MediaSettings::Video); + return VideoPlayerSession(); + } + case S60MediaRecognizer::Audio: { + m_control->setMediaType(S60MediaSettings::Audio); + return AudioPlayerSession(); + } + default: + m_control->setMediaType(S60MediaSettings::Unknown); + break; + } + + return NULL; +} + +/*! + * \return media playersession (videoplayersession). + * constructs the videoplayersession object and connects all the respective signals and slots. + * and initialises all the media settings. +*/ + +S60MediaPlayerSession* S60MediaPlayerService::VideoPlayerSession() +{ + DP0("S60MediaPlayerService::VideoPlayerSession +++"); + + if (!m_videoPlayerSession) { + m_videoPlayerSession = new S60VideoPlayerSession(this, m_networkAccessControl); + + connect(m_videoPlayerSession, SIGNAL(positionChanged(qint64)), + m_control, SIGNAL(positionChanged(qint64))); + connect(m_videoPlayerSession, SIGNAL(playbackRateChanged(qreal)), + m_control, SIGNAL(playbackRateChanged(qreal))); + connect(m_videoPlayerSession, SIGNAL(volumeChanged(int)), + m_control, SIGNAL(volumeChanged(int))); + connect(m_videoPlayerSession, SIGNAL(mutedChanged(bool)), + m_control, SIGNAL(mutedChanged(bool))); + connect(m_videoPlayerSession, SIGNAL(durationChanged(qint64)), + m_control, SIGNAL(durationChanged(qint64))); + connect(m_videoPlayerSession, SIGNAL(stateChanged(QMediaPlayer::State)), + m_control, SIGNAL(stateChanged(QMediaPlayer::State))); + connect(m_videoPlayerSession, SIGNAL(mediaStatusChanged(QMediaPlayer::MediaStatus)), + m_control, SIGNAL(mediaStatusChanged(QMediaPlayer::MediaStatus))); + connect(m_videoPlayerSession,SIGNAL(bufferStatusChanged(int)), + m_control, SIGNAL(bufferStatusChanged(int))); + connect(m_videoPlayerSession, SIGNAL(videoAvailableChanged(bool)), + m_control, SIGNAL(videoAvailableChanged(bool))); + connect(m_videoPlayerSession, SIGNAL(audioAvailableChanged(bool)), + m_control, SIGNAL(audioAvailableChanged(bool))); + connect(m_videoPlayerSession, SIGNAL(seekableChanged(bool)), + m_control, SIGNAL(seekableChanged(bool))); + connect(m_videoPlayerSession, SIGNAL(availablePlaybackRangesChanged(const QMediaTimeRange&)), + m_control, SIGNAL(availablePlaybackRangesChanged(const QMediaTimeRange&))); + connect(m_videoPlayerSession, SIGNAL(error(int, const QString &)), + m_control, SIGNAL(error(int, const QString &))); + connect(m_videoPlayerSession, SIGNAL(metaDataChanged()), + m_metaData, SIGNAL(metaDataChanged())); + connect(m_videoPlayerSession, SIGNAL(activeEndpointChanged(const QString&)), + m_audioEndpointSelector, SIGNAL(activeEndpointChanged(const QString&))); + connect(m_videoPlayerSession, SIGNAL(mediaChanged()), + m_streamControl, SLOT(handleStreamsChanged())); + connect(m_videoPlayerSession, SIGNAL(accessPointChanged(int)), + m_networkAccessControl, SLOT(accessPointChanged(int))); + + } + + m_videoPlayerSession->setVolume(m_control->mediaControlSettings().volume()); + m_videoPlayerSession->setMuted(m_control->mediaControlSettings().isMuted()); + m_videoPlayerSession->setAudioEndpoint(m_control->mediaControlSettings().audioEndpoint()); + + DP0("S60MediaPlayerService::VideoPlayerSession ---"); + + return m_videoPlayerSession; +} + +/*! + * \return media playersession (audioplayersession). + * constructs the audioplayersession object and connects all the respective signals and slots. + * and initialises all the media settings. +*/ + +S60MediaPlayerSession* S60MediaPlayerService::AudioPlayerSession() +{ + DP0("S60MediaPlayerService::AudioPlayerSession +++"); + + if (!m_audioPlayerSession) { + m_audioPlayerSession = new S60AudioPlayerSession(this); + + connect(m_audioPlayerSession, SIGNAL(positionChanged(qint64)), + m_control, SIGNAL(positionChanged(qint64))); + connect(m_audioPlayerSession, SIGNAL(playbackRateChanged(qreal)), + m_control, SIGNAL(playbackRateChanged(qreal))); + connect(m_audioPlayerSession, SIGNAL(volumeChanged(int)), + m_control, SIGNAL(volumeChanged(int))); + connect(m_audioPlayerSession, SIGNAL(mutedChanged(bool)), + m_control, SIGNAL(mutedChanged(bool))); + connect(m_audioPlayerSession, SIGNAL(durationChanged(qint64)), + m_control, SIGNAL(durationChanged(qint64))); + connect(m_audioPlayerSession, SIGNAL(stateChanged(QMediaPlayer::State)), + m_control, SIGNAL(stateChanged(QMediaPlayer::State))); + connect(m_audioPlayerSession, SIGNAL(mediaStatusChanged(QMediaPlayer::MediaStatus)), + m_control, SIGNAL(mediaStatusChanged(QMediaPlayer::MediaStatus))); + connect(m_audioPlayerSession,SIGNAL(bufferStatusChanged(int)), + m_control, SIGNAL(bufferStatusChanged(int))); + connect(m_audioPlayerSession, SIGNAL(videoAvailableChanged(bool)), + m_control, SIGNAL(videoAvailableChanged(bool))); + connect(m_audioPlayerSession, SIGNAL(audioAvailableChanged(bool)), + m_control, SIGNAL(audioAvailableChanged(bool))); + connect(m_audioPlayerSession, SIGNAL(seekableChanged(bool)), + m_control, SIGNAL(seekableChanged(bool))); + connect(m_audioPlayerSession, SIGNAL(availablePlaybackRangesChanged(const QMediaTimeRange&)), + m_control, SIGNAL(availablePlaybackRangesChanged(const QMediaTimeRange&))); + connect(m_audioPlayerSession, SIGNAL(error(int, const QString &)), + m_control, SIGNAL(error(int, const QString &))); + connect(m_audioPlayerSession, SIGNAL(metaDataChanged()), + m_metaData, SIGNAL(metaDataChanged())); + connect(m_audioPlayerSession, SIGNAL(activeEndpointChanged(const QString&)), + m_audioEndpointSelector, SIGNAL(activeEndpointChanged(const QString&))); + connect(m_audioPlayerSession, SIGNAL(mediaChanged()), + m_streamControl, SLOT(handleStreamsChanged())); + + } + + m_audioPlayerSession->setVolume(m_control->mediaControlSettings().volume()); + m_audioPlayerSession->setMuted(m_control->mediaControlSettings().isMuted()); + m_audioPlayerSession->setAudioEndpoint(m_control->mediaControlSettings().audioEndpoint()); + + DP0("S60MediaPlayerService::AudioPlayerSession ---"); + + return m_audioPlayerSession; +} diff --git a/src/plugins/symbian/mmf/mediaplayer/s60mediaplayerservice.h b/src/plugins/symbian/mmf/mediaplayer/s60mediaplayerservice.h new file mode 100644 index 000000000..d45ad45cc --- /dev/null +++ b/src/plugins/symbian/mmf/mediaplayer/s60mediaplayerservice.h @@ -0,0 +1,97 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** +****************************************************************************/ + +#ifndef S60VIDEOPLAYERSERVICE_H +#define S60VIDEOPLAYERSERVICE_H + +#include <QtCore/qobject.h> +#include <qmediaservice.h> + +#include "ms60mediaplayerresolver.h" +#include "s60mediaplayeraudioendpointselector.h" + +QT_BEGIN_NAMESPACE +class QMediaMetaData; +class QMediaPlayerControl; +class QMediaPlaylist; +QT_END_NAMESPACE + +QT_USE_NAMESPACE + +class S60VideoPlayerSession; +class S60AudioPlayerSession; +class S60MediaPlayerControl; +class S60MediaMetaDataProvider; +class S60MediaStreamControl; +class S60MediaRecognizer; + +class QMediaPlaylistNavigator; +class S60MediaNetworkAccessControl; + +class S60MediaPlayerService : public QMediaService, public MS60MediaPlayerResolver +{ + Q_OBJECT + +public: + + S60MediaPlayerService(QObject *parent = 0); + ~S60MediaPlayerService(); + + QMediaControl *requestControl(const char *name); + void releaseControl(QMediaControl *control); + +protected: // From MS60MediaPlayerResolver + S60MediaPlayerSession* PlayerSession(); + S60MediaPlayerSession* VideoPlayerSession(); + S60MediaPlayerSession* AudioPlayerSession(); + +private: + S60MediaPlayerControl *m_control; + S60VideoPlayerSession *m_videoPlayerSession; + S60AudioPlayerSession *m_audioPlayerSession; + S60MediaMetaDataProvider *m_metaData; + S60MediaPlayerAudioEndpointSelector *m_audioEndpointSelector; + S60MediaStreamControl *m_streamControl; + S60MediaNetworkAccessControl *m_networkAccessControl; + QMediaControl *m_videoOutput; +}; + +#endif diff --git a/src/plugins/symbian/mmf/mediaplayer/s60mediaplayersession.cpp b/src/plugins/symbian/mmf/mediaplayer/s60mediaplayersession.cpp new file mode 100644 index 000000000..49a840a2d --- /dev/null +++ b/src/plugins/symbian/mmf/mediaplayer/s60mediaplayersession.cpp @@ -0,0 +1,1054 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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 "DebugMacros.h" + +#include "s60mediaplayersession.h" + +#include <QtCore/qdebug.h> +#include <QtCore/qdir.h> +#include <QtCore/qvariant.h> +#include <QtCore/qtimer.h> +#include <mmf/common/mmferrors.h> +#include <qmediatimerange.h> + +/*! + Construct a media playersession with the given \a parent. +*/ + +S60MediaPlayerSession::S60MediaPlayerSession(QObject *parent) + : QObject(parent) + , m_stream(false) + , m_playbackRate(0) + , m_muted(false) + , m_volume(0) + , m_state(QMediaPlayer::StoppedState) + , m_mediaStatus(QMediaPlayer::NoMedia) + , m_progressTimer(new QTimer(this)) + , m_stalledTimer(new QTimer(this)) + , m_error(KErrNone) + , m_play_requested(false) + , m_seekable(true) +{ + DP0("S60MediaPlayerSession::S60MediaPlayerSession +++"); + + connect(m_progressTimer, SIGNAL(timeout()), this, SLOT(tick())); + connect(m_stalledTimer, SIGNAL(timeout()), this, SLOT(stalled())); + + DP0("S60MediaPlayerSession::S60MediaPlayerSession ---"); +} + +/*! + Destroys a media playersession. +*/ + +S60MediaPlayerSession::~S60MediaPlayerSession() +{ + DP0("S60MediaPlayerSession::~S60MediaPlayerSession +++"); + DP0("S60MediaPlayerSession::~S60MediaPlayerSession ---"); +} + +/*! + * \return the audio volume of a player session. +*/ +int S60MediaPlayerSession::volume() const +{ + DP1("S60MediaPlayerSession::volume", m_volume); + + return m_volume; +} + +/*! + Sets the audio \a volume of a player session. +*/ + +void S60MediaPlayerSession::setVolume(int volume) +{ + DP0("S60MediaPlayerSession::setVolume +++"); + + DP1("S60MediaPlayerSession::setVolume - ", volume); + + if (m_volume == volume) + return; + + m_volume = volume; + emit volumeChanged(m_volume); + + // Dont set symbian players volume until media loaded. + // Leaves with KerrNotReady although documentation says otherwise. + if (!m_muted && + ( mediaStatus() == QMediaPlayer::LoadedMedia + || (mediaStatus() == QMediaPlayer::StalledMedia && state() != QMediaPlayer::StoppedState) + || mediaStatus() == QMediaPlayer::BufferingMedia + || mediaStatus() == QMediaPlayer::BufferedMedia + || mediaStatus() == QMediaPlayer::EndOfMedia)) { + TRAPD(err, doSetVolumeL(m_volume)); + setError(err); + } + DP0("S60MediaPlayerSession::setVolume ---"); +} + +/*! + \return the mute state of a player session. +*/ + +bool S60MediaPlayerSession::isMuted() const +{ + DP1("S60MediaPlayerSession::isMuted", m_muted); + + return m_muted; +} + +/*! + Identifies if the current media is seekable. + + \return true if it possible to seek within the current media, and false otherwise. +*/ + +bool S60MediaPlayerSession::isSeekable() const +{ + DP1("S60MediaPlayerSession::isSeekable", m_seekable); + + return m_seekable; +} + +/*! + Sets the \a status of the current media. +*/ + +void S60MediaPlayerSession::setMediaStatus(QMediaPlayer::MediaStatus status) +{ + DP0("S60MediaPlayerSession::setMediaStatus +++"); + + if (m_mediaStatus == status) + return; + + m_mediaStatus = status; + + emit mediaStatusChanged(m_mediaStatus); + + if (m_play_requested && m_mediaStatus == QMediaPlayer::LoadedMedia) + play(); + + DP0("S60MediaPlayerSession::setMediaStatus ---"); +} + +/*! + Sets the \a state on media player. +*/ + +void S60MediaPlayerSession::setState(QMediaPlayer::State state) +{ + DP0("S60MediaPlayerSession::setState +++"); + + if (m_state == state) + return; + + m_state = state; + emit stateChanged(m_state); + + DP0("S60MediaPlayerSession::setState ---"); +} + +/*! + \return the state of a player session. +*/ + +QMediaPlayer::State S60MediaPlayerSession::state() const +{ + DP1("S60MediaPlayerSession::state", m_state); + + return m_state; +} + +/*! + \return the status of the current media. +*/ + +QMediaPlayer::MediaStatus S60MediaPlayerSession::mediaStatus() const +{ + DP1("S60MediaPlayerSession::mediaStatus", m_mediaStatus); + + return m_mediaStatus; +} + +/*! + * Loads the \a url for playback. + * If \a url is local file then it loads audio playersesion if its audio file. + * If it is a local video file then loads the video playersession. +*/ + +void S60MediaPlayerSession::load(const QMediaContent source) +{ + DP0("S60MediaPlayerSession::load +++"); + + m_source = source; + setMediaStatus(QMediaPlayer::LoadingMedia); + startStalledTimer(); + m_stream = (source.canonicalUrl().scheme() == "file")?false:true; + m_UrlPath = source.canonicalUrl(); + TRAPD(err, + if (m_stream) + doLoadUrlL(QString2TPtrC(source.canonicalUrl().toString())); + else + doLoadL(QString2TPtrC(QDir::toNativeSeparators(source.canonicalUrl().toLocalFile())))); + setError(err); + + DP0("S60MediaPlayerSession::load ---"); +} + +TBool S60MediaPlayerSession::isStreaming() +{ + return m_stream; +} + +/*! + Start or resume playing the current source. +*/ +void S60MediaPlayerSession::play() +{ + DP0("S60MediaPlayerSession::play +++"); + + if ( (state() == QMediaPlayer::PlayingState && m_play_requested == false) + || mediaStatus() == QMediaPlayer::UnknownMediaStatus + || mediaStatus() == QMediaPlayer::NoMedia + || mediaStatus() == QMediaPlayer::InvalidMedia) + return; + + setState(QMediaPlayer::PlayingState); + + if (mediaStatus() == QMediaPlayer::LoadingMedia || + (mediaStatus() == QMediaPlayer::StalledMedia && + state() == QMediaPlayer::StoppedState)) + { + m_play_requested = true; + return; + } + + m_play_requested = false; + m_duration = duration(); + setVolume(m_volume); + setMuted(m_muted); + startProgressTimer(); + doPlay(); + + DP0("S60MediaPlayerSession::play ---"); +} + +/*! + Pause playing the current source. +*/ + +void S60MediaPlayerSession::pause() +{ + DP0("S60MediaPlayerSession::pause +++"); + + if (state() != QMediaPlayer::PlayingState) + return; + + if (mediaStatus() == QMediaPlayer::NoMedia || + mediaStatus() == QMediaPlayer::InvalidMedia) + return; + + setState(QMediaPlayer::PausedState); + stopProgressTimer(); + TRAP_IGNORE(doPauseL()); + m_play_requested = false; + + DP0("S60MediaPlayerSession::pause ---"); +} + +/*! + Stop playing, and reset the play position to the beginning. +*/ + +void S60MediaPlayerSession::stop() +{ + DP0("S60MediaPlayerSession::stop +++"); + + if (state() == QMediaPlayer::StoppedState) + return; + + m_play_requested = false; + m_state = QMediaPlayer::StoppedState; + if (mediaStatus() == QMediaPlayer::BufferingMedia || + mediaStatus() == QMediaPlayer::BufferedMedia || + mediaStatus() == QMediaPlayer::StalledMedia) + setMediaStatus(QMediaPlayer::LoadedMedia); + if (mediaStatus() == QMediaPlayer::LoadingMedia) + setMediaStatus(QMediaPlayer::UnknownMediaStatus); + stopProgressTimer(); + stopStalledTimer(); + doStop(); + emit positionChanged(0); + emit stateChanged(m_state); + + DP0("S60MediaPlayerSession::stop ---"); +} + +/*! + * Stops the playback and closes the controllers. + * And resets all the flags and status, state to default values. +*/ + +void S60MediaPlayerSession::reset() +{ + DP0("S60MediaPlayerSession::reset +++"); + + m_play_requested = false; + setError(KErrNone, QString(), true); + stopProgressTimer(); + stopStalledTimer(); + doStop(); + doClose(); + setState(QMediaPlayer::StoppedState); + setMediaStatus(QMediaPlayer::UnknownMediaStatus); + setPosition(0); + + DP0("S60MediaPlayerSession::reset ---"); +} + +/*! + * Sets \a renderer as video renderer. +*/ + +void S60MediaPlayerSession::setVideoRenderer(QObject *renderer) +{ + DP0("S60MediaPlayerSession::setVideoRenderer +++"); + + Q_UNUSED(renderer); + + DP0("S60MediaPlayerSession::setVideoRenderer ---"); +} + +/*! + * the percentage of the temporary buffer filled before playback begins. + + When the player object is buffering; this property holds the percentage of + the temporary buffer that is filled. The buffer will need to reach 100% + filled before playback can resume, at which time the MediaStatus will be + BufferedMedia. + + \sa mediaStatus() +*/ + +int S60MediaPlayerSession::bufferStatus() +{ + DP0("S60MediaPlayerSession::bufferStatus"); + + if (state() ==QMediaPlayer::StoppedState) + return 0; + + if( mediaStatus() == QMediaPlayer::LoadingMedia + || mediaStatus() == QMediaPlayer::UnknownMediaStatus + || mediaStatus() == QMediaPlayer::NoMedia + || mediaStatus() == QMediaPlayer::InvalidMedia) + return 0; + + int progress = 0; + TRAPD(err, progress = doGetBufferStatusL()); + // If buffer status query not supported by codec return 100 + // do not set error + if(err == KErrNotSupported) + return 100; + + setError(err); + return progress; +} + +/*! + * return TRUE if Meta data is available in current media source. +*/ + +bool S60MediaPlayerSession::isMetadataAvailable() const +{ + DP0("S60MediaPlayerSession::isMetadataAvailable"); + + return !m_metaDataMap.isEmpty(); +} + +/*! + * \return the \a key meta data. +*/ +QVariant S60MediaPlayerSession::metaData(const QString &key) const +{ + DP0("S60MediaPlayerSession::metaData (const QString &key) const"); + + return m_metaDataMap.value(key); +} + +/*! + * \return the \a key meta data as QString. +*/ + +QVariant S60MediaPlayerSession::metaData(QtMultimediaKit::MetaData key) const +{ + DP0("S60MediaPlayerSession::metaData (QtMultimediaKit::MetaData key) const"); + + return metaData(metaDataKeyAsString(key)); +} + +/*! + * \return List of all available meta data from current media source. +*/ + +QList<QtMultimediaKit::MetaData> S60MediaPlayerSession::availableMetaData() const +{ + DP0("S60MediaPlayerSession::availableMetaData +++"); + + QList<QtMultimediaKit::MetaData> metaDataTags; + if (isMetadataAvailable()) { + for (int i = QtMultimediaKit::Title; i <= QtMultimediaKit::ThumbnailImage; i++) { + QString metaDataItem = metaDataKeyAsString((QtMultimediaKit::MetaData)i); + if (!metaDataItem.isEmpty()) { + if (!metaData(metaDataItem).isNull()) { + metaDataTags.append((QtMultimediaKit::MetaData)i); + } + } + } + } + + DP0("S60MediaPlayerSession::availableMetaData ---"); + + return metaDataTags; +} + +/*! + * \return all available extended meta data of current media source. +*/ + +QStringList S60MediaPlayerSession::availableExtendedMetaData() const +{ + DP0("S60MediaPlayerSession::availableExtendedMetaData"); + + return m_metaDataMap.keys(); +} + +/*! + * \return meta data \a key as QString. +*/ + +QString S60MediaPlayerSession::metaDataKeyAsString(QtMultimediaKit::MetaData key) const +{ + DP1("S60MediaPlayerSession::metaDataKeyAsString", key); + + switch(key) { + case QtMultimediaKit::Title: return "title"; + case QtMultimediaKit::AlbumArtist: return "artist"; + case QtMultimediaKit::Comment: return "comment"; + case QtMultimediaKit::Genre: return "genre"; + case QtMultimediaKit::Year: return "year"; + case QtMultimediaKit::Copyright: return "copyright"; + case QtMultimediaKit::AlbumTitle: return "album"; + case QtMultimediaKit::Composer: return "composer"; + case QtMultimediaKit::TrackNumber: return "albumtrack"; + case QtMultimediaKit::AudioBitRate: return "audiobitrate"; + case QtMultimediaKit::VideoBitRate: return "videobitrate"; + case QtMultimediaKit::Duration: return "duration"; + case QtMultimediaKit::MediaType: return "contenttype"; + case QtMultimediaKit::CoverArtImage: return "attachedpicture"; + case QtMultimediaKit::SubTitle: // TODO: Find the matching metadata keys + case QtMultimediaKit::Description: + case QtMultimediaKit::Category: + case QtMultimediaKit::Date: + case QtMultimediaKit::UserRating: + case QtMultimediaKit::Keywords: + case QtMultimediaKit::Language: + case QtMultimediaKit::Publisher: + case QtMultimediaKit::ParentalRating: + case QtMultimediaKit::RatingOrganisation: + case QtMultimediaKit::Size: + case QtMultimediaKit::AudioCodec: + case QtMultimediaKit::AverageLevel: + case QtMultimediaKit::ChannelCount: + case QtMultimediaKit::PeakValue: + case QtMultimediaKit::SampleRate: + case QtMultimediaKit::Author: + case QtMultimediaKit::ContributingArtist: + case QtMultimediaKit::Conductor: + case QtMultimediaKit::Lyrics: + case QtMultimediaKit::Mood: + case QtMultimediaKit::TrackCount: + case QtMultimediaKit::CoverArtUrlSmall: + case QtMultimediaKit::CoverArtUrlLarge: + case QtMultimediaKit::Resolution: + case QtMultimediaKit::PixelAspectRatio: + case QtMultimediaKit::VideoFrameRate: + case QtMultimediaKit::VideoCodec: + case QtMultimediaKit::PosterUrl: + case QtMultimediaKit::ChapterNumber: + case QtMultimediaKit::Director: + case QtMultimediaKit::LeadPerformer: + case QtMultimediaKit::Writer: + case QtMultimediaKit::CameraManufacturer: + case QtMultimediaKit::CameraModel: + case QtMultimediaKit::Event: + case QtMultimediaKit::Subject: + default: + break; + } + + return QString(); +} + +/*! + Sets the \a muted state of a player session. +*/ + +void S60MediaPlayerSession::setMuted(bool muted) +{ + DP0("S60MediaPlayerSession::setMuted +++"); + DP1("S60MediaPlayerSession::setMuted - ", muted); + + m_muted = muted; + emit mutedChanged(m_muted); + + if( m_mediaStatus == QMediaPlayer::LoadedMedia + || (m_mediaStatus == QMediaPlayer::StalledMedia && state() != QMediaPlayer::StoppedState) + || m_mediaStatus == QMediaPlayer::BufferingMedia + || m_mediaStatus == QMediaPlayer::BufferedMedia + || m_mediaStatus == QMediaPlayer::EndOfMedia) { + TRAPD(err, doSetVolumeL((m_muted)?0:m_volume)); + setError(err); + } + DP0("S60MediaPlayerSession::setMuted ---"); +} + +/*! + \return the duration of the current media in milliseconds. +*/ + +qint64 S60MediaPlayerSession::duration() const +{ + // DP0("S60MediaPlayerSession::duration"); + + if( mediaStatus() == QMediaPlayer::LoadingMedia + || mediaStatus() == QMediaPlayer::UnknownMediaStatus + || mediaStatus() == QMediaPlayer::NoMedia + || (mediaStatus() == QMediaPlayer::StalledMedia && state() == QMediaPlayer::StoppedState) + || mediaStatus() == QMediaPlayer::InvalidMedia) + return -1; + + qint64 pos = 0; + TRAP_IGNORE(pos = doGetDurationL()); + return pos; +} + +/*! + \return the current playback position in milliseconds. +*/ + +qint64 S60MediaPlayerSession::position() const +{ + // DP0("S60MediaPlayerSession::position"); + + if( mediaStatus() == QMediaPlayer::LoadingMedia + || mediaStatus() == QMediaPlayer::UnknownMediaStatus + || mediaStatus() == QMediaPlayer::NoMedia + || (mediaStatus() == QMediaPlayer::StalledMedia && state() == QMediaPlayer::StoppedState) + || mediaStatus() == QMediaPlayer::InvalidMedia) + return 0; + + qint64 pos = 0; + TRAP_IGNORE(pos = doGetPositionL()); + if (!m_play_requested && pos ==0 + && mediaStatus() != QMediaPlayer::LoadedMedia) + return m_duration; + return pos; +} + +/*! + Sets the playback \a pos of the current media. This will initiate a seek and it may take + some time for playback to reach the position set. +*/ + +void S60MediaPlayerSession::setPosition(qint64 pos) +{ + DP0("S60MediaPlayerSession::setPosition +++"); + + DP1("S60MediaPlayerSession::setPosition - ", pos); + + if (position() == pos) + return; + + QMediaPlayer::State originalState = state(); + + if (originalState == QMediaPlayer::PlayingState) + pause(); + + TRAPD(err, doSetPositionL(pos * 1000)); + setError(err); + + if (err == KErrNone) { + if (mediaStatus() == QMediaPlayer::EndOfMedia) + setMediaStatus(QMediaPlayer::LoadedMedia); + } + else if (err == KErrNotSupported) { + m_seekable = false; + emit seekableChanged(m_seekable); + } + + if (originalState == QMediaPlayer::PlayingState) + play(); + + emit positionChanged(position()); + + DP0("S60MediaPlayerSession::setPosition ---"); +} + +/*! + * Set the audio endpoint to \a audioEndpoint. +*/ + +void S60MediaPlayerSession::setAudioEndpoint(const QString& audioEndpoint) +{ + DP0("S60MediaPlayerSession::setAudioEndpoint +++"); + + DP1("S60MediaPlayerSession::setAudioEndpoint - ", audioEndpoint); + + doSetAudioEndpoint(audioEndpoint); + + DP0("S60MediaPlayerSession::setAudioEndpoint ---"); +} + +/*! + * Loading of media source is completed. + * And ready for playback. Updates all the media status, state, settings etc. + * And emits the signals. +*/ + +void S60MediaPlayerSession::loaded() +{ + DP0("S60MediaPlayerSession::loaded +++"); + + stopStalledTimer(); + if (m_error == KErrNone || m_error == KErrMMPartialPlayback) { + setMediaStatus(QMediaPlayer::LoadedMedia); + TRAPD(err, updateMetaDataEntriesL()); + setError(err); + emit durationChanged(duration()); + emit positionChanged(0); + emit videoAvailableChanged(isVideoAvailable()); + emit audioAvailableChanged(isAudioAvailable()); + emit mediaChanged(); + + m_seekable = getIsSeekable(); + } + + DP0("S60MediaPlayerSession::loaded ---"); +} + +/*! + * Playback is completed as medai source reached end of media. +*/ +void S60MediaPlayerSession::endOfMedia() +{ + DP0("S60MediaPlayerSession::endOfMedia +++"); + + m_state = QMediaPlayer::StoppedState; + setMediaStatus(QMediaPlayer::EndOfMedia); + //there is a chance that user might have called play from EOF callback + //if we are already in playing state, do not send state change callback + if(m_state == QMediaPlayer::StoppedState) + emit stateChanged(QMediaPlayer::StoppedState); + emit positionChanged(m_duration); + + DP0("S60MediaPlayerSession::endOfMedia ---"); +} + +/*! + * The percentage of the temporary buffer filling before playback begins. + + When the player object is buffering; this property holds the percentage of + the temporary buffer that is filled. The buffer will need to reach 100% + filled before playback can resume, at which time the MediaStatus will be + BufferedMedia. + + \sa mediaStatus() +*/ + +void S60MediaPlayerSession::buffering() +{ + DP0("S60MediaPlayerSession::buffering +++"); + + startStalledTimer(); + setMediaStatus(QMediaPlayer::BufferingMedia); + +//Buffering cannot happen in stopped state. Hence update the state + if (state() == QMediaPlayer::StoppedState) + setState(QMediaPlayer::PausedState); + + DP0("S60MediaPlayerSession::buffering ---"); +} + +/*! + * Buffer is filled with data and to for continuing/start playback. +*/ + +void S60MediaPlayerSession::buffered() +{ + DP0("S60MediaPlayerSession::buffered +++"); + + stopStalledTimer(); + setMediaStatus(QMediaPlayer::BufferedMedia); + + DP0("S60MediaPlayerSession::buffered ---"); +} + +/*! + * Sets media status as stalled as waiting for the buffer to be filled to start playback. +*/ + +void S60MediaPlayerSession::stalled() +{ + DP0("S60MediaPlayerSession::stalled +++"); + + setMediaStatus(QMediaPlayer::StalledMedia); + + DP0("S60MediaPlayerSession::stalled ---"); +} + +/*! + * \return all the meta data entries in the current media source. +*/ + +QMap<QString, QVariant>& S60MediaPlayerSession::metaDataEntries() +{ + DP0("S60MediaPlayerSession::metaDataEntries"); + + return m_metaDataMap; +} + +/*! + * \return Error by converting Symbian specific error to Multimedia error. +*/ + +QMediaPlayer::Error S60MediaPlayerSession::fromSymbianErrorToMultimediaError(int error) +{ + DP0("S60MediaPlayerSession::fromSymbianErrorToMultimediaError"); + + DP1("S60MediaPlayerSession::fromSymbianErrorToMultimediaError - ", error); + + switch(error) { + case KErrNoMemory: + case KErrNotFound: + case KErrBadHandle: + case KErrAbort: + case KErrNotSupported: + case KErrCorrupt: + case KErrGeneral: + case KErrArgument: + case KErrPathNotFound: + case KErrDied: + case KErrServerTerminated: + case KErrServerBusy: + case KErrCompletion: + case KErrBadPower: + case KErrMMInvalidProtocol: + case KErrMMInvalidURL: + return QMediaPlayer::ResourceError; + + case KErrMMPartialPlayback: + return QMediaPlayer::FormatError; + + case KErrMMAudioDevice: + case KErrMMVideoDevice: + case KErrMMDecoder: + case KErrUnknown: + return QMediaPlayer::ServiceMissingError; + + case KErrMMNotEnoughBandwidth: + case KErrMMSocketServiceNotFound: + case KErrMMNetworkRead: + case KErrMMNetworkWrite: + case KErrMMServerSocket: + case KErrMMServerNotSupported: + case KErrMMUDPReceive: + case KErrMMMulticast: + case KErrMMProxyServer: + case KErrMMProxyServerNotSupported: + case KErrMMProxyServerConnect: + case KErrCouldNotConnect: + return QMediaPlayer::NetworkError; + + case KErrNotReady: + case KErrInUse: + case KErrAccessDenied: + case KErrLocked: + case KErrMMDRMNotAuthorized: + case KErrPermissionDenied: + case KErrCancel: + case KErrAlreadyExists: + return QMediaPlayer::AccessDeniedError; + + case KErrNone: + return QMediaPlayer::NoError; + + default: + return QMediaPlayer::ResourceError; + } +} + +/*! + * \return error. + */ + +int S60MediaPlayerSession::error() const +{ + DP1("S60MediaPlayerSession::error", m_error); + + return m_error; +} + +/*! + * Sets the error. + * * If playback complete/prepare complete ..., etc with successful then sets error as ZERO + * else Multimedia error. +*/ + +void S60MediaPlayerSession::setError(int error, const QString &errorString, bool forceReset) +{ + DP0("S60MediaPlayerSession::setError +++"); + + DP5("S60MediaPlayerSession::setError - error:", error,"errorString:", errorString, "forceReset:", forceReset); + + if( forceReset ) { + m_error = KErrNone; + emit this->error(QMediaPlayer::NoError, QString()); + return; + } + + // If error does not change and m_error is reseted without forceReset flag + if (error == m_error || + (m_error != KErrNone && error == KErrNone)) + return; + + m_error = error; + QMediaPlayer::Error mediaError = fromSymbianErrorToMultimediaError(m_error); + QString symbianError = QString(errorString); + + if (mediaError != QMediaPlayer::NoError) { + // TODO: fix to user friendly string at some point + // These error string are only dev usable + symbianError.append("Symbian:"); + symbianError.append(QString::number(m_error)); + } + + emit this->error(mediaError, symbianError); + + if (m_error == KErrInUse) { + pause(); + } else if (mediaError != QMediaPlayer::NoError) { + m_play_requested = false; + setMediaStatus(QMediaPlayer::InvalidMedia); + stop(); + } +} + +void S60MediaPlayerSession::setAndEmitError(int error) +{ + m_error = error; + QMediaPlayer::Error rateError = fromSymbianErrorToMultimediaError(error); + QString symbianError; + symbianError.append("Symbian:"); + symbianError.append(QString::number(error)); + emit this->error(rateError, symbianError); + + DP0("S60MediaPlayerSession::setError ---"); +} + +/*! + * emits the signal if there is a changes in position and buffering status. + */ + +void S60MediaPlayerSession::tick() +{ + DP0("S60MediaPlayerSession::tick +++"); + + emit positionChanged(position()); + + if (bufferStatus() < 100) + emit bufferStatusChanged(bufferStatus()); + + DP0("S60MediaPlayerSession::tick ---"); +} + +/*! + * Starts the timer once the media source starts buffering. +*/ + +void S60MediaPlayerSession::startProgressTimer() +{ + DP0("S60MediaPlayerSession::startProgressTimer +++"); + + m_progressTimer->start(500); + + DP0("S60MediaPlayerSession::startProgressTimer ---"); +} + +/*! + * Stops the timer once the media source finished buffering. +*/ + +void S60MediaPlayerSession::stopProgressTimer() +{ + DP0("S60MediaPlayerSession::stopProgressTimer +++"); + + m_progressTimer->stop(); + + DP0("S60MediaPlayerSession::stopProgressTimer ---"); +} + +/*! + * Starts the timer while waiting for some events to happen like source buffering or call backs etc. + * So that if the events doesn't occur before stalled timer stops, it'll set the error/media status etc. +*/ + +void S60MediaPlayerSession::startStalledTimer() +{ + DP0("S60MediaPlayerSession::startStalledTimer +++"); + + m_stalledTimer->start(30000); + + DP0("S60MediaPlayerSession::startStalledTimer ---"); +} + +/*! + * Stops the timer when some events occurred while waiting for them. + * media source started buffering or call back is received etc. +*/ + +void S60MediaPlayerSession::stopStalledTimer() +{ + DP0("S60MediaPlayerSession::stopStalledTimer +++"); + + m_stalledTimer->stop(); + + DP0("S60MediaPlayerSession::stopStalledTimer ---"); +} + +/*! + * \return Converted Symbian specific Descriptor to QString. +*/ + +QString S60MediaPlayerSession::TDesC2QString(const TDesC& aDescriptor) +{ + DP0("S60MediaPlayerSession::TDesC2QString"); + + return QString::fromUtf16(aDescriptor.Ptr(), aDescriptor.Length()); +} + +/*! + * \return Converted QString to non-modifiable pointer Descriptor. +*/ + +TPtrC S60MediaPlayerSession::QString2TPtrC( const QString& string ) +{ + DP0("S60MediaPlayerSession::QString2TPtrC"); + + // Returned TPtrC is valid as long as the given parameter is valid and unmodified + return TPtrC16(static_cast<const TUint16*>(string.utf16()), string.length()); +} + +/*! + * \return Converted Symbian TRect object to QRect object. +*/ + +QRect S60MediaPlayerSession::TRect2QRect(const TRect& tr) +{ + DP0("S60MediaPlayerSession::TRect2QRect"); + + return QRect(tr.iTl.iX, tr.iTl.iY, tr.Width(), tr.Height()); +} + +/*! + * \return converted QRect object to Symbian specific TRec object. + */ + +TRect S60MediaPlayerSession::QRect2TRect(const QRect& qr) +{ + DP0("S60MediaPlayerSession::QRect2TRect"); + + return TRect(TPoint(qr.left(), qr.top()), TSize(qr.width(), qr.height())); +} + +/*! + \fn bool S60MediaPlayerSession::isVideoAvailable(); + + + Returns TRUE if Video is available. +*/ + +/*! + \fn bool S60MediaPlayerSession::isAudioAvailable(); + + + Returns TRUE if Audio is available. +*/ + +/*! + \fn void S60MediaPlayerSession::setPlaybackRate (qreal rate); + + + Sets \a rate play back rate on media source. getIsSeekable +*/ + +/*! + \fn bool S60MediaPlayerSession::getIsSeekable () const; + + + \return TRUE if Seekable possible on current media source else FALSE. +*/ + +/*! + \fn QString S60MediaPlayerSession::activeEndpoint () const; + + + \return active end point name.. +*/ + +/*! + \fn QString S60MediaPlayerSession::defaultEndpoint () const; + + + \return default end point name. +*/ + diff --git a/src/plugins/symbian/mmf/mediaplayer/s60mediaplayersession.h b/src/plugins/symbian/mmf/mediaplayer/s60mediaplayersession.h new file mode 100644 index 000000000..e6889d101 --- /dev/null +++ b/src/plugins/symbian/mmf/mediaplayer/s60mediaplayersession.h @@ -0,0 +1,187 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** +****************************************************************************/ + +#ifndef S60MEDIAPLAYERSESSION_H +#define S60MEDIAPLAYERSESSION_H + +#include <QtCore/qobject.h> +#include <QtCore/qurl.h> +#include <QtCore/qpair.h> +#include <qmediaplayer.h> +#include <e32cmn.h> // for TDesC +#include <QRect> +#include "s60mediaplayerservice.h" + + +_LIT( KSeekable, "Seekable" ); +_LIT( KFalse, "0"); + +QT_BEGIN_NAMESPACE +class QMediaTimeRange; +QT_END_NAMESPACE + +class QTimer; + +class S60MediaPlayerSession : public QObject +{ + Q_OBJECT + +public: + S60MediaPlayerSession(QObject *parent); + virtual ~S60MediaPlayerSession(); + + // for player control interface to use + QMediaPlayer::State state() const; + QMediaPlayer::MediaStatus mediaStatus() const; + qint64 duration() const; + qint64 position() const; + void setPosition(qint64 pos); + int volume() const; + void setVolume(int volume); + bool isMuted() const; + void setMuted(bool muted); + virtual bool isVideoAvailable() = 0; + virtual bool isAudioAvailable() = 0; + bool isSeekable() const; + void play(); + void pause(); + void stop(); + void reset(); + bool isMetadataAvailable() const; + QVariant metaData(const QString &key) const; + QVariant metaData(QtMultimediaKit::MetaData key) const; + QList<QtMultimediaKit::MetaData> availableMetaData() const; + QStringList availableExtendedMetaData() const; + QString metaDataKeyAsString(QtMultimediaKit::MetaData key) const; + void load(const QMediaContent source); + int bufferStatus(); + virtual void setVideoRenderer(QObject *renderer); + void setMediaStatus(QMediaPlayer::MediaStatus); + void setState(QMediaPlayer::State state); + void setAudioEndpoint(const QString& audioEndpoint); + virtual void setPlaybackRate(qreal rate) = 0; + virtual bool getIsSeekable() const { return ETrue; } + TBool isStreaming(); + +protected: + virtual void doLoadL(const TDesC &path) = 0; + virtual void doLoadUrlL(const TDesC &path) = 0; + virtual void doPlay() = 0; + virtual void doStop() = 0; + virtual void doClose() = 0; + virtual void doPauseL() = 0; + virtual void doSetVolumeL(int volume) = 0; + virtual void doSetPositionL(qint64 microSeconds) = 0; + virtual qint64 doGetPositionL() const = 0; + virtual void updateMetaDataEntriesL() = 0; + virtual int doGetBufferStatusL() const = 0; + virtual qint64 doGetDurationL() const = 0; + virtual void doSetAudioEndpoint(const QString& audioEndpoint) = 0; + +public: + // From S60MediaPlayerAudioEndpointSelector + virtual QString activeEndpoint() const = 0; + virtual QString defaultEndpoint() const = 0; +public Q_SLOTS: + virtual void setActiveEndpoint(const QString& name) = 0; + +protected: + int error() const; + void setError(int error, const QString &errorString = QString(), bool forceReset = false); + void setAndEmitError(int error); + void loaded(); + void buffering(); + void buffered(); + void endOfMedia(); + QMap<QString, QVariant>& metaDataEntries(); + QMediaPlayer::Error fromSymbianErrorToMultimediaError(int error); + void startProgressTimer(); + void stopProgressTimer(); + void startStalledTimer(); + void stopStalledTimer(); + QString TDesC2QString(const TDesC& aDescriptor); + TPtrC QString2TPtrC( const QString& string ); + QRect TRect2QRect(const TRect& tr); + TRect QRect2TRect(const QRect& qr); + +protected slots: + void tick(); + void stalled(); + +signals: + void durationChanged(qint64 duration); + void positionChanged(qint64 position); + void stateChanged(QMediaPlayer::State state); + void mediaStatusChanged(QMediaPlayer::MediaStatus mediaStatus); + void videoAvailableChanged(bool videoAvailable); + void audioAvailableChanged(bool audioAvailable); + void bufferStatusChanged(int percentFilled); + void seekableChanged(bool); + void availablePlaybackRangesChanged(const QMediaTimeRange&); + void metaDataChanged(); + void error(int error, const QString &errorString); + void activeEndpointChanged(const QString &name); + void mediaChanged(); + void playbackRateChanged(qreal rate); + void volumeChanged(int volume); + void mutedChanged(bool muted); + +protected: + QUrl m_UrlPath; + bool m_stream; + QMediaContent m_source; + +private: + qreal m_playbackRate; + QMap<QString, QVariant> m_metaDataMap; + bool m_muted; + int m_volume; + QMediaPlayer::State m_state; + QMediaPlayer::MediaStatus m_mediaStatus; + QTimer *m_progressTimer; + QTimer *m_stalledTimer; + int m_error; + bool m_play_requested; + bool m_seekable; + qint64 m_duration; +}; + +#endif diff --git a/src/plugins/symbian/mmf/mediaplayer/s60mediarecognizer.cpp b/src/plugins/symbian/mmf/mediaplayer/s60mediarecognizer.cpp new file mode 100644 index 000000000..48b565c34 --- /dev/null +++ b/src/plugins/symbian/mmf/mediaplayer/s60mediarecognizer.cpp @@ -0,0 +1,167 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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 "DebugMacros.h" + +#include "s60mediarecognizer.h" +#include <e32def.h> +#include <e32cmn.h> +#include <QtCore/qurl.h> +#include <QtCore/qdir.h> +#include <QtCore/qdebug.h> + +#include <apgcli.h> + +static const TInt KMimeTypePrefixLength = 6; // "audio/" or "video/" + +_LIT(KMimeTypePrefixAudio, "audio/"); +_LIT(KMimeTypePrefixVideo, "video/"); +_LIT(KMimeTypeRingingTone, "application/vnd.nokia.ringing-tone"); + +/*! + Construct a media Recognizer with the given \a parent. +*/ + +S60MediaRecognizer::S60MediaRecognizer(QObject *parent) : QObject(parent) +{ + DP0("S60MediaRecognizer::S60MediaRecognizer +++"); + DP0("S60MediaRecognizer::S60MediaRecognizer ---"); +} + +/*! + Destroys a media Recognizer. +*/ + +S60MediaRecognizer::~S60MediaRecognizer() +{ + DP0("S60MediaRecognizer::~S60MediaRecognizer +++"); + + m_file.Close(); + m_fileServer.Close(); + m_recognizer.Close(); + + DP0("S60MediaRecognizer::~S60MediaRecognizer ---"); +} + +/*! + * \return media type of \a url. + * \a url may be a streaming link or a local file. + * If \a url is local file then identifies the media type and returns it. +*/ + +S60MediaRecognizer::MediaType S60MediaRecognizer::mediaType(const QUrl &url) +{ + DP0("S60MediaRecognizer::mediaType"); + + bool isStream = (url.scheme() == "file")?false:true; + + if (isStream) + return Url; + else + return identifyMediaType(QDir::cleanPath(url.toLocalFile())); +} + +/*! + * \return Media type of \a file name by recognizing its mimetype whether its audio or video. +*/ + +S60MediaRecognizer::MediaType S60MediaRecognizer::identifyMediaType(const QString& fileName) +{ + DP0("S60MediaRecognizer::identifyMediaType +++"); + + DP1("S60MediaRecognizer::identifyMediaType - ", fileName); + + S60MediaRecognizer::MediaType result = Video; // default to videoplayer + bool recognizerOpened = false; + + TInt err = m_recognizer.Connect(); + if (err == KErrNone) { + recognizerOpened = true; + } + + err = m_fileServer.Connect(); + if (err == KErrNone) { + recognizerOpened = true; + } + + // This is needed for sharing file handles for the recognizer + err = m_fileServer.ShareProtected(); + if (err == KErrNone) { + recognizerOpened = true; + } + + if (recognizerOpened) { + m_file.Close(); + err = m_file.Open(m_fileServer, QString2TPtrC(QDir::toNativeSeparators(fileName)), EFileRead | + EFileShareReadersOnly); + + if (err == KErrNone) { + TDataRecognitionResult recognizerResult; + err = m_recognizer.RecognizeData(m_file, recognizerResult); + if (err == KErrNone) { + const TPtrC mimeType = recognizerResult.iDataType.Des(); + + if (mimeType.Left(KMimeTypePrefixLength).Compare(KMimeTypePrefixAudio) == 0 || + mimeType.Compare(KMimeTypeRingingTone) == 0) { + result = Audio; + } else if (mimeType.Left(KMimeTypePrefixLength).Compare(KMimeTypePrefixVideo) == 0) { + result = Video; + } + } + } + } + + DP0("S60MediaRecognizer::identifyMediaType ---"); + + return result; +} + +/*! + * \return Symbian modifiable pointer descriptor from a QString \a string. + */ + +TPtrC S60MediaRecognizer::QString2TPtrC( const QString& string ) +{ + DP1("S60MediaRecognizer::QString2TPtrC - ", string); + + // Returned TPtrC is valid as long as the given parameter is valid and unmodified + return TPtrC16(static_cast<const TUint16*>(string.utf16()), string.length()); +} diff --git a/src/plugins/symbian/mmf/mediaplayer/s60mediarecognizer.h b/src/plugins/symbian/mmf/mediaplayer/s60mediarecognizer.h new file mode 100644 index 000000000..bdd0caabe --- /dev/null +++ b/src/plugins/symbian/mmf/mediaplayer/s60mediarecognizer.h @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** +****************************************************************************/ + +#ifndef S60MEDIARECOGNIZER_H_ +#define S60MEDIARECOGNIZER_H_ + +#include <QtCore/qobject.h> + +#include <apgcli.h> +#include <f32file.h> + +class QUrl; + +class S60MediaRecognizer : public QObject +{ + Q_OBJECT + +public: + enum MediaType { + Audio, + Video, + Url, + NotSupported = -1 + }; + + S60MediaRecognizer(QObject *parent = 0); + ~S60MediaRecognizer(); + + S60MediaRecognizer::MediaType mediaType(const QUrl &url); + S60MediaRecognizer::MediaType identifyMediaType(const QString& fileName); + +protected: + TPtrC QString2TPtrC( const QString& string ); + +private: + RApaLsSession m_recognizer; + RFile m_file; + RFs m_fileServer; +}; + +#endif /* S60MEDIARECOGNIZER_H_ */ diff --git a/src/plugins/symbian/mmf/mediaplayer/s60mediastreamcontrol.cpp b/src/plugins/symbian/mmf/mediaplayer/s60mediastreamcontrol.cpp new file mode 100644 index 000000000..9a2ce5c02 --- /dev/null +++ b/src/plugins/symbian/mmf/mediaplayer/s60mediastreamcontrol.cpp @@ -0,0 +1,201 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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 "DebugMacros.h" + +#include "s60mediastreamcontrol.h" +#include "s60mediaplayersession.h" +#include "s60mediaplayercontrol.h" +#include <qmediastreamscontrol.h> + +#include <QtCore/qdir.h> +#include <QtCore/qurl.h> +#include <QtCore/qdebug.h> + +/*! + Constructs a new media streams control with the given \a control. +*/ + +S60MediaStreamControl::S60MediaStreamControl(QObject *control, QObject *parent) + : QMediaStreamsControl(parent) + , m_control(NULL) + , m_mediaType(S60MediaSettings::Unknown) +{ + DP0("S60MediaStreamControl::S60MediaStreamControl +++"); + + m_control = qobject_cast<S60MediaPlayerControl*>(control); + m_mediaType = m_control->mediaControlSettings().mediaType(); + + DP0("S60MediaStreamControl::S60MediaStreamControl ---"); +} + +/*! + Destroys a media streams control. +*/ + +S60MediaStreamControl::~S60MediaStreamControl() +{ + DP0("S60MediaStreamControl::~S60MediaStreamControl +++"); + DP0("S60MediaStreamControl::~S60MediaStreamControl ---"); +} + +/*! + \return the number of media streams. +*/ + +int S60MediaStreamControl::streamCount() +{ + DP0("S60MediaStreamControl::streamCount"); + + int streamCount = 0; + if (m_control->isAudioAvailable()) + streamCount++; + if (m_control->isVideoAvailable()) + streamCount++; + DP1("S60MediaStreamControl::streamCount", streamCount); + + return streamCount; +} + +/*! + \return the type of a media \a streamNumber. +*/ + +QMediaStreamsControl::StreamType S60MediaStreamControl::streamType(int streamNumber) +{ + DP0("S60MediaStreamControl::streamType +++"); + + DP1("S60MediaStreamControl::streamType - ", streamNumber); + + Q_UNUSED(streamNumber); + + QMediaStreamsControl::StreamType type = QMediaStreamsControl::UnknownStream; + + if (m_control->mediaControlSettings().mediaType() == S60MediaSettings::Video) + type = QMediaStreamsControl::VideoStream; + else + type = QMediaStreamsControl::AudioStream; + + DP0("S60MediaStreamControl::streamType ---"); + + return type; +} + +/*! + \return the meta-data value of \a key for a given \a streamNumber. + + Useful metadata keya are QtMultimediaKit::Title, QtMultimediaKit::Description and QtMultimediaKit::Language. +*/ + +QVariant S60MediaStreamControl::metaData(int streamNumber, QtMultimediaKit::MetaData key) +{ + DP0("S60MediaStreamControl::metaData"); + + Q_UNUSED(streamNumber); + + if (m_control->session()) { + if (m_control->session()->isMetadataAvailable()) + return m_control->session()->metaData(key); + } + return QVariant(); +} + +/*! + \return true if the media \a streamNumber is active else false. +*/ + +bool S60MediaStreamControl::isActive(int streamNumber) +{ + DP0("S60MediaStreamControl::isActive +++"); + + DP1("S60MediaStreamControl::isActive - ", streamNumber); + + if (m_control->mediaControlSettings().mediaType() == S60MediaSettings::Video) { + switch (streamNumber) { + case 1: + return m_control->isVideoAvailable(); + case 2: + return m_control->isAudioAvailable(); + default: + break; + } + } + + DP0("S60MediaStreamControl::isActive ---"); + + return m_control->isAudioAvailable(); +} + +/*! + Sets the active \a streamNumber of a media \a state. + + Symbian MMF does not support enabling or disabling specific media streams. + + Setting the active state of a media stream to true will activate it. If any other stream + of the same type was previously active it will be deactivated. Setting the active state fo a + media stream to false will deactivate it. +*/ + +void S60MediaStreamControl::setActive(int streamNumber, bool state) +{ + DP0("S60MediaStreamControl::setActive +++"); + + DP2("S60MediaStreamControl::setActive - ", streamNumber, state); + + Q_UNUSED(streamNumber); + Q_UNUSED(state); + // Symbian MMF does not support enabling or disabling specific media streams + + DP0("S60MediaStreamControl::setActive ---"); +} + +/*! + The signal is emitted when the available streams list is changed. +*/ + +void S60MediaStreamControl::handleStreamsChanged() +{ + DP0("S60MediaStreamControl::handleStreamsChanged +++"); + + emit streamsChanged(); + + DP0("S60MediaStreamControl::handleStreamsChanged ---"); +} diff --git a/src/plugins/symbian/mmf/mediaplayer/s60mediastreamcontrol.h b/src/plugins/symbian/mmf/mediaplayer/s60mediastreamcontrol.h new file mode 100644 index 000000000..702ebc7b2 --- /dev/null +++ b/src/plugins/symbian/mmf/mediaplayer/s60mediastreamcontrol.h @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** +****************************************************************************/ + +#ifndef S60MEDIASTREAMCONTROL_H +#define S60MEDIASTREAMCONTROL_H + +#include <QVariant> + +#include "s60mediaplayercontrol.h" + +#include <qmediastreamscontrol.h> +#include <qtmedianamespace.h> + +QT_USE_NAMESPACE + +class S60MediaPlayerControl; +class S60MediaSettings; + +class S60MediaStreamControl : public QMediaStreamsControl +{ + Q_OBJECT +public: + S60MediaStreamControl(QObject *session, QObject *parent = 0); + ~S60MediaStreamControl(); + + // from QMediaStreamsControl + int streamCount(); + QMediaStreamsControl::StreamType streamType(int streamNumber); + QVariant metaData(int streamNumber, QtMultimediaKit::MetaData key); + bool isActive(int streamNumber); + void setActive(int streamNumber, bool state); + +public Q_SLOTS: + void handleStreamsChanged(); + +private: + S60MediaPlayerControl *m_control; + S60MediaSettings::TMediaType m_mediaType; +}; + +#endif //S60MEDIASTREAMCONTROL_H diff --git a/src/plugins/symbian/mmf/mediaplayer/s60videooutputinterface.h b/src/plugins/symbian/mmf/mediaplayer/s60videooutputinterface.h new file mode 100644 index 000000000..f5388dbbc --- /dev/null +++ b/src/plugins/symbian/mmf/mediaplayer/s60videooutputinterface.h @@ -0,0 +1,62 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** +****************************************************************************/ + +#ifndef S60VIDEOOUTPUTINTERFACE_H +#define S60VIDEOOUTPUTINTERFACE_H + +#include <QtCore/qglobal.h> +#include <QtGui/qwindowdefs.h> +#include <coecntrl.h> + +class S60VideoOutputInterface +{ +public: + RWindow *videoWindowHandle() const { return videoWinId() ? static_cast<RWindow *>(videoWinId()->DrawableWindow()) : 0 ; } + virtual WId videoWinId() const = 0; + // If VIDEOOUTPUT_GRAPHICS_SURFACES is defined, the return value is the video + // rectangle relative to the video window. If not, the return value is the + // absolute screen rectangle. + virtual QRect videoDisplayRect() const = 0; + virtual Qt::AspectRatioMode videoAspectRatio() const = 0; +}; + +#endif // S60VIDEOOUTPUTINTERFACE_H + diff --git a/src/plugins/symbian/mmf/mediaplayer/s60videoplayersession.cpp b/src/plugins/symbian/mmf/mediaplayer/s60videoplayersession.cpp new file mode 100644 index 000000000..49d511ca2 --- /dev/null +++ b/src/plugins/symbian/mmf/mediaplayer/s60videoplayersession.cpp @@ -0,0 +1,1124 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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 "DebugMacros.h" + +#include "s60videoplayersession.h" +#include "s60mediaplayerservice.h" +#include "s60videowidgetcontrol.h" +#include "s60videowidgetdisplay.h" +#include "s60videowindowcontrol.h" +#include "s60videowindowdisplay.h" + +#include <QtCore/QTimer> +#include <QtGui/QApplication> +#include <QtGui/QDesktopWidget> +#include <QtGui/QSymbianEvent> +#include <QtGui/QWidget> + +#include <coecntrl.h> +#include <coemain.h> // For CCoeEnv +#include <w32std.h> +#include <mmf/common/mmferrors.h> +#include <mmf/common/mmfcontrollerframeworkbase.h> +#include <MMFROPCustomCommandConstants.h> +#ifdef HTTP_COOKIES_ENABLED +#include <MMFSessionInfoCustomCommandConstants.h> +#endif + +const QString DefaultAudioEndpoint = QLatin1String("Default"); +const TUid KHelixUID = {0x101F8514}; + +//Hard-coding the command to support older versions. +const TInt KMMFROPControllerEnablePausedLoadingStatus = 7; + +TVideoRotation videoRotation(qreal angle) +{ + // Convert to clockwise + angle = 360.0f - angle; + while (angle >= 360.0f) + angle -= 360.0f; + TVideoRotation result = EVideoRotationNone; + if (angle >= 45.0f && angle < 135.0f) + result = EVideoRotationClockwise90; + else if (angle >= 135.0f && angle < 225.0f) + result = EVideoRotationClockwise180; + else if (angle >= 225.0f && angle < 315.0f) + result = EVideoRotationClockwise270; + return result; +} + +S60VideoPlayerEventHandler *S60VideoPlayerEventHandler::m_instance = 0; +QCoreApplication::EventFilter S60VideoPlayerEventHandler::m_eventFilter = 0; +QList<ApplicationFocusObserver *> S60VideoPlayerEventHandler::m_applicationFocusObservers; + +S60VideoPlayerEventHandler *S60VideoPlayerEventHandler::instance() +{ + if (!m_instance) + m_instance = new S60VideoPlayerEventHandler(); + return m_instance; +} + +S60VideoPlayerEventHandler::S60VideoPlayerEventHandler() +{ + m_eventFilter = QCoreApplication::instance()->setEventFilter(filterEvent); +} + +S60VideoPlayerEventHandler::~S60VideoPlayerEventHandler() +{ + QCoreApplication::instance()->setEventFilter(m_eventFilter); +} + +void S60VideoPlayerEventHandler::addApplicationFocusObserver(ApplicationFocusObserver *observer) +{ + m_applicationFocusObservers.append(observer); +} + +void S60VideoPlayerEventHandler::removeApplicationFocusObserver(ApplicationFocusObserver *observer) +{ + m_applicationFocusObservers.removeAt(m_applicationFocusObservers.indexOf(observer)); + if (m_applicationFocusObservers.count() == 0) { + delete m_instance; + m_instance = 0; + } +} + +bool S60VideoPlayerEventHandler::filterEvent(void *message, long *result) +{ + if (const QSymbianEvent *symbianEvent = reinterpret_cast<const QSymbianEvent*>(message)) { + switch (symbianEvent->type()) { + case QSymbianEvent::WindowServerEvent: + { + const TWsEvent *wsEvent = symbianEvent->windowServerEvent(); + if (EEventFocusLost == wsEvent->Type() || EEventFocusGained == wsEvent->Type()) { + for (QList<ApplicationFocusObserver *>::const_iterator it = m_applicationFocusObservers.constBegin(); + it != m_applicationFocusObservers.constEnd(); ++it) { + if (EEventFocusLost == wsEvent->Type()) + (*it)->applicationLostFocus(); + else if (EEventFocusGained == wsEvent->Type()) + (*it)->applicationGainedFocus(); + } + } + } + break; + default: + break; + } + } + bool ret = false; + if (m_eventFilter) + ret = m_eventFilter(message, result); + return ret; +} + +/*! + Constructs the CVideoPlayerUtility2 object with given \a service and \a object. + And Registers for Video Loading Notifications. +*/ +S60VideoPlayerSession::S60VideoPlayerSession(QMediaService *service, S60MediaNetworkAccessControl *object) + : S60MediaPlayerSession(service) + , m_accessPointId(0) + , m_wsSession(&CCoeEnv::Static()->WsSession()) + , m_screenDevice(CCoeEnv::Static()->ScreenDevice()) + , m_service(service) + , m_player(0) +#ifndef VIDEOOUTPUT_GRAPHICS_SURFACES + , m_dsaActive(false) + , m_dsaStopped(false) +#endif + , m_videoOutputControl(0) + , m_videoOutputDisplay(0) + , m_displayWindow(0) +#ifdef HAS_AUDIOROUTING_IN_VIDEOPLAYER + , m_audioOutput(0) +#endif + , m_audioEndpoint(DefaultAudioEndpoint) + , m_pendingChanges(0) + , m_backendInitiatedPause(false) +#ifdef HTTP_COOKIES_ENABLED + , m_destinationPckg(KUidInterfaceMMFControllerSessionInfo) +#endif +{ + DP0("S60VideoPlayerSession::S60VideoPlayerSession +++"); + + m_networkAccessControl = object; +#ifdef VIDEOOUTPUT_GRAPHICS_SURFACES + QT_TRAP_THROWING(m_player = CVideoPlayerUtility2::NewL( + *this, + 0, + EMdaPriorityPreferenceNone + )); + m_player->RegisterForVideoLoadingNotification(*this); +#else + RWindow *window = 0; + QRect extentRect; + QWidget *widget = QApplication::activeWindow(); + if (!widget) + widget = QApplication::allWidgets().at(0); + Q_ASSERT(widget); + WId wid = widget->effectiveWinId(); + if (!wid) + wid = widget->winId(); + window = static_cast<RWindow *>(wid->DrawableWindow()); + extentRect = QRect(widget->mapToGlobal(widget->pos()), widget->size()); + TRect clipRect = QRect2TRect(extentRect); + const TRect desktopRect = QRect2TRect(QApplication::desktop()->screenGeometry()); + clipRect.Intersection(desktopRect); + QT_TRAP_THROWING(m_player = CVideoPlayerUtility::NewL( + *this, + 0, + EMdaPriorityPreferenceNone, + *m_wsSession, + *m_screenDevice, + *window, + QRect2TRect(extentRect), + clipRect)); + m_dsaActive = true; + m_player->RegisterForVideoLoadingNotification(*this); +#endif // VIDEOOUTPUT_GRAPHICS_SURFACES + S60VideoPlayerEventHandler::instance()->addApplicationFocusObserver(this); + DP0("S60VideoPlayerSession::S60VideoPlayerSession ---"); +} + +/*! + Destroys the CVideoPlayerUtility2 object. + + And Unregister the observer. +*/ + +S60VideoPlayerSession::~S60VideoPlayerSession() +{ + DP0("S60VideoPlayerSession::~S60VideoPlayerSession +++"); + S60VideoPlayerEventHandler::instance()->removeApplicationFocusObserver(this); +#ifdef HAS_AUDIOROUTING_IN_VIDEOPLAYER + if (m_audioOutput) + m_audioOutput->UnregisterObserver(*this); + delete m_audioOutput; +#endif + m_player->Close(); + delete m_player; + + DP0("S60VideoPlayerSession::~S60VideoPlayerSession ---"); +} + +void S60VideoPlayerSession::applicationGainedFocus() +{ + if (m_backendInitiatedPause) { + m_backendInitiatedPause = false; + play(); + } + if (QMediaPlayer::PausedState == state()) { + TRAPD(err, m_player->RefreshFrameL()); + setError(err); + } +} + +void S60VideoPlayerSession::applicationLostFocus() +{ + if (QMediaPlayer::PlayingState == state()) { + m_backendInitiatedPause = true; + pause(); + } +} + +/*! + + Opens the a file from \a path. +*/ + +void S60VideoPlayerSession::doLoadL(const TDesC &path) +{ + DP0("S60VideoPlayerSession::doLoadL +++"); + +#ifdef HAS_AUDIOROUTING_IN_VIDEOPLAYER + // m_audioOutput needs to be reinitialized after MapcInitComplete + if (m_audioOutput) + m_audioOutput->UnregisterObserver(*this); + delete m_audioOutput; + m_audioOutput = NULL; +#endif + m_player->OpenFileL(path, KHelixUID); + + DP0("S60VideoPlayerSession::doLoadL ---"); +} + +/*! + Sets the playbackRate with \a rate. +*/ + +void S60VideoPlayerSession::setPlaybackRate(qreal rate) +{ + DP0("S60VideoPlayerSession::setPlaybackRate +++"); + + DP1("S60VideoPlayerSession::setPlaybackRate - ", rate); + + /* + * setPlaybackRate is not supported in S60 3.1 and 3.2 + * This flag will be defined for 3.1 and 3.2 + */ +#ifndef PLAY_RATE_NOT_SUPPORTED + //setPlayVelocity requires rate in the form of + //50 = 0.5x ;100 = 1.x ; 200 = 2.x ; 300 = 3.x + //so multiplying rate with 100 + TRAPD(err, m_player->SetPlayVelocityL((TInt)(rate*100))); + if (KErrNone == err) + emit playbackRateChanged(rate); + else + setError(err); +#endif + + DP0("S60VideoPlayerSession::setPlaybackRate ---"); +} + +/*! + + Opens the a Url from \a path for streaming the source. +*/ + +void S60VideoPlayerSession::doLoadUrlL(const TDesC &path) +{ + DP0("S60VideoPlayerSession::doLoadUrlL +++"); + +#ifdef HAS_AUDIOROUTING_IN_VIDEOPLAYER + // m_audioOutput needs to be reinitialized after MapcInitComplete + if (m_audioOutput) + m_audioOutput->UnregisterObserver(*this); + delete m_audioOutput; + m_audioOutput = NULL; +#endif + m_accessPointId = m_networkAccessControl->accessPointId(); + m_player->OpenUrlL(path, m_accessPointId, KNullDesC8, KHelixUID); + + DP0("S60VideoPlayerSession::doLoadUrlL ---"); +} + +/*! + + Returns the percentage of the video clip loaded. +*/ + +int S60VideoPlayerSession::doGetBufferStatusL() const +{ + // DP0("S60VideoPlayerSession::doGetBufferStatusL +++"); + + int progress = 0; + m_player->GetVideoLoadingProgressL(progress); + + // DP0("S60VideoPlayerSession::doGetBufferStatusL ---"); + + return progress; +} + +/*! + Returns the duration of the video sample in microseconds. +*/ + +qint64 S60VideoPlayerSession::doGetDurationL() const +{ + // DP0("S60VideoPlayerSession::doGetDurationL"); + + return m_player->DurationL().Int64() / qint64(1000); +} + +/*! + * Sets the \a videooutput for video rendering. +*/ + +void S60VideoPlayerSession::setVideoRenderer(QObject *videoOutput) +{ + DP0("S60VideoPlayerSession::setVideoRenderer +++"); + if (videoOutput != m_videoOutputControl) { + if (m_videoOutputDisplay) { + disconnect(m_videoOutputDisplay); + m_videoOutputDisplay->disconnect(this); + m_videoOutputDisplay = 0; + } + if (videoOutput) { + if (S60VideoWidgetControl *control = qobject_cast<S60VideoWidgetControl *>(videoOutput)) + m_videoOutputDisplay = control->display(); + if (!m_videoOutputDisplay) + return; + m_videoOutputDisplay->setNativeSize(m_nativeSize); + connect(this, SIGNAL(nativeSizeChanged(QSize)), m_videoOutputDisplay, SLOT(setNativeSize(QSize))); + connect(m_videoOutputDisplay, SIGNAL(windowHandleChanged(RWindow *)), this, SLOT(windowHandleChanged())); + connect(m_videoOutputDisplay, SIGNAL(displayRectChanged(QRect, QRect)), this, SLOT(displayRectChanged())); + connect(m_videoOutputDisplay, SIGNAL(aspectRatioModeChanged(Qt::AspectRatioMode)), this, SLOT(aspectRatioChanged())); + connect(m_videoOutputDisplay, SIGNAL(rotationChanged(qreal)), this, SLOT(rotationChanged())); +#ifndef VIDEOOUTPUT_GRAPHICS_SURFACES + connect(m_videoOutputDisplay, SIGNAL(beginVideoWindowNativePaint()), this, SLOT(suspendDirectScreenAccess())); + connect(m_videoOutputDisplay, SIGNAL(endVideoWindowNativePaint()), this, SLOT(resumeDirectScreenAccess())); +#endif + } + m_videoOutputControl = videoOutput; + windowHandleChanged(); + } + + DP0("S60VideoPlayerSession::setVideoRenderer ---"); +} + +/*! + * Apply the pending changes for window. +*/ +void S60VideoPlayerSession::applyPendingChanges(bool force) +{ + DP0("S60VideoPlayerSession::applyPendingChanges +++"); + + if ( force + || QMediaPlayer::LoadedMedia == mediaStatus() + || QMediaPlayer::StalledMedia == mediaStatus() + || QMediaPlayer::BufferingMedia == mediaStatus() + || QMediaPlayer::BufferedMedia == mediaStatus() + || QMediaPlayer::EndOfMedia == mediaStatus()) { + int error = KErrNone; + RWindow *const window = m_videoOutputDisplay ? m_videoOutputDisplay->windowHandle() : 0; + const QRect extentRect = m_videoOutputDisplay ? m_videoOutputDisplay->extentRect() : QRect(); + const QRect clipRect = m_videoOutputDisplay ? m_videoOutputDisplay->clipRect() : QRect(); +#ifdef VIDEOOUTPUT_GRAPHICS_SURFACES + if (m_pendingChanges & WindowHandle) { + if (m_displayWindow) { + m_player->RemoveDisplayWindow(*m_displayWindow); + m_displayWindow = 0; + } + if (window) { + TRAP(error, m_player->AddDisplayWindowL(*m_wsSession, *m_screenDevice, + *window, + QRect2TRect(extentRect), + QRect2TRect(clipRect))); + if (KErrNone == error) + m_displayWindow = window; + } + m_pendingChanges = ScaleFactors; + } + if (KErrNone == error && (m_pendingChanges & DisplayRect) && m_displayWindow) { + TRAP(error, m_player->SetVideoExtentL(*m_displayWindow, QRect2TRect(extentRect))); + if (KErrNone == error) + TRAP(error, m_player->SetWindowClipRectL(*m_displayWindow, QRect2TRect(clipRect))); + m_pendingChanges ^= DisplayRect; + m_pendingChanges |= ScaleFactors; + } +#else + if (m_pendingChanges & WindowHandle || m_pendingChanges & DisplayRect) { + if (window) { + TRAP(error, m_player->SetDisplayWindowL(*m_wsSession, *m_screenDevice, + *window, + QRect2TRect(extentRect), + QRect2TRect(clipRect))); + if (KErrNone == error) + m_displayWindow = window; + } + m_dsaActive = (KErrNone == error); + m_dsaStopped = false; + m_pendingChanges = ScaleFactors; + } + +#endif // VIDEOOUTPUT_GRAPHICS_SURFACES + if (KErrNone == error && (m_pendingChanges & ScaleFactors) && m_displayWindow && m_videoOutputDisplay) { + const TVideoRotation rotation = videoRotation(m_videoOutputDisplay->rotation()); + const bool swap = (rotation == EVideoRotationClockwise90 || rotation == EVideoRotationClockwise270); + const QSize extentSize = swap ? QSize(extentRect.height(), extentRect.width()) : extentRect.size(); + QSize scaled = m_nativeSize; + if (m_videoOutputDisplay->aspectRatioMode() == Qt::IgnoreAspectRatio) + scaled.scale(extentSize, Qt::IgnoreAspectRatio); + else if (m_videoOutputDisplay->aspectRatioMode() == Qt::KeepAspectRatio) + scaled.scale(extentSize, Qt::KeepAspectRatio); + else if (m_videoOutputDisplay->aspectRatioMode() == Qt::KeepAspectRatioByExpanding) + scaled.scale(extentSize, Qt::KeepAspectRatioByExpanding); + const qreal width = qreal(scaled.width()) / qreal(m_nativeSize.width()) * qreal(100); + const qreal height = qreal(scaled.height()) / qreal(m_nativeSize.height()) * qreal(100); +#ifdef VIDEOOUTPUT_GRAPHICS_SURFACES + TRAP(error, m_player->SetScaleFactorL(*m_displayWindow, width, height)); +#else + static const TBool antialias = ETrue; + TRAP(error, m_player->SetScaleFactorL(width, height, antialias)); +#endif // VIDEOOUTPUT_GRAPHICS_SURFACES + m_pendingChanges ^= ScaleFactors; + } + if (KErrNone == error && (m_pendingChanges && Rotation) && m_displayWindow && m_videoOutputDisplay) { + const TVideoRotation rotation = videoRotation(m_videoOutputDisplay->rotation()); +#ifdef VIDEOOUTPUT_GRAPHICS_SURFACES + TRAP(error, m_player->SetRotationL(*m_displayWindow, rotation)); +#else + TRAP(error, m_player->SetRotationL(rotation)); +#endif // VIDEOOUTPUT_GRAPHICS_SURFACES + m_pendingChanges ^= Rotation; + } + setError(error); + } + + DP0("S60VideoPlayerSession::applyPendingChanges ---"); +} + +/*! + * \return TRUE if video is available. +*/ + +bool S60VideoPlayerSession::isVideoAvailable() +{ + DP0("S60VideoPlayerSession::isVideoAvailable"); + +#ifdef PRE_S60_50_PLATFORM + return true; // this is not supported in pre 5th platforms +#else + if ( mediaStatus() == QMediaPlayer::LoadingMedia + || mediaStatus() == QMediaPlayer::UnknownMediaStatus + || mediaStatus() == QMediaPlayer::NoMedia + || (mediaStatus() == QMediaPlayer::StalledMedia && state() == QMediaPlayer::StoppedState) + || mediaStatus() == QMediaPlayer::InvalidMedia) + return false; + + if (m_player) { + bool videoAvailable = false; + TRAPD(err, videoAvailable = m_player->VideoEnabledL()); + setError(err); + return videoAvailable; + } else { + return false; + } +#endif + +} + +/*! + * \return TRUE if Audio available. +*/ + +bool S60VideoPlayerSession::isAudioAvailable() +{ + DP0("S60VideoPlayerSession::isAudioAvailable"); + + if ( mediaStatus() == QMediaPlayer::LoadingMedia + || mediaStatus() == QMediaPlayer::UnknownMediaStatus + || mediaStatus() == QMediaPlayer::NoMedia + || (mediaStatus() == QMediaPlayer::StalledMedia && state() == QMediaPlayer::StoppedState) + || mediaStatus() == QMediaPlayer::InvalidMedia) + return false; + + if (m_player) { + bool audioAvailable = false; + TRAPD(err, audioAvailable = m_player->AudioEnabledL()); + setError(err); + return audioAvailable; + } else { + return false; + } +} + +/*! + Start or resume playing the current source. +*/ + +void S60VideoPlayerSession::doPlay() +{ + DP0("S60VideoPlayerSession::doPlay +++"); + + m_player->Play(); + + DP0("S60VideoPlayerSession::doPlay ---"); +} + +/*! + Pause playing the current source. +*/ + +void S60VideoPlayerSession::doPauseL() +{ + DP0("S60VideoPlayerSession::doPauseL +++"); + + m_player->PauseL(); + + DP0("S60VideoPlayerSession::doPauseL ---"); +} + +/*! + + Stop playing, and reset the play position to the beginning. +*/ + +void S60VideoPlayerSession::doStop() +{ + DP0("S60VideoPlayerSession::doStop +++"); + + if (m_stream) + m_networkAccessControl->resetIndex(); + + m_player->Stop(); + + DP0("S60VideoPlayerSession::doStop ---"); +} + +/*! + Closes the current audio clip (allowing another clip to be opened) +*/ + +void S60VideoPlayerSession::doClose() +{ + DP0("S60VideoPlayerSession::doClose +++"); + +#ifdef HAS_AUDIOROUTING_IN_VIDEOPLAYER + if (m_audioOutput) { + m_audioOutput->UnregisterObserver(*this); + delete m_audioOutput; + m_audioOutput = NULL; + } +#endif + + m_player->Close(); + +// close will remove the window handle in media clint video. +// So mark it in pending changes. + m_pendingChanges |= WindowHandle; + + DP0("S60VideoPlayerSession::doClose ---"); +} + +/*! + * Returns the current playback position in microseconds from the start of the clip. + +*/ + +qint64 S60VideoPlayerSession::doGetPositionL() const +{ + // DP0("S60VideoPlayerSession::doGetPositionL"); + + return m_player->PositionL().Int64() / qint64(1000); +} + +/*! + Sets the current playback position to \a microSeconds from the start of the clip. +*/ + +void S60VideoPlayerSession::doSetPositionL(qint64 microSeconds) +{ + // DP0("S60VideoPlayerSession::doSetPositionL"); + + m_player->SetPositionL(TTimeIntervalMicroSeconds(microSeconds)); +} + +/*! + + Changes the current playback volume to specified \a value. +*/ + +void S60VideoPlayerSession::doSetVolumeL(int volume) +{ + DP0("S60VideoPlayerSession::doSetVolumeL +++"); + + DP1("S60VideoPlayerSession::doSetVolumeL - ", volume); + + m_player->SetVolumeL(volume * m_player->MaxVolume() / 100); + + DP0("S60VideoPlayerSession::doSetVolumeL ---"); +} + +/*! + * Notification to the client that the opening of the video clip has completed. + * If successful then an \a aError will be ZERO else system wide error. +*/ + +void S60VideoPlayerSession::MvpuoOpenComplete(TInt aError) +{ + DP0("S60VideoPlayerSession::MvpuoOpenComplete +++"); + + DP1("S60VideoPlayerSession::MvpuoOpenComplete - aError:", aError); + + setError(aError); +#ifdef HTTP_COOKIES_ENABLED + if (KErrNone == aError) { + TInt err(KErrNone); + const QByteArray userAgentString("User-Agent"); + TInt uasize = m_source.canonicalRequest().rawHeader(userAgentString).size(); + TPtrC8 userAgent((const unsigned char*)(m_source.canonicalRequest().rawHeader(userAgentString).constData()), uasize); + if (userAgent.Length()) { + err = m_player->CustomCommandSync(m_destinationPckg, EMMFSetSessionInfo, _L8("User-Agent"), userAgent); + if (err != KErrNone) { + setError(err); + return; + } + } + const QByteArray refererString("Referer"); + TInt refsize = m_source.canonicalRequest().rawHeader(refererString).size(); + TPtrC8 referer((const unsigned char*)m_source.canonicalRequest().rawHeader(refererString).constData(),refsize); + if (referer.Length()) { + err = m_player->CustomCommandSync(m_destinationPckg, EMMFSetSessionInfo, _L8("Referer"), referer); + if (err != KErrNone) { + setError(err); + return; + } + } + const QByteArray cookieString("Cookie"); + TInt cksize = m_source.canonicalRequest().rawHeader(cookieString).size(); + TPtrC8 cookie((const unsigned char*)m_source.canonicalRequest().rawHeader(cookieString).constData(),cksize); + if (cookie.Length()) { + err = m_player->CustomCommandSync(m_destinationPckg, EMMFSetSessionInfo, _L8("Cookie"), cookie); + if (err != KErrNone) { + setError(err); + return; + } + } + m_player->Prepare(); + } +#else + if (KErrNone == aError) + m_player->Prepare(); +#endif + const TMMFMessageDestinationPckg dest( KUidInterfaceMMFROPController ); + TRAP_IGNORE(m_player->CustomCommandSync(dest, KMMFROPControllerEnablePausedLoadingStatus, KNullDesC8, KNullDesC8)); + + DP0("S60VideoPlayerSession::MvpuoOpenComplete ---"); +} + +/*! + * Notification to the client that the opening of the video clip has been preapred. + * If successful then an \a aError will be ZERO else system wide error. +*/ + +void S60VideoPlayerSession::MvpuoPrepareComplete(TInt aError) +{ + DP0("S60VideoPlayerSession::MvpuoPrepareComplete +++"); + + DP1("S60VideoPlayerSession::MvpuoPrepareComplete - aError:", aError); + + if (KErrNone == aError && m_stream) { + emit accessPointChanged(m_accessPointId); + } + if (KErrCouldNotConnect == aError && !(m_networkAccessControl->isLastAccessPoint())) { + load(m_source); + return; + } + TInt error = aError; + if (KErrNone == error || KErrMMPartialPlayback == error) { + TSize originalSize; + TRAP(error, m_player->VideoFrameSizeL(originalSize)); + if (KErrNone == error) { + m_nativeSize = QSize(originalSize.iWidth, originalSize.iHeight); + emit nativeSizeChanged(m_nativeSize); + m_pendingChanges |= ScaleFactors; +#ifdef HAS_AUDIOROUTING_IN_VIDEOPLAYER + Q_ASSERT(!m_audioOutput); + TRAP(error, m_audioOutput = CAudioOutput::NewL(*m_player)); + if (KErrNone == error) { + TRAP(error, m_audioOutput->RegisterObserverL(*this)); + if (KErrNone == error) + setActiveEndpoint(m_audioEndpoint); + } +#endif + } + if (KErrNone == error) { + applyPendingChanges(true); // force apply even though state is not Loaded + if (KErrNone == this->error()) // applyPendingChanges() can call setError() + loaded(); + } + } else { + setError(error); + } + + DP0("S60VideoPlayerSession::MvpuoPrepareComplete ---"); +} + +/*! + * Notification that frame requested by a call to GetFrameL is ready. +*/ + +void S60VideoPlayerSession::MvpuoFrameReady(CFbsBitmap &aFrame, TInt aError) +{ + DP0("S60VideoPlayerSession::MvpuoFrameReady +++"); + + Q_UNUSED(aFrame); + Q_UNUSED(aError); + + DP0("S60VideoPlayerSession::MvpuoFrameReady ---"); +} + +/*! + * Notification that video playback has completed. + * If successful then \a aError will be ZERO else system wide error. + * This not called if playback is explicitly stopped by calling stop. +*/ + +void S60VideoPlayerSession::MvpuoPlayComplete(TInt aError) +{ + DP0("S60VideoPlayerSession::MvpuoPlayComplete +++"); + + DP1("S60VideoPlayerSession::MvpuoPlayComplete - aError", aError); + + if (m_stream) + m_networkAccessControl->resetIndex(); + + if (aError != KErrNone) { + setError(aError); + doClose(); + } else { + endOfMedia(); + } + + DP0("S60VideoPlayerSession::MvpuoPlayComplete ---"); +} + + +/*! + * General \a event notification from controller. + * These events are specified by the supplier of the controller. +*/ + +void S60VideoPlayerSession::MvpuoEvent(const TMMFEvent &aEvent) +{ + DP0("S60VideoPlayerSession::MvpuoEvent +++"); + + Q_UNUSED(aEvent); + + DP0("S60VideoPlayerSession::MvpuoEvent ---"); +} + +/*! + + Updates meta data entries in the current video clip. +*/ + +void S60VideoPlayerSession::updateMetaDataEntriesL() +{ + DP0("S60VideoPlayerSession::updateMetaDataEntriesL +++"); + + metaDataEntries().clear(); + int numberOfMetaDataEntries = 0; + numberOfMetaDataEntries = m_player->NumberOfMetaDataEntriesL(); + for (int i = 0; i < numberOfMetaDataEntries; i++) { + CMMFMetaDataEntry *entry = NULL; + entry = m_player->MetaDataEntryL(i); + metaDataEntries().insert(TDesC2QString(entry->Name()), TDesC2QString(entry->Value())); + delete entry; + } + emit metaDataChanged(); + + DP0("S60VideoPlayerSession::updateMetaDataEntriesL ---"); +} + +/*! + * Apply the window changes when window handle changes. +*/ + +void S60VideoPlayerSession::windowHandleChanged() +{ + DP0("S60VideoPlayerSession::windowHandleChanged +++"); + + m_pendingChanges |= WindowHandle; + applyPendingChanges(); + + DP0("S60VideoPlayerSession::windowHandleChanged ---"); +} + +/*! + * Apply the window changes when display Rect changes. +*/ + +void S60VideoPlayerSession::displayRectChanged() +{ + DP0("S60VideoPlayerSession::displayRectChanged +++"); + + m_pendingChanges |= DisplayRect; + applyPendingChanges(); + + DP0("S60VideoPlayerSession::displayRectChanged ---"); +} + +/*! + * Apply the window changes when aspect Ratio changes. +*/ + +void S60VideoPlayerSession::aspectRatioChanged() +{ + DP0("S60VideoPlayerSession::aspectRatioChanged +++"); + + m_pendingChanges |= ScaleFactors; + applyPendingChanges(); + + DP0("S60VideoPlayerSession::aspectRatioChanged ---"); +} + +void S60VideoPlayerSession::rotationChanged() +{ + m_pendingChanges |= ScaleFactors; + m_pendingChanges |= Rotation; + applyPendingChanges(); +} + +#ifndef VIDEOOUTPUT_GRAPHICS_SURFACES +void S60VideoPlayerSession::suspendDirectScreenAccess() +{ + DP0("S60VideoPlayerSession::suspendDirectScreenAccess +++"); + + m_dsaStopped = stopDirectScreenAccess(); + + DP0("S60VideoPlayerSession::suspendDirectScreenAccess ---"); +} + +void S60VideoPlayerSession::resumeDirectScreenAccess() +{ + DP0("S60VideoPlayerSession::resumeDirectScreenAccess +++"); + + if (!m_dsaStopped) + return; + startDirectScreenAccess(); + m_dsaStopped = false; + + DP0("S60VideoPlayerSession::resumeDirectScreenAccess ---"); +} + +void S60VideoPlayerSession::startDirectScreenAccess() +{ + DP0("S60VideoPlayerSession::startDirectScreenAccess +++"); + + if (m_dsaActive) + return; + TRAPD(err, m_player->StartDirectScreenAccessL()); + if (err == KErrNone) + m_dsaActive = true; + setError(err); + + DP0("S60VideoPlayerSession::startDirectScreenAccess ---"); +} + +bool S60VideoPlayerSession::stopDirectScreenAccess() +{ + DP0("S60VideoPlayerSession::stopDirectScreenAccess"); + + if (!m_dsaActive) + return false; + TRAPD(err, m_player->StopDirectScreenAccessL()); + if (err == KErrNone) + m_dsaActive = false; + setError(err); + return true; +} +#endif + +/*! + * The percentage of the temporary buffer filling before playback begins. +*/ + +void S60VideoPlayerSession::MvloLoadingStarted() +{ + DP0("S60VideoPlayerSession::MvloLoadingStarted +++"); + + buffering(); + + DP0("S60VideoPlayerSession::MvloLoadingStarted ---"); +} + +/*! + * Buffer is filled with data and to for continuing/start playback. +*/ + +void S60VideoPlayerSession::MvloLoadingComplete() +{ + DP0("S60VideoPlayerSession::MvloLoadingComplete +++"); + + buffered(); + + DP0("S60VideoPlayerSession::MvloLoadingComplete ---"); +} + +/*! + Defiens which Audio End point to use. + + \a audioEndpoint audioEndpoint name. +*/ + +void S60VideoPlayerSession::doSetAudioEndpoint(const QString& audioEndpoint) +{ + DP0("S60VideoPlayerSession::doSetAudioEndpoint +++"); + + DP1("S60VideoPlayerSession::doSetAudioEndpoint - ", audioEndpoint); + + m_audioEndpoint = audioEndpoint; + + DP0("S60VideoPlayerSession::doSetAudioEndpoint ---"); +} + +/*! + + Returns audioEndpoint name. +*/ + +QString S60VideoPlayerSession::activeEndpoint() const +{ + DP0("S60VideoPlayerSession::activeEndpoint +++"); + + QString outputName = m_audioEndpoint; +#ifdef HAS_AUDIOROUTING_IN_VIDEOPLAYER + if (m_audioOutput) { + CAudioOutput::TAudioOutputPreference output = m_audioOutput->AudioOutput(); + outputName = qStringFromTAudioOutputPreference(output); + } +#endif + + DP1("S60VideoPlayerSession::activeEndpoint- outputName:", outputName); + DP0("S60VideoPlayerSession::activeEndpoint ---"); + return outputName; +} + +/*! + * Returns default Audio End point in use. +*/ + +QString S60VideoPlayerSession::defaultEndpoint() const +{ + DP0("S60VideoPlayerSession::defaultEndpoint +++"); + + QString outputName = DefaultAudioEndpoint; +#ifdef HAS_AUDIOROUTING_IN_VIDEOPLAYER + if (m_audioOutput) { + CAudioOutput::TAudioOutputPreference output = m_audioOutput->DefaultAudioOutput(); + outputName = qStringFromTAudioOutputPreference(output); + } +#endif + + DP1("S60VideoPlayerSession::defaultEndpoint, outputName:", outputName); + DP0("S60VideoPlayerSession::defaultEndpoint ---"); + + return outputName; +} + +/*! + Sets active end \a name as an Audio End point. +*/ + +void S60VideoPlayerSession::setActiveEndpoint(const QString& name) +{ + DP0("S60VideoPlayerSession::setActiveEndpoint +++"); + + DP1("S60VideoPlayerSession::setActiveEndpoint - ", name); + +#ifdef HAS_AUDIOROUTING_IN_VIDEOPLAYER + CAudioOutput::TAudioOutputPreference output = CAudioOutput::ENoPreference; + if (name == DefaultAudioEndpoint) + output = CAudioOutput::ENoPreference; + else if (name == QString("All")) + output = CAudioOutput::EAll; + else if (name == QString("None")) + output = CAudioOutput::ENoOutput; + else if (name == QString("Earphone")) + output = CAudioOutput::EPrivate; + else if (name == QString("Speaker")) + output = CAudioOutput::EPublic; + if (m_audioOutput) { + TRAPD(err, m_audioOutput->SetAudioOutputL(output)); + setError(err); + } +#endif + + DP0("S60VideoPlayerSession::setActiveEndpoint ---"); +} + +/*! + The default Audio output has been changed. + + \a aAudioOutput Audio Output object. + + \a aNewDefault is CAudioOutput::TAudioOutputPreference. +*/ + +#ifdef HAS_AUDIOROUTING_IN_VIDEOPLAYER +void S60VideoPlayerSession::DefaultAudioOutputChanged( CAudioOutput& aAudioOutput, + CAudioOutput::TAudioOutputPreference aNewDefault) +{ + DP0("S60VideoPlayerSession::DefaultAudioOutputChanged +++"); + + // Emit already implemented in setActiveEndpoint function + Q_UNUSED(aAudioOutput) + Q_UNUSED(aNewDefault) + + DP0("S60VideoPlayerSession::DefaultAudioOutputChanged ---"); +} + +/*! + * \return CAudioOutput::ENoOutput by converting it to QString. +*/ + +QString S60VideoPlayerSession::qStringFromTAudioOutputPreference(CAudioOutput::TAudioOutputPreference output) const +{ + DP0("S60VideoPlayerSession::qStringFromTAudioOutputPreference"); + + if (output == CAudioOutput::ENoPreference) + return QString("Default"); + else if (output == CAudioOutput::EAll) + return QString("All"); + else if (output == CAudioOutput::ENoOutput) + return QString("None"); + else if (output == CAudioOutput::EPrivate) + return QString("Earphone"); + else if (output == CAudioOutput::EPublic) + return QString("Speaker"); + return QString("Default"); +} +#endif //HAS_AUDIOROUTING_IN_VIDEOPLAYER) + +/*! + * \return TRUE if video is Seekable else FALSE. +*/ + +bool S60VideoPlayerSession::getIsSeekable() const +{ + DP0("S60VideoPlayerSession::getIsSeekable +++"); + + bool seekable = ETrue; + int numberOfMetaDataEntries = 0; + + TRAPD(err, numberOfMetaDataEntries = m_player->NumberOfMetaDataEntriesL()); + if (err) + return seekable; + + for (int i = 0; i < numberOfMetaDataEntries; i++) { + CMMFMetaDataEntry *entry = NULL; + TRAP(err, entry = m_player->MetaDataEntryL(i)); + + if (err) + return seekable; + + if (!entry->Name().Compare(KSeekable)) { + if (!entry->Value().Compare(KFalse)) + seekable = EFalse; + break; + } + } + DP0("S60VideoPlayerSession::getIsSeekable ---"); + + return seekable; +} diff --git a/src/plugins/symbian/mmf/mediaplayer/s60videoplayersession.h b/src/plugins/symbian/mmf/mediaplayer/s60videoplayersession.h new file mode 100644 index 000000000..f73683af8 --- /dev/null +++ b/src/plugins/symbian/mmf/mediaplayer/s60videoplayersession.h @@ -0,0 +1,218 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef S60VIDEOPLAYERSESSION_H +#define S60VIDEOPLAYERSESSION_H + +#include "s60mediaplayersession.h" +#include "s60mediaplayeraudioendpointselector.h" +#include "s60medianetworkaccesscontrol.h" +#include "s60videodisplay.h" + +#ifdef VIDEOOUTPUT_GRAPHICS_SURFACES +#include <videoplayer2.h> +#else +#include <videoplayer.h> +#endif // VIDEOOUTPUT_GRAPHICS_SURFACES + +#include <QtCore/QCoreApplication> +#include <QtGui/qwidget.h> +#include <qvideowidget.h> + +#ifdef HAS_AUDIOROUTING_IN_VIDEOPLAYER +#include <AudioOutput.h> +#include <MAudioOutputObserver.h> +#endif // HAS_AUDIOROUTING_IN_VIDEOPLAYER + +class QTimer; +class S60MediaNetworkAccessControl; +class S60VideoDisplay; + +// Helper classes to pass Symbian events from WServ to the S60VideoPlayerSession +// so it can control video player on certain events if required + +class ApplicationFocusObserver +{ +public: + virtual void applicationGainedFocus() = 0; + virtual void applicationLostFocus() = 0; +}; + +class S60VideoPlayerEventHandler : public QObject +{ +public: + static S60VideoPlayerEventHandler *instance(); + static bool filterEvent(void *message, long *result); + void addApplicationFocusObserver(ApplicationFocusObserver* observer); + void removeApplicationFocusObserver(ApplicationFocusObserver* observer); +private: + S60VideoPlayerEventHandler(); + ~S60VideoPlayerEventHandler(); +private: + static S60VideoPlayerEventHandler *m_instance; + static QList<ApplicationFocusObserver *> m_applicationFocusObservers; + static QCoreApplication::EventFilter m_eventFilter; +}; + +class S60VideoPlayerSession : public S60MediaPlayerSession + , public MVideoPlayerUtilityObserver + , public MVideoLoadingObserver +#ifdef HAS_AUDIOROUTING_IN_VIDEOPLAYER + , public MAudioOutputObserver +#endif // HAS_AUDIOROUTING_IN_VIDEOPLAYER + , public ApplicationFocusObserver +{ + Q_OBJECT +public: + S60VideoPlayerSession(QMediaService *service, S60MediaNetworkAccessControl *object); + ~S60VideoPlayerSession(); + + // From S60MediaPlayerSession + bool isVideoAvailable(); + bool isAudioAvailable(); + void setVideoRenderer(QObject *renderer); + + // From MVideoLoadingObserver + void MvloLoadingStarted(); + void MvloLoadingComplete(); + void setPlaybackRate(qreal rate); +#ifdef HAS_AUDIOROUTING_IN_VIDEOPLAYER + // From MAudioOutputObserver + void DefaultAudioOutputChanged(CAudioOutput& aAudioOutput, + CAudioOutput::TAudioOutputPreference aNewDefault); +#endif + + // From S60MediaPlayerAudioEndpointSelector + QString activeEndpoint() const; + QString defaultEndpoint() const; + + // ApplicationFocusObserver + void applicationGainedFocus(); + void applicationLostFocus(); + +signals: + void nativeSizeChanged(QSize); + +public Q_SLOTS: + void setActiveEndpoint(const QString& name); + +signals: + void accessPointChanged(int); + +protected: + // From S60MediaPlayerSession + void doLoadL(const TDesC &path); + void doLoadUrlL(const TDesC &path); + void doPlay(); + void doStop(); + void doClose(); + void doPauseL(); + void doSetVolumeL(int volume); + qint64 doGetPositionL() const; + void doSetPositionL(qint64 microSeconds); + void updateMetaDataEntriesL(); + int doGetBufferStatusL() const; + qint64 doGetDurationL() const; + void doSetAudioEndpoint(const QString& audioEndpoint); + bool getIsSeekable() const; + +private slots: + void windowHandleChanged(); + void displayRectChanged(); + void aspectRatioChanged(); + void rotationChanged(); +#ifndef VIDEOOUTPUT_GRAPHICS_SURFACES + void suspendDirectScreenAccess(); + void resumeDirectScreenAccess(); +#endif + +private: + void applyPendingChanges(bool force = false); +#ifndef VIDEOOUTPUT_GRAPHICS_SURFACES + void startDirectScreenAccess(); + bool stopDirectScreenAccess(); +#endif +#ifdef HAS_AUDIOROUTING_IN_VIDEOPLAYER + QString qStringFromTAudioOutputPreference(CAudioOutput::TAudioOutputPreference output) const; +#endif + + // From MVideoPlayerUtilityObserver + void MvpuoOpenComplete(TInt aError); + void MvpuoPrepareComplete(TInt aError); + void MvpuoFrameReady(CFbsBitmap &aFrame, TInt aError); + void MvpuoPlayComplete(TInt aError); + void MvpuoEvent(const TMMFEvent &aEvent); + +private: + int m_accessPointId; + S60MediaNetworkAccessControl* m_networkAccessControl; + RWsSession *const m_wsSession; + CWsScreenDevice *const m_screenDevice; + QMediaService *const m_service; +#ifdef VIDEOOUTPUT_GRAPHICS_SURFACES + CVideoPlayerUtility2 *m_player; +#else + CVideoPlayerUtility *m_player; + bool m_dsaActive; + bool m_dsaStopped; +#endif // VIDEOOUTPUT_GRAPHICS_SURFACES + QObject *m_videoOutputControl; + S60VideoDisplay *m_videoOutputDisplay; + RWindow *m_displayWindow; + QSize m_nativeSize; +#ifdef HTTP_COOKIES_ENABLED + TMMFMessageDestinationPckg m_destinationPckg; +#endif +#ifdef HAS_AUDIOROUTING_IN_VIDEOPLAYER + CAudioOutput *m_audioOutput; +#endif + QString m_audioEndpoint; + enum Parameter { + WindowHandle = 0x1, + DisplayRect = 0x2, + ScaleFactors = 0x4, + Rotation = 0x8 + }; + QFlags<Parameter> m_pendingChanges; + bool m_backendInitiatedPause; +}; + +#endif diff --git a/src/plugins/symbian/mmf/mediaplayer/s60videorenderer.cpp b/src/plugins/symbian/mmf/mediaplayer/s60videorenderer.cpp new file mode 100644 index 000000000..2de6896a0 --- /dev/null +++ b/src/plugins/symbian/mmf/mediaplayer/s60videorenderer.cpp @@ -0,0 +1,95 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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 "DebugMacros.h" + +#include "s60videorenderer.h" + +#include <QtCore/qcoreevent.h> +#include <QtGui/qapplication.h> + +/*! + Constructs a new video renderer media end point with the given \a parent. +*/ + +S60VideoRenderer::S60VideoRenderer(QObject *parent) + : QVideoRendererControl(parent) +{ + DP0("S60VideoRenderer::S60VideoRenderer +++"); + + DP0("S60VideoRenderer::S60VideoRenderer ---"); + +} + +/*! + Destroys a video renderer media end point. +*/ + +S60VideoRenderer::~S60VideoRenderer() +{ + DP0("S60VideoRenderer::~S60VideoRenderer +++"); + DP0("S60VideoRenderer::~S60VideoRenderer ---"); +} + +/*! + \return the surface a video producer renders to. +*/ + +QAbstractVideoSurface *S60VideoRenderer::surface() const +{ + DP0("S60VideoRenderer::surface"); + + return m_surface; +} + +/*! + Sets the \a surface a video producer renders to. +*/ + +void S60VideoRenderer::setSurface(QAbstractVideoSurface *surface) +{ + DP0("S60VideoRenderer::setSurface +++"); + + m_surface = surface; + + DP0("S60VideoRenderer::setSurface ---"); +} + diff --git a/src/plugins/symbian/mmf/mediaplayer/s60videorenderer.h b/src/plugins/symbian/mmf/mediaplayer/s60videorenderer.h new file mode 100644 index 000000000..6e90d42c3 --- /dev/null +++ b/src/plugins/symbian/mmf/mediaplayer/s60videorenderer.h @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** +****************************************************************************/ + +#ifndef S60VIDEORENDERER_H +#define S60VIDEORENDERER_H + +#include <QtCore/qobject.h> +#include <qvideorenderercontrol.h> + +QT_USE_NAMESPACE + +class S60VideoRenderer : public QVideoRendererControl +{ + Q_OBJECT + +public: + S60VideoRenderer(QObject *parent = 0); + virtual ~S60VideoRenderer(); + + QAbstractVideoSurface *surface() const; + void setSurface(QAbstractVideoSurface *surface); + +private: + + QAbstractVideoSurface *m_surface; +}; + +#endif // S60VIDEORENDERER_H diff --git a/src/plugins/symbian/mmf/mediaplayer/s60videosurface.cpp b/src/plugins/symbian/mmf/mediaplayer/s60videosurface.cpp new file mode 100644 index 000000000..563d33b40 --- /dev/null +++ b/src/plugins/symbian/mmf/mediaplayer/s60videosurface.cpp @@ -0,0 +1,372 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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 "DebugMacros.h" + +#include <qvideosurfaceformat.h> + +#include "s60videosurface.h" +/*! + * Constructs a video surface with the given \a parent. +*/ + +S60VideoSurface::S60VideoSurface(QObject *parent) + : QAbstractVideoSurface(parent) + , m_winId(0) +{ + DP0("S60VideoSurface::S60VideoSurface +++"); + DP0("S60VideoSurface::S60VideoSurface ---"); +} + +/*! + * Destroys video surface. +*/ + +S60VideoSurface::~S60VideoSurface() +{ + DP0("S60VideoSurface::~S60VideoSurface +++"); + DP0("S60VideoSurface::~S60VideoSurface ---"); +} + +/*! + \return the ID of the window a video surface end point renders to. +*/ + +WId S60VideoSurface::winId() const +{ + DP0("S60VideoSurface::winId"); + + return m_winId; +} + +/*! + Sets the \a id of the window a video surface end point renders to. +*/ + +void S60VideoSurface::setWinId(WId id) +{ + DP0("S60VideoSurface::setWinId +++"); + + m_winId = id; + + DP0("S60VideoSurface::setWinId ---"); +} + +/*! + \return the sub-rect of a window where video is displayed. +*/ + +QRect S60VideoSurface::displayRect() const +{ + DP0("S60VideoSurface::displayRect"); + + return m_displayRect; +} + +/*! + Sets the sub-\a rect of a window where video is displayed. +*/ + +void S60VideoSurface::setDisplayRect(const QRect &rect) +{ + DP0("S60VideoSurface::setDisplayRect +++"); + + m_displayRect = rect; + + DP0("S60VideoSurface::setDisplayRect ---"); +} + +/*! + \return the brightness adjustment applied to a video surface. + + Valid brightness values range between -100 and 100, the default is 0. +*/ + +int S60VideoSurface::brightness() const +{ + DP0("S60VideoSurface::brightness"); + + return 0; +} + +/*! + Sets a \a brightness adjustment for a video surface. + + Valid brightness values range between -100 and 100, the default is 0. +*/ + +void S60VideoSurface::setBrightness(int brightness) +{ + DP0("S60VideoSurface::setBrightness +++"); + + DP1("S60VideoSurface::setBrightness - brightness:", brightness); + + Q_UNUSED(brightness); + + DP0("S60VideoSurface::setBrightness ---"); +} + +/*! + \return the contrast adjustment applied to a video surface. + + Valid contrast values range between -100 and 100, the default is 0. +*/ + +int S60VideoSurface::contrast() const +{ + DP0("S60VideoSurface::contrast"); + + return 0; +} + +/*! + Sets the \a contrast adjustment for a video surface. + + Valid contrast values range between -100 and 100, the default is 0. +*/ + +void S60VideoSurface::setContrast(int contrast) +{ + DP0("S60VideoSurface::setContrast +++"); + + DP1("S60VideoSurface::setContrast - ", contrast); + + Q_UNUSED(contrast); + + DP0("S60VideoSurface::setContrast ---"); +} + +/*! + \return the hue adjustment applied to a video surface. + + Value hue values range between -100 and 100, the default is 0. +*/ + +int S60VideoSurface::hue() const +{ + DP0("S60VideoSurface::hue"); + + return 0; +} + +/*! + Sets a \a hue adjustment for a video surface. + + Valid hue values range between -100 and 100, the default is 0. +*/ + +void S60VideoSurface::setHue(int hue) +{ + DP0("S60VideoSurface::setHue +++"); + + DP1("S60VideoSurface::setHue - ", hue); + + Q_UNUSED(hue); + + DP0("S60VideoSurface::setHue ---"); +} + +/*! + \return the saturation adjustment applied to a video surface. + + Value saturation values range between -100 and 100, the default is 0. +*/ + +int S60VideoSurface::saturation() const +{ + DP0("S60VideoSurface::saturation"); + + return 0; +} + +/*! + Sets a \a saturation adjustment for a video surface. + + Valid saturation values range between -100 and 100, the default is 0. +*/ + +void S60VideoSurface::setSaturation(int saturation) +{ + DP0("S60VideoSurface::setSaturation +++"); + + DP1("S60VideoSurface::setSaturation - ", saturation); + + Q_UNUSED(saturation); + + DP0("S60VideoSurface::setSaturation ---"); +} + +/*! + * \return ZERO. \a attribute, \a minimum, \a maximum are not used. +*/ +int S60VideoSurface::getAttribute(const char *attribute, int minimum, int maximum) const +{ + DP0("S60VideoSurface::getAttribute +++"); + + Q_UNUSED(attribute); + Q_UNUSED(minimum); + Q_UNUSED(maximum); + + DP0("S60VideoSurface::getAttribute ---"); + + return 0; +} + +/*! + * Sets the \a attribute, \a minimum, \a maximum. + * But never used. +*/ + +void S60VideoSurface::setAttribute(const char *attribute, int value, int minimum, int maximum) +{ + DP0("S60VideoSurface::setAttribute +++"); + + Q_UNUSED(attribute); + Q_UNUSED(value); + Q_UNUSED(minimum); + Q_UNUSED(maximum); + + DP0("S60VideoSurface::setAttribute ---"); + +} + +/*! + * \return ZERO. + * \a value, \a fromLower, \a fromUpper, \a toLower, \a toUpper are never used. +*/ + +int S60VideoSurface::redistribute( + int value, int fromLower, int fromUpper, int toLower, int toUpper) +{ + DP0("S60VideoSurface::redistribute +++"); + + Q_UNUSED(value); + Q_UNUSED(fromLower); + Q_UNUSED(fromUpper); + Q_UNUSED(toLower); + Q_UNUSED(toUpper); + + DP0("S60VideoSurface::redistribute ---"); + + return 0; +} + +/*! + * \return List of video surface supported Pixel Formats. +*/ + +QList<QVideoFrame::PixelFormat> S60VideoSurface::supportedPixelFormats( + QAbstractVideoBuffer::HandleType handleType) const +{ + DP0("S60VideoSurface::supportedPixelFormats +++"); + + Q_UNUSED(handleType); + QList<QVideoFrame::PixelFormat> list; + + DP0("S60VideoSurface::supportedPixelFormats ---"); + + return list; +} + +/*! + * \return always FALSE, as \a format never used. +*/ + +bool S60VideoSurface::start(const QVideoSurfaceFormat &format) +{ + DP0("S60VideoSurface::start"); + + Q_UNUSED(format); + return false; +} + +/*! + * Stops video surface. +*/ +void S60VideoSurface::stop() +{ + DP0("S60VideoSurface::stop +++"); + + DP0("S60VideoSurface::stop ---"); + +} + +/*! + * \return always FALS, as \a format is never used. +*/ +bool S60VideoSurface::present(const QVideoFrame &frame) +{ + DP0("S60VideoSurface::present"); + + Q_UNUSED(frame); + return false; +} + +/*! + * \return always FALSE. +*/ + +bool S60VideoSurface::findPort() +{ + DP0("S60VideoSurface::findPort"); + + return false; +} + +void S60VideoSurface::querySupportedFormats() +{ + DP0("S60VideoSurface::querySupportedFormats +++"); + + DP0("S60VideoSurface::querySupportedFormats ---"); + +} + +/*! + * \return always FLASE, as \a format never used. +*/ + +bool S60VideoSurface::isFormatSupported(const QVideoSurfaceFormat &format) const +{ + DP0("S60VideoSurface::isFormatSupported"); + + Q_UNUSED(format); + return false; +} diff --git a/src/plugins/symbian/mmf/mediaplayer/s60videosurface.h b/src/plugins/symbian/mmf/mediaplayer/s60videosurface.h new file mode 100644 index 000000000..9f13755b7 --- /dev/null +++ b/src/plugins/symbian/mmf/mediaplayer/s60videosurface.h @@ -0,0 +1,106 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** +****************************************************************************/ + +#ifndef S60VIDEOSURFACE_H +#define S60VIDEOSURFACE_H + +#include <QtGui/qwidget.h> +#include <qabstractvideosurface.h> + +class S60VideoSurface : public QAbstractVideoSurface +{ + Q_OBJECT +public: + S60VideoSurface(QObject *parent = 0); + ~S60VideoSurface(); + + WId winId() const; + void setWinId(WId id); + + QRect displayRect() const; + void setDisplayRect(const QRect &rect); + + int brightness() const; + void setBrightness(int brightness); + + int contrast() const; + void setContrast(int contrast); + + int hue() const; + void setHue(int hue); + + int saturation() const; + void setSaturation(int saturation); + + QList<QVideoFrame::PixelFormat> supportedPixelFormats( + QAbstractVideoBuffer::HandleType handleType = QAbstractVideoBuffer::NoHandle) const; + + bool isFormatSupported(const QVideoSurfaceFormat &format) const; + + bool start(const QVideoSurfaceFormat &format); + void stop(); + + bool present(const QVideoFrame &frame); + +private: + WId m_winId; + //XvPortID m_portId; + //GC m_gc; + //XvImage *m_image; + QList<QVideoFrame::PixelFormat> m_supportedPixelFormats; + QVector<int> m_formatIds; + QRect m_viewport; + QRect m_displayRect; + QPair<int, int> m_brightnessRange; + QPair<int, int> m_contrastRange; + QPair<int, int> m_hueRange; + QPair<int, int> m_saturationRange; + + bool findPort(); + void querySupportedFormats(); + + int getAttribute(const char *attribute, int minimum, int maximum) const; + void setAttribute(const char *attribute, int value, int minimum, int maximum); + + static int redistribute(int value, int fromLower, int fromUpper, int toLower, int toUpper); +}; + +#endif diff --git a/src/plugins/symbian/mmf/mmf.pro b/src/plugins/symbian/mmf/mmf.pro new file mode 100644 index 000000000..2bae03e59 --- /dev/null +++ b/src/plugins/symbian/mmf/mmf.pro @@ -0,0 +1,58 @@ +TEMPLATE = lib + +CONFIG += plugin +TARGET = $$qtLibraryTarget(qtmultimediakit_mmfengine) +PLUGIN_TYPE = mediaservice +include (../../../../common.pri) +qtAddLibrary(QtMultimediaKit) + +#includes here so that all defines are added here also +include(mediaplayer/mediaplayer_s60.pri) +include(radio/radio.pri) + +QT += network + +# we include mmf audiorecording only if we are not building openmaxal based backend +!contains(openmaxal_symbian_enabled, yes) { + message("Enabling mmf mediarecording backend") + include(audiosource/audiosource_s60.pri) +} + +DEPENDPATH += . +INCLUDEPATH += . \ + $${SOURCE_DIR}/include \ + $${SOURCE_DIR}/src/multimedia \ + $${SOURCE_DIR}/src/multimedia/audio \ + $${SOURCE_DIR}/src/multimedia/video \ + $${SOURCE_DIR}/plugins/multimedia/symbian/mmf/inc \ + $${SOURCE_DIR} + + +HEADERS += s60mediaserviceplugin.h \ + s60formatsupported.h + +SOURCES += s60mediaserviceplugin.cpp \ + s60formatsupported.cpp + +contains(S60_VERSION, 3.2)|contains(S60_VERSION, 3.1) { + DEFINES += PRE_S60_50_PLATFORM +} +contains(mmf_http_cookies_enabled, yes) { + DEFINES += HTTP_COOKIES_ENABLED +} +load(data_caging_paths) +TARGET.EPOCALLOWDLLDATA = 1 +TARGET.UID3=0x2002AC76 +TARGET.CAPABILITY = ALL -TCB +MMP_RULES += EXPORTUNFROZEN + +#make a sis package from plugin + api + stub (plugin) +pluginDep.sources = $${TARGET}.dll +pluginDep.path = $${QT_PLUGINS_BASE_DIR}/$${PLUGIN_TYPE} +DEPLOYMENT += pluginDep + +#Media API spesific deployment +QtMediaDeployment.sources = QtMultimediaKit.dll +QtMediaDeployment.path = /sys/bin + +DEPLOYMENT += QtMediaDeployment diff --git a/src/plugins/symbian/mmf/radio/radio.pri b/src/plugins/symbian/mmf/radio/radio.pri new file mode 100644 index 000000000..a4703d126 --- /dev/null +++ b/src/plugins/symbian/mmf/radio/radio.pri @@ -0,0 +1,24 @@ +INCLUDEPATH += $$PWD + +contains(tunerlib_s60_enabled, yes) { + + LIBS += -ltunerutility + DEFINES += TUNERLIBUSED + INCLUDEPATH += $${EPOCROOT}epoc32/include/mmf/common + + HEADERS += $$PWD/s60radiotunercontrol_31.h + SOURCES += $$PWD/s60radiotunercontrol_31.cpp +} + +contains(radioutility_s60_enabled, yes) { + LIBS += -lradio_utility + DEFINES += RADIOUTILITYLIBUSED + + HEADERS += $$PWD/s60radiotunercontrol_since32.h + SOURCES += $$PWD/s60radiotunercontrol_since32.cpp +} + +contains(tunerlib_s60_enabled, yes)|contains(radioutility_s60_enabled, yes) { + HEADERS += $$PWD/s60radiotunerservice.h + SOURCES += $$PWD/s60radiotunerservice.cpp +} diff --git a/src/plugins/symbian/mmf/radio/s60radiotunercontrol_31.cpp b/src/plugins/symbian/mmf/radio/s60radiotunercontrol_31.cpp new file mode 100644 index 000000000..b7627e312 --- /dev/null +++ b/src/plugins/symbian/mmf/radio/s60radiotunercontrol_31.cpp @@ -0,0 +1,603 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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 "DebugMacros.h" + +#include "s60radiotunercontrol_31.h" +#include "s60radiotunerservice.h" + +#include <QtCore/qdebug.h> +#include <QFile> + +// from AudioPreference.h +const TInt KAudioPriorityFMRadio = 79; +const TUint KAudioPrefRadioAudioEvent = 0x03000001; + +S60RadioTunerControl::S60RadioTunerControl(QObject *parent) + : QRadioTunerControl(parent) + , m_error(0) + , m_tunerState(0) + , m_apiTunerState(QRadioTuner::StoppedState) + , m_audioInitializationComplete(false) + , m_radioError(QRadioTuner::NoError) + , m_muted(false) + , m_isStereo(true) + , m_stereoMode(QRadioTuner::Auto) + , m_signal(0) + , m_currentBand(QRadioTuner::FM) + , m_currentFreq(87500000) + , m_scanning(false) + , m_vol(50) +{ + DP0("S60RadioTunerControl::S60RadioTunerControl +++"); + + initRadio(); + + DP0("S60RadioTunerControl::S60RadioTunerControl ---"); +} + +S60RadioTunerControl::~S60RadioTunerControl() +{ + DP0("S60RadioTunerControl::~S60RadioTunerControl +++"); + + if (m_tunerUtility) { + m_tunerUtility->Close(); + m_tunerUtility->CancelNotifyChange(); + m_tunerUtility->CancelNotifySignalStrength(); + m_tunerUtility->CancelNotifyStereoChange(); + delete m_tunerUtility; + } + if (m_audioPlayerUtility) { + m_audioPlayerUtility = NULL; + } + + DP0("S60RadioTunerControl::~S60RadioTunerControl ---"); +} + +bool S60RadioTunerControl::initRadio() +{ + DP0("S60RadioTunerControl::initRadio +++"); + + m_available = false; + + TRAPD(tunerError, m_tunerUtility = CMMTunerUtility::NewL(*this, CMMTunerUtility::ETunerBandFm, 1, + CMMTunerUtility::ETunerAccessPriorityNormal)); + if (tunerError != KErrNone) { + m_radioError = QRadioTuner::OpenError; + return m_available; + } + + TRAPD(playerError, m_audioPlayerUtility = m_tunerUtility->TunerPlayerUtilityL(*this)); + if (playerError != KErrNone) { + m_radioError = QRadioTuner::OpenError; + return m_available; + } + + TRAPD(initializeError, m_audioPlayerUtility->InitializeL(KAudioPriorityFMRadio, + TMdaPriorityPreference(KAudioPrefRadioAudioEvent))); + if (initializeError != KErrNone) { + m_radioError = QRadioTuner::OpenError; + return m_available; + } + + m_tunerUtility->NotifyChange(*this); + m_tunerUtility->NotifyStereoChange(*this); + m_tunerUtility->NotifySignalStrength(*this); + + TFrequency freq(m_currentFreq); + m_tunerUtility->Tune(freq); + + m_available = true; + + DP0("S60RadioTunerControl::initRadio ---"); + + return m_available; +} + +void S60RadioTunerControl::start() +{ + DP0("S60RadioTunerControl::start +++"); + + if (!m_audioInitializationComplete) { + TFrequency freq(m_currentFreq); + m_tunerUtility->Tune(freq); + } else { + m_audioPlayerUtility->Play(); + } + + m_apiTunerState = QRadioTuner::ActiveState; + emit stateChanged(m_apiTunerState); + + DP0("S60RadioTunerControl::start ---"); +} + +void S60RadioTunerControl::stop() +{ + DP0("S60RadioTunerControl::stop +++"); + + if (m_audioPlayerUtility) { + m_audioPlayerUtility->Stop(); + m_apiTunerState = QRadioTuner::StoppedState; + emit stateChanged(m_apiTunerState); + } + + DP0("S60RadioTunerControl::stop ---"); +} + +QRadioTuner::State S60RadioTunerControl::state() const +{ + DP0("S60RadioTunerControl::state"); + + return m_apiTunerState; +} + +QRadioTuner::Band S60RadioTunerControl::band() const +{ + DP0("S60RadioTunerControl::band"); + + return m_currentBand; +} + +bool S60RadioTunerControl::isBandSupported(QRadioTuner::Band b) const +{ + DP0("S60RadioTunerControl::isBandSupported"); + + if(b == QRadioTuner::FM) + return true; + else if(b == QRadioTuner::LW) + return false; + else if(b == QRadioTuner::AM) + return true; + else if(b == QRadioTuner::SW) + return false; + else + return false; +} + +void S60RadioTunerControl::setBand(QRadioTuner::Band b) +{ + DP0("S60RadioTunerControl::setBand +++"); + + QRadioTuner::Band tempBand = b; + if (tempBand != m_currentBand) { + m_currentBand = b; + emit bandChanged(m_currentBand); + } + + DP0("S60RadioTunerControl::setBand ---"); +} + +int S60RadioTunerControl::frequency() const +{ + DP0("S60RadioTunerControl::frequency"); + + return m_currentFreq; +} + +void S60RadioTunerControl::setFrequency(int frequency) +{ + DP0("S60RadioTunerControl::setFrequency +++"); + + m_currentFreq = frequency; + TFrequency freq(m_currentFreq); + m_tunerUtility->Tune(freq); + + DP0("S60RadioTunerControl::setFrequency ---"); +} + +int S60RadioTunerControl::frequencyStep(QRadioTuner::Band b) const +{ + DP0("S60RadioTunerControl::frequencyStep +++"); + + int step = 0; + + if(b == QRadioTuner::FM) + step = 100000; // 100kHz steps + else if(b == QRadioTuner::LW) + step = 1000; // 1kHz steps + else if(b == QRadioTuner::AM) + step = 1000; // 1kHz steps + else if(b == QRadioTuner::SW) + step = 500; // 500Hz steps + + DP1("S60RadioTunerControl::frequencyStep, Step:", step); + DP0("S60RadioTunerControl::frequencyStep ---"); + + return step; +} + +QPair<int,int> S60RadioTunerControl::frequencyRange(QRadioTuner::Band band) const +{ + DP0("S60RadioTunerControl::frequencyRange +++"); + + TFrequency bottomFreq; + TFrequency topFreq; + int bandError = KErrNone; + + if (m_tunerUtility){ + bandError = m_tunerUtility->GetFrequencyBandRange(bottomFreq, topFreq); + if (!bandError) { + return qMakePair<int,int>(bottomFreq.iFrequency, topFreq.iFrequency); + } + } + + DP0("S60RadioTunerControl::frequencyRange ---"); + + return qMakePair<int,int>(0,0); +} + +CMMTunerUtility::TTunerBand S60RadioTunerControl::getNativeBand(QRadioTuner::Band b) const +{ + DP0("S60RadioTunerControl::getNativeBand"); + + // api match to native s60 bands + if (b == QRadioTuner::AM) + return CMMTunerUtility::ETunerBandAm; + else if (b == QRadioTuner::FM) + return CMMTunerUtility::ETunerBandFm; + else if (b == QRadioTuner::LW) + return CMMTunerUtility::ETunerBandLw; + else + return CMMTunerUtility::ETunerNoBand; +} + +bool S60RadioTunerControl::isStereo() const +{ + DP0("S60RadioTunerControl::isStereo"); + + return m_isStereo; +} + +QRadioTuner::StereoMode S60RadioTunerControl::stereoMode() const +{ + DP0("S60RadioTunerControl::stereoMode"); + + return m_stereoMode; +} + +void S60RadioTunerControl::setStereoMode(QRadioTuner::StereoMode mode) +{ + DP0("S60RadioTunerControl::setStereoMode +++"); + + m_stereoMode = mode; + if (m_tunerUtility) { + if (QRadioTuner::ForceMono == mode) + m_tunerUtility->ForceMonoReception(true); + else + m_tunerUtility->ForceMonoReception(false); + } + + DP0("S60RadioTunerControl::setStereoMode ---"); +} + +int S60RadioTunerControl::signalStrength() const +{ + DP0("S60RadioTunerControl::signalStrength +++"); + + // return value is a percentage value + if (m_tunerUtility) { + TInt maxSignalStrength; + TInt currentSignalStrength; + m_error = m_tunerUtility->GetMaxSignalStrength(maxSignalStrength); + if (m_error == KErrNone) { + m_error = m_tunerUtility->GetSignalStrength(currentSignalStrength); + if (m_error == KErrNone) { + if (maxSignalStrength == 0 || currentSignalStrength == 0) { + return 0; + } + m_signal = ((TInt64)currentSignalStrength) * 100 / maxSignalStrength; + } + } + } + + DP1("S60RadioTunerControl::signalStrength, m_signal:", m_signal); + DP0("S60RadioTunerControl::signalStrength ---"); + + return m_signal; +} + +int S60RadioTunerControl::volume() const +{ + DP0("S60RadioTunerControl::volume"); + + return m_vol; +} + +void S60RadioTunerControl::setVolume(int volume) +{ + DP0("S60RadioTunerControl::setVolume +++"); + DP1("S60RadioTunerControl::setVolume: ", volume); + + if (m_audioPlayerUtility) { + m_vol = volume; + TInt error = m_audioPlayerUtility->SetVolume(volume/10); + emit volumeChanged(m_vol); + } + + DP0("S60RadioTunerControl::setVolume ---"); +} + +bool S60RadioTunerControl::isMuted() const +{ + DP0("S60RadioTunerControl::isMuted"); + + return m_muted; +} + +void S60RadioTunerControl::setMuted(bool muted) +{ + DP0("S60RadioTunerControl::setMuted +++"); + + DP1("S60RadioTunerControl::setMuted:", muted); + + if (m_audioPlayerUtility && m_audioInitializationComplete) { + m_muted = muted; + m_audioPlayerUtility->Mute(m_muted); + emit mutedChanged(m_muted); + } + + DP0("S60RadioTunerControl::setMuted ---"); +} + +bool S60RadioTunerControl::isSearching() const +{ + DP0("S60RadioTunerControl::isSearching"); + + if (m_tunerUtility) { + TUint32 tempState; + m_tunerUtility->GetState(tempState); + if (tempState == CMMTunerUtility::ETunerStateRetuning || m_scanning) { + return true; + } else + return false; + } + return true; +} + +void S60RadioTunerControl::cancelSearch() +{ + DP0("S60RadioTunerControl::cancelSearch +++"); + + m_tunerUtility->CancelRetune(); + m_scanning = false; + emit searchingChanged(false); + + DP0("S60RadioTunerControl::cancelSearch ---"); +} + +void S60RadioTunerControl::searchForward() +{ + DP0("S60RadioTunerControl::searchForward +++"); + + m_scanning = true; + setVolume(m_vol); + m_tunerUtility->StationSeek(CMMTunerUtility::ESearchDirectionUp); + emit searchingChanged(true); + + DP0("S60RadioTunerControl::searchForward ---"); +} + +void S60RadioTunerControl::searchBackward() +{ + DP0("S60RadioTunerControl::searchBackward +++"); + + m_scanning = true; + setVolume(m_vol); + m_tunerUtility->StationSeek(CMMTunerUtility::ESearchDirectionDown); + emit searchingChanged(true); + + DP0("S60RadioTunerControl::searchBackward ---"); +} + +bool S60RadioTunerControl::isValid() const +{ + DP0("S60RadioTunerControl::isValid"); + + return m_available; +} + +bool S60RadioTunerControl::isAvailable() const +{ + DP0("S60RadioTunerControl::isAvailable"); + + return m_available; +} + +QtMultimediaKit::AvailabilityError S60RadioTunerControl::availabilityError() const +{ + DP0("S60RadioTunerControl::availabilityError"); + + if (m_available) + return QtMultimediaKit::NoError; + else + return QtMultimediaKit::ResourceError; +} + +QRadioTuner::Error S60RadioTunerControl::error() const +{ + DP1("QtMultimediaKit::NoError", m_radioError); + + return m_radioError; +} + +QString S60RadioTunerControl::errorString() const +{ + DP1("S60RadioTunerControl::errorString", m_errorString); + + return m_errorString; +} + +void S60RadioTunerControl::MToTuneComplete(TInt aError) +{ + DP0("S60RadioTunerControl::MToTuneComplete +++"); + DP1("S60RadioTunerControl::MToTuneComplete, aError:",aError); + + if (aError == KErrNone) { + m_scanning = false; + m_audioPlayerUtility->Play(); + if (!m_audioInitializationComplete) { + TRAPD(initializeError, m_audioPlayerUtility->InitializeL(KAudioPriorityFMRadio, + TMdaPriorityPreference(KAudioPrefRadioAudioEvent))); + if (initializeError != KErrNone) { + m_radioError = QRadioTuner::OpenError; + } + } + } + + DP0("S60RadioTunerControl::MToTuneComplete ---"); +} + +void S60RadioTunerControl::MTcoFrequencyChanged(const TFrequency& aOldFrequency, const TFrequency& aNewFrequency) +{ + DP0("S60RadioTunerControl::MTcoFrequencyChanged +++"); + + m_currentFreq = aNewFrequency.iFrequency; + m_scanning = false; + emit frequencyChanged(m_currentFreq); + + DP0("S60RadioTunerControl::MTcoFrequencyChanged ---"); +} + +void S60RadioTunerControl::MTcoStateChanged(const TUint32& aOldState, const TUint32& aNewState) +{ + DP0("S60RadioTunerControl::MTcoStateChanged +++"); + + if (aNewState == CMMTunerUtility::ETunerStateActive) { + m_apiTunerState = QRadioTuner::ActiveState; + } + if (aNewState == CMMTunerUtility::ETunerStatePlaying) { + m_apiTunerState = QRadioTuner::ActiveState; + } + if (aOldState != aNewState){ + emit stateChanged(m_apiTunerState); + } + + DP0("S60RadioTunerControl::MTcoStateChanged ---"); +} + +void S60RadioTunerControl::MTcoAntennaDetached() +{ + DP0("S60RadioTunerControl::MTcoAntennaDetached +++"); + + DP0("S60RadioTunerControl::MTcoAntennaDetached ---"); + + // no actions +} + +void S60RadioTunerControl::MTcoAntennaAttached() +{ + DP0("S60RadioTunerControl::MTcoAntennaAttached +++"); + + DP0("S60RadioTunerControl::MTcoAntennaAttached ---"); + + // no actions +} + +void S60RadioTunerControl::FlightModeChanged(TBool aFlightMode) +{ + DP0("S60RadioTunerControl::FlightModeChanged +++"); + + DP0("S60RadioTunerControl::FlightModeChanged ---"); + + // no actions +} + +void S60RadioTunerControl::MTsoStereoReceptionChanged(TBool aStereo) +{ + DP0("S60RadioTunerControl::MTsoStereoReceptionChanged +++"); + DP1("S60RadioTunerControl::MTsoStereoReceptionChanged, aStereo:", aStereo); + m_isStereo = aStereo; + emit stereoStatusChanged(aStereo); + + DP0("S60RadioTunerControl::MTsoStereoReceptionChanged ---"); +} + +void S60RadioTunerControl::MTsoForcedMonoChanged(TBool aForcedMono) +{ + DP0("S60RadioTunerControl::MTsoForcedMonoChanged +++"); + DP1("S60RadioTunerControl::MTsoForcedMonoChanged, aForcedMono:", aForcedMono); + + if (aForcedMono) { + m_stereoMode = QRadioTuner::ForceMono; + } + + DP0("S60RadioTunerControl::MTsoForcedMonoChanged ---"); +} + +void S60RadioTunerControl::MssoSignalStrengthChanged(TInt aNewSignalStrength) +{ + DP0("S60RadioTunerControl::MssoSignalStrengthChanged +++"); + DP1("S60RadioTunerControl::MssoSignalStrengthChanged, aNewSignalStrength:", aNewSignalStrength); + + m_signal = aNewSignalStrength; + emit signalStrengthChanged(m_signal); + + DP0("S60RadioTunerControl::MssoSignalStrengthChanged ---"); +} + +void S60RadioTunerControl::MTapoInitializeComplete(TInt aError) +{ + DP0("S60RadioTunerControl::MTapoInitializeComplete +++"); + DP1("S60RadioTunerControl::MTapoInitializeComplete, aError:", aError); + if (aError == KErrNone) { + m_audioInitializationComplete = true; + m_available = true; + m_audioPlayerUtility->Play(); + m_apiTunerState = QRadioTuner::ActiveState; + emit stateChanged(m_apiTunerState); + } else if (aError != KErrNone) { + m_radioError = QRadioTuner::OpenError; + } + + DP0("S60RadioTunerControl::MTapoInitializeComplete ---"); +} + +void S60RadioTunerControl::MTapoPlayEvent(TEventType aEvent, TInt aError, TAny* aAdditionalInfo) +{ + DP0("S60RadioTunerControl::MTapoPlayEvent +++"); + + DP0("S60RadioTunerControl::MTapoPlayEvent ---"); + + // no actions +} + + + diff --git a/src/plugins/symbian/mmf/radio/s60radiotunercontrol_31.h b/src/plugins/symbian/mmf/radio/s60radiotunercontrol_31.h new file mode 100644 index 000000000..c8bb8d362 --- /dev/null +++ b/src/plugins/symbian/mmf/radio/s60radiotunercontrol_31.h @@ -0,0 +1,161 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** +****************************************************************************/ + +#ifndef S60RADIOTUNERCONTROL_H +#define S60RADIOTUNERCONTROL_H + +#include <QtCore/qobject.h> +#include <qradiotunercontrol.h> +#include <qradiotuner.h> +#include <tuner.h> + +class S60RadioTunerService; + +QT_USE_NAMESPACE + +class S60RadioTunerControl + : public QRadioTunerControl + , public MMMTunerObserver + , public MMMTunerStereoObserver + , public MMMSignalStrengthObserver + , public MMMTunerChangeObserver + , public MMMTunerAudioPlayerObserver +{ + Q_OBJECT +public: + S60RadioTunerControl(QObject *parent = 0); + ~S60RadioTunerControl(); + + QRadioTuner::State state() const; + + QRadioTuner::Band band() const; + void setBand(QRadioTuner::Band b); + bool isBandSupported(QRadioTuner::Band b) const; + + int frequency() const; + int frequencyStep(QRadioTuner::Band b) const; + QPair<int,int> frequencyRange(QRadioTuner::Band b) const; + void setFrequency(int frequency); + + bool isStereo() const; + QRadioTuner::StereoMode stereoMode() const; + void setStereoMode(QRadioTuner::StereoMode mode); + + int signalStrength() const; + + int volume() const; + void setVolume(int volume); + + bool isMuted() const; + void setMuted(bool muted); + + bool isSearching() const; + void searchForward(); + void searchBackward(); + void cancelSearch(); + + bool isValid() const; + + bool isAvailable() const; + QtMultimediaKit::AvailabilityError availabilityError() const; + + void start(); + void stop(); + + QRadioTuner::Error error() const; + QString errorString() const; + + //MMMTunerObserver + void MToTuneComplete(TInt aError); + + //MMMTunerChangeObserver + void MTcoFrequencyChanged(const TFrequency& aOldFrequency, const TFrequency& aNewFrequency); + void MTcoStateChanged(const TUint32& aOldState, const TUint32& aNewState); + void MTcoAntennaDetached(); + void MTcoAntennaAttached(); + void FlightModeChanged(TBool aFlightMode); + + //MMMTunerStereoObserver + void MTsoStereoReceptionChanged(TBool aStereo); + void MTsoForcedMonoChanged(TBool aForcedMono); + + //MMMSignalStrengthObserver + void MssoSignalStrengthChanged(TInt aNewSignalStrength); + + //MMMTunerAudioPlayerObserver + void MTapoInitializeComplete(TInt aError); + void MTapoPlayEvent(TEventType aEvent, TInt aError, TAny* aAdditionalInfo); + +private slots: + + +private: + bool initRadio(); + CMMTunerUtility::TTunerBand getNativeBand(QRadioTuner::Band b) const; + + mutable int m_error; + CMMTunerUtility *m_tunerUtility; + CMMTunerAudioPlayerUtility *m_audioPlayerUtility; + + bool m_audioInitializationComplete; + bool m_muted; + bool m_isStereo; + bool m_available; + int m_step; + int m_vol; + mutable int m_signal; + bool m_scanning; + bool forward; + QRadioTuner::Band m_currentBand; + qint64 m_currentFreq; + + QRadioTuner::Error m_radioError; + QRadioTuner::StereoMode m_stereoMode; + QString m_errorString; + //caps meaning what the tuner can do. + TTunerCapabilities m_currentTunerCapabilities; + long m_tunerState; + QRadioTuner::State m_apiTunerState; + +}; + +#endif + diff --git a/src/plugins/symbian/mmf/radio/s60radiotunercontrol_since32.cpp b/src/plugins/symbian/mmf/radio/s60radiotunercontrol_since32.cpp new file mode 100644 index 000000000..991c6b8e4 --- /dev/null +++ b/src/plugins/symbian/mmf/radio/s60radiotunercontrol_since32.cpp @@ -0,0 +1,685 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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 "DebugMacros.h" + +#include "s60radiotunercontrol_since32.h" +#include "s60radiotunerservice.h" + +#include <QtCore/qdebug.h> +#include <RadioFmTunerUtility.h> + +S60RadioTunerControl::S60RadioTunerControl(QObject *parent) + : QRadioTunerControl(parent) + , m_error(0) + , m_radioUtility(NULL) + , m_fmTunerUtility(NULL) + , m_playerUtility(NULL) + , m_maxVolume(100) + , m_audioInitializationComplete(false) + , m_muted(false) + , m_isStereo(true) + , m_vol(50) + , m_signal(0) + , m_scanning(false) + , m_currentBand(QRadioTuner::FM) + , m_currentFreq(87500000) + , m_radioError(QRadioTuner::NoError) + , m_stereoMode(QRadioTuner::Auto) + , m_apiTunerState(QRadioTuner::StoppedState) + , m_previousSignal(0) + , m_volChangeRequired(false) + , m_signalStrengthTimer(new QTimer(this)) +{ + DP0("S60RadioTunerControl::S60RadioTunerControl +++"); + bool retValue = initRadio(); + if (!retValue) { + m_errorString = QString(tr("Initialize Error.")); + emit error(QRadioTuner::ResourceError); + } else { + connect(m_signalStrengthTimer, SIGNAL(timeout()), this, SLOT(changeSignalStrength())); + } + DP0("S60RadioTunerControl::S60RadioTunerControl ---"); +} + +S60RadioTunerControl::~S60RadioTunerControl() +{ + DP0("S60RadioTunerControl::~S60RadioTunerControl +++"); + + if (m_fmTunerUtility) { + m_fmTunerUtility->Close(); + } + + if (m_playerUtility) { + m_playerUtility->Close(); + } + + delete m_radioUtility; + + DP0("S60RadioTunerControl::~S60RadioTunerControl ---"); +} + +QRadioTuner::State S60RadioTunerControl::state() const +{ + DP0("S60RadioTunerControl::state"); + + return m_apiTunerState; +} + +QRadioTuner::Band S60RadioTunerControl::band() const +{ + DP0("S60RadioTunerControl::band"); + + return m_currentBand; +} + +bool S60RadioTunerControl::isBandSupported(QRadioTuner::Band b) const +{ + DP0("S60RadioTunerControl::isBandSupported"); + if (b == QRadioTuner::FM) + return true; + else if (b == QRadioTuner::LW) + return false; + else if (b == QRadioTuner::AM) + return false; + else if (b == QRadioTuner::SW) + return false; + else if (b == QRadioTuner::FM2) + return false; + else + return false; +} + +void S60RadioTunerControl::changeSignalStrength() + { + + int currentSignal = signalStrength(); + if (currentSignal != m_previousSignal) + { + m_previousSignal = currentSignal; + emit signalStrengthChanged(currentSignal); + } + } +void S60RadioTunerControl::setBand(QRadioTuner::Band b) +{ + DP0("S60RadioTunerControl::setBand +++"); + QRadioTuner::Band tempBand = b; + if (tempBand != m_currentBand ) { + if (isBandSupported(tempBand)){ + m_currentBand = b; + emit bandChanged(m_currentBand); + } + else { + switch(tempBand) + { + case QRadioTuner::FM : + m_errorString = QString(tr("Band FM not Supported")); + break; + case QRadioTuner::AM : + m_errorString = QString(tr("Band AM not Supported")); + break; + case QRadioTuner::SW : + m_errorString = QString(tr("Band SW not Supported")); + break; + case QRadioTuner::LW : + m_errorString = QString(tr("Band LW not Supported")); + break; + case QRadioTuner::FM2 : + m_errorString = QString(tr("Band FM2 not Supported")); + break; + default : + m_errorString = QString("Band %1 not Supported").arg(tempBand); + break; + } + emit error(QRadioTuner::OutOfRangeError); + } + } + + DP0("S60RadioTunerControl::setBand ---"); +} + +int S60RadioTunerControl::frequency() const +{ + DP0("S60RadioTunerControl::frequency"); + + return m_currentFreq; +} + +void S60RadioTunerControl::setFrequency(int frequency) +{ + DP0("S60RadioTunerControl::setFrequency +++"); + DP1("S60RadioTunerControl::setFrequency, frequency:", frequency); + + m_currentFreq = frequency; + m_fmTunerUtility->SetFrequency(m_currentFreq); + + DP0("S60RadioTunerControl::setFrequency ---"); +} +int S60RadioTunerControl::frequencyStep(QRadioTuner::Band b) const +{ + DP0("S60RadioTunerControl::frequencyStep +++"); + + int step = 0; + if (b == QRadioTuner::FM) + step = 100000; // 100kHz steps + else if(b == QRadioTuner::LW) + step = 1000; // 1kHz steps + else if (b == QRadioTuner::AM) + step = 1000; // 1kHz steps + else if(b == QRadioTuner::SW) + step = 500; // 500Hz steps + DP1("S60RadioTunerControl::frequencyStep, Step:", step); + DP0("S60RadioTunerControl::frequencyStep ---"); + + return step; +} + +QPair<int,int> S60RadioTunerControl::frequencyRange(QRadioTuner::Band band) const +{ + DP0("S60RadioTunerControl::frequencyRange +++"); + + int bottomFreq; + int topFreq; + + int bandError = KErrNone; + TFmRadioFrequencyRange range; + + if (m_fmTunerUtility) { + bandError = m_fmTunerUtility->GetFrequencyRange(range, bottomFreq, topFreq); + } + if (!bandError) { + return qMakePair<int,int>(bottomFreq, topFreq); + } + + DP0("S60RadioTunerControl::frequencyRange ---"); + + return qMakePair<int,int>(0,0); +} + +bool S60RadioTunerControl::isStereo() const +{ + DP0("S60RadioTunerControl::isStereo"); + + return m_isStereo; +} + +QRadioTuner::StereoMode S60RadioTunerControl::stereoMode() const +{ + DP0("S60RadioTunerControl::stereoMode"); + + return m_stereoMode; +} + +void S60RadioTunerControl::setStereoMode(QRadioTuner::StereoMode mode) +{ + DP0("S60RadioTunerControl::setStereoMode +++"); + + if (m_fmTunerUtility) { + if (QRadioTuner::ForceMono == mode) { + m_fmTunerUtility->ForceMonoReception(true); + m_stereoMode = QRadioTuner::ForceMono; + m_isStereo = false; + } else { + m_fmTunerUtility->ForceMonoReception(false); + m_isStereo = true; + m_stereoMode = QRadioTuner::ForceStereo; + } + } + + DP0("S60RadioTunerControl::setStereoMode ---"); +} + +int S60RadioTunerControl::signalStrength() const +{ + DP0("S60RadioTunerControl::signalStrength +++"); + + // return value is a percentage value + if (m_fmTunerUtility) { + TInt maxSignalStrength; + TInt currentSignalStrength; + m_error = m_fmTunerUtility->GetMaxSignalStrength(maxSignalStrength); + + if (m_error == KErrNone) { + m_error = m_fmTunerUtility->GetSignalStrength(currentSignalStrength); + if (m_error == KErrNone) { + if (currentSignalStrength == 0 || maxSignalStrength == 0) { + return currentSignalStrength; + } + m_signal = ((TInt64)currentSignalStrength) * 100 / maxSignalStrength; + } + } + } + + DP1("S60RadioTunerControl::signalStrength, m_signal:", m_signal); + DP0("S60RadioTunerControl::signalStrength ---"); + + return m_signal; +} + +int S60RadioTunerControl::volume() const +{ + DP0("S60RadioTunerControl::volume"); + + return m_vol; +} + +void S60RadioTunerControl::setVolume(int volume) +{ + DP0("S60RadioTunerControl::setVolume +++"); + DP1("S60RadioTunerControl::setVolume, Volume:", volume); + + int boundVolume = qBound(0, volume, 100); + + if (m_vol == boundVolume ) + return; + + if (!m_muted && m_playerUtility) { + m_vol = boundVolume; + // Don't set volume until State is in Active State. + if (state() == QRadioTuner::ActiveState ) { + m_playerUtility->SetVolume(m_vol*m_volMultiplier); + + } else { + m_volChangeRequired = TRUE; + emit volumeChanged(boundVolume); + } + } + DP0("S60RadioTunerControl::setVolume ---"); +} + +bool S60RadioTunerControl::isMuted() const +{ + DP0("S60RadioTunerControl::isMuted"); + + return m_muted; +} + +void S60RadioTunerControl::setMuted(bool muted) +{ + DP0("S60RadioTunerControl::setMuted +++"); + DP1("S60RadioTunerControl::setMuted, Muted:", muted); + if (m_playerUtility) { + m_muted = muted; + m_playerUtility->Mute(m_muted); + } + DP0("S60RadioTunerControl::setMuted ---"); +} + +bool S60RadioTunerControl::isSearching() const +{ + DP0("S60RadioTunerControl::isSearching"); + + return m_scanning; +} + +void S60RadioTunerControl::cancelSearch() +{ + DP0("S60RadioTunerControl::cancelSearch +++"); + + m_fmTunerUtility->CancelStationSeek(); + m_scanning = false; + emit searchingChanged(false); + + DP0("S60RadioTunerControl::cancelSearch ---"); +} + +void S60RadioTunerControl::searchForward() +{ + DP0("S60RadioTunerControl::searchForward +++"); + m_fmTunerUtility->StationSeek(true); + m_scanning = true; + emit searchingChanged(m_scanning); + DP0("S60RadioTunerControl::searchForward ---"); +} + +void S60RadioTunerControl::searchBackward() +{ + DP0("S60RadioTunerControl::searchBackward +++"); + m_fmTunerUtility->StationSeek(false); + m_scanning = true; + emit searchingChanged(m_scanning); + DP0("S60RadioTunerControl::searchBackward ---"); +} + +bool S60RadioTunerControl::isValid() const +{ + DP0("S60RadioTunerControl::isValid"); + + return m_available; +} + +bool S60RadioTunerControl::initRadio() +{ + DP0("S60RadioTunerControl::initRadio +++"); + m_available = false; + // create an instance of Radio Utility factory and indicate + // FM Radio is a primary client + TRAPD(utilityError, + m_radioUtility = CRadioUtility::NewL(ETrue); + // Get a tuner utility + m_fmTunerUtility = &m_radioUtility->RadioFmTunerUtilityL(*this); + // we want to listen radio in offline mode too + m_fmTunerUtility->EnableTunerInOfflineMode(ETrue); + // Get a player utility + m_playerUtility = &m_radioUtility->RadioPlayerUtilityL(*this); + ); + if (utilityError != KErrNone) { + m_radioError = QRadioTuner::ResourceError; + return m_available; + } + + m_tunerControl = false; + + m_available = true; + DP1("S60RadioTunerControl::initRadio, m_available:", m_available); + DP0("S60RadioTunerControl::initRadio ---"); + return m_available; +} + +bool S60RadioTunerControl::isAvailable() const +{ + DP0("S60RadioTunerControl::isAvailable"); + + return m_available; +} + +QtMultimediaKit::AvailabilityError S60RadioTunerControl::availabilityError() const +{ + DP0("S60RadioTunerControl::availabilityError"); + if (m_available) + return QtMultimediaKit::NoError; + else + return QtMultimediaKit::ResourceError; +} + +void S60RadioTunerControl::start() +{ + DP0("S60RadioTunerControl::start +++"); + if (!m_tunerControl) { + m_fmTunerUtility->RequestTunerControl(); + } else { + m_playerUtility->Play(); + } + m_signalStrengthTimer->start(3000); + + DP0("S60RadioTunerControl::start ---"); +} + +void S60RadioTunerControl::stop() +{ + DP0("S60RadioTunerControl::stop +++"); + if (m_playerUtility) { + m_playerUtility->Stop(); + } + m_signalStrengthTimer->stop(); + DP0("S60RadioTunerControl::stop ---"); +} + +QRadioTuner::Error S60RadioTunerControl::error() const +{ + DP1("S60RadioTunerControl::error", m_radioError); + + return m_radioError; +} +QString S60RadioTunerControl::errorString() const +{ + DP1("S60RadioTunerControl::errorString", m_errorString); + + return m_errorString; +} + +void S60RadioTunerControl::MrpoStateChange(TPlayerState aState, TInt aError) +{ + DP0("S60RadioTunerControl::MrpoStateChange +++"); + if (aError == KErrNone){ + m_radioError = QRadioTuner::NoError; + if (aState == ERadioPlayerIdle) { + m_apiTunerState = QRadioTuner::StoppedState; + } else if (aState == ERadioPlayerPlaying) { + m_apiTunerState = QRadioTuner::ActiveState; + //Apply pending volume changes. + if(m_volChangeRequired){ + setVolume(m_vol); + } + } + } else { + m_apiTunerState = QRadioTuner::StoppedState; + } + emit stateChanged(m_apiTunerState); + DP0("S60RadioTunerControl::MrpoStateChange ---"); +} + +void S60RadioTunerControl::MrpoVolumeChange(TInt aVolume) +{ + DP0("S60RadioTunerControl::MrpoVolumeChange +++"); + DP1("S60RadioTunerControl::MrpoVolumeChange, aVolume:", aVolume); + m_vol = (aVolume/m_volMultiplier); + if (!m_volChangeRequired) { + emit volumeChanged(m_vol); + + } else { + m_volChangeRequired = false; + } + DP0("S60RadioTunerControl::MrpoVolumeChange ---"); +} + +void S60RadioTunerControl::MrpoMuteChange(TBool aMute) +{ + DP0("S60RadioTunerControl::MrpoMuteChange +++"); + DP1("S60RadioTunerControl::MrpoMuteChange, aMute:", aMute); + m_muted = aMute; + emit mutedChanged(m_muted); + DP0("S60RadioTunerControl::MrpoMuteChange ---"); +} + +void S60RadioTunerControl::MrpoBalanceChange(TInt aLeftPercentage, TInt aRightPercentage) +{ + DP0("S60RadioTunerControl::MrpoBalanceChange +++"); + + DP0("S60RadioTunerControl::MrpoBalanceChange ---"); + + // no actions +} + +void S60RadioTunerControl::MrftoRequestTunerControlComplete(TInt aError) +{ + DP0("S60RadioTunerControl::MrftoRequestTunerControlComplete +++"); + DP1("S60RadioTunerControl::MrftoRequestTunerControlComplete, aError:", aError); + if (aError == KErrNone) { + m_playerUtility->GetMaxVolume(m_maxVolume); + m_volMultiplier = float(m_maxVolume)/float(100); + m_radioError = QRadioTuner::NoError; + m_tunerControl = true; + m_available = true; + m_fmTunerUtility->SetFrequency(m_currentFreq); + m_playerUtility->Play(); + int signal = signalStrength(); + if (m_signal != signal) { + emit signalStrengthChanged(signal); + m_signal = signal; + } + + } else if (aError == KFmRadioErrAntennaNotConnected) { + m_radioError = QRadioTuner::OpenError; + m_errorString = QString(tr("Antenna Not Connected")); + emit error(m_radioError); + } else if (aError == KErrAlreadyExists){ + m_radioError = QRadioTuner::ResourceError; + m_errorString = QString(tr("Resource Error.")); + emit error(m_radioError); + } else if (aError == KFmRadioErrFrequencyOutOfBandRange) { + m_radioError = QRadioTuner::OutOfRangeError; + m_errorString = QString(tr("Frequency out of band range")); + emit error(m_radioError); + }else{ + m_radioError = QRadioTuner::OpenError; + m_errorString = QString(tr("Unknown Error.")); + emit error(m_radioError); + } + + DP0("S60RadioTunerControl::MrftoRequestTunerControlComplete ---"); +} + +void S60RadioTunerControl::MrftoSetFrequencyRangeComplete(TInt aError) +{ + DP0("S60RadioTunerControl::MrftoSetFrequencyRangeComplete +++"); + DP1("S60RadioTunerControl::MrftoSetFrequencyRangeComplete, aError:", aError); + if (aError == KFmRadioErrFrequencyOutOfBandRange || KFmRadioErrFrequencyNotValid) { + m_radioError = QRadioTuner::OutOfRangeError; + m_errorString = QString(tr("Frequency Out of Band Range or Frequency Not Valid")); + emit error(m_radioError); + } else if (aError == KFmRadioErrHardwareFaulty || KFmRadioErrOfflineMode) { + m_radioError = QRadioTuner::OpenError; + m_errorString = QString(tr("Hardware failure or RadioInOfflineMode")); + emit error(m_radioError); + } + DP0("S60RadioTunerControl::MrftoSetFrequencyRangeComplete ---"); +} + +void S60RadioTunerControl::MrftoSetFrequencyComplete(TInt aError) +{ + DP0("S60RadioTunerControl::MrftoSetFrequencyComplete +++"); + DP1("S60RadioTunerControl::MrftoSetFrequencyComplete, aError", aError); + if (aError == KErrNone) { + m_radioError = QRadioTuner::NoError; + } else if (aError == KFmRadioErrFrequencyOutOfBandRange || KFmRadioErrFrequencyNotValid) { + m_radioError = QRadioTuner::OutOfRangeError; + m_errorString = QString(tr("Frequency Out of range or not Valid.")); + emit error(m_radioError); + } else if (aError == KFmRadioErrHardwareFaulty || KFmRadioErrOfflineMode) { + m_radioError = QRadioTuner::OpenError; + m_errorString = QString("Hardware failure or Radio In Offline Mode"); + emit error(m_radioError); + } + DP0("S60RadioTunerControl::MrftoSetFrequencyComplete ---"); +} + +void S60RadioTunerControl::MrftoStationSeekComplete(TInt aError, TInt aFrequency) +{ + DP0("S60RadioTunerControl::MrftoStationSeekComplete +++"); + DP3("S60RadioTunerControl::MrftoStationSeekComplete, aError:", aError, " Frequency:", aFrequency); + m_scanning = false; + if (aError == KErrNone) { + m_radioError = QRadioTuner::NoError; + m_currentFreq = aFrequency; + emit searchingChanged(m_scanning); + } else { + m_radioError = QRadioTuner::OpenError; + emit searchingChanged(m_scanning); + m_errorString = QString("Scanning Error"); + emit error(m_radioError); + } + DP0("S60RadioTunerControl::MrftoStationSeekComplete ---"); +} + +void S60RadioTunerControl::MrftoFmTransmitterStatusChange(TBool aActive) +{ + DP0("S60RadioTunerControl::MrftoFmTransmitterStatusChange +++"); + + DP0("S60RadioTunerControl::MrftoFmTransmitterStatusChange ---"); + + //no actions +} + +void S60RadioTunerControl::MrftoAntennaStatusChange(TBool aAttached) +{ + DP0("S60RadioTunerControl::MrftoAntennaStatusChange +++"); + DP1("S60RadioTunerControl::MrftoAntennaStatusChange, aAttached:", aAttached); + if (aAttached && m_tunerControl) { + m_playerUtility->Play(); + } + DP0("S60RadioTunerControl::MrftoAntennaStatusChange ---"); +} + +void S60RadioTunerControl::MrftoOfflineModeStatusChange(TBool /*aOfflineMode*/) +{ + DP0("S60RadioTunerControl::MrftoOfflineModeStatusChange +++"); + + DP0("S60RadioTunerControl::MrftoOfflineModeStatusChange ---"); + + +} + +void S60RadioTunerControl::MrftoFrequencyRangeChange(TFmRadioFrequencyRange aBand /*, TInt aMinFreq, TInt aMaxFreq*/) +{ + DP0("S60RadioTunerControl::MrftoFrequencyRangeChange +++"); + if (aBand == EFmRangeEuroAmerica) { + setBand(QRadioTuner::FM); + } + DP0("S60RadioTunerControl::MrftoFrequencyRangeChange ---"); +} + +void S60RadioTunerControl::MrftoFrequencyChange(TInt aNewFrequency) +{ + DP0("S60RadioTunerControl::MrftoFrequencyChange +++"); + DP1("S60RadioTunerControl::MrftoFrequencyChange, aNewFrequency:", aNewFrequency); + m_currentFreq = aNewFrequency; + emit frequencyChanged(m_currentFreq); + + int signal = signalStrength(); + if (m_signal != signal) { + emit signalStrengthChanged(signal); + m_signal = signal; + } + DP0("S60RadioTunerControl::MrftoFrequencyChange ---"); +} + +void S60RadioTunerControl::MrftoForcedMonoChange(TBool aForcedMono) +{ + DP0("S60RadioTunerControl::MrftoForcedMonoChange +++"); + DP1("S60RadioTunerControl::MrftoForcedMonoChange, aForcedMono:", aForcedMono); + if (aForcedMono) { + m_stereoMode = QRadioTuner::ForceMono; + } else { + m_stereoMode = QRadioTuner::ForceStereo; + } + emit stereoStatusChanged(!aForcedMono); + DP0("S60RadioTunerControl::MrftoForcedMonoChange ---"); +} + +void S60RadioTunerControl::MrftoSquelchChange(TBool aSquelch) +{ + DP0("S60RadioTunerControl::MrftoSquelchChange"); + + DP1("S60RadioTunerControl::MrftoSquelchChange, aSquelch:", aSquelch); + + // no actions +} diff --git a/src/plugins/symbian/mmf/radio/s60radiotunercontrol_since32.h b/src/plugins/symbian/mmf/radio/s60radiotunercontrol_since32.h new file mode 100644 index 000000000..481d64c67 --- /dev/null +++ b/src/plugins/symbian/mmf/radio/s60radiotunercontrol_since32.h @@ -0,0 +1,296 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** +****************************************************************************/ + +#ifndef S60RADIOTUNERCONTROL_H +#define S60RADIOTUNERCONTROL_H + +#include <QtCore/qobject.h> +#include <QtCore/qtimer.h> +#include <qradiotunercontrol.h> +#include <qradiotuner.h> + +#include <RadioUtility.h> +#include <RadioFmTunerUtility.h> +#include <RadioPlayerUtility.h> + +class S60RadioTunerService; +class CFMRadioEngineCallObserver; + +QT_USE_NAMESPACE + +class S60RadioTunerControl + : public QRadioTunerControl + , public MRadioPlayerObserver + , public MRadioFmTunerObserver +{ + Q_OBJECT +public: + S60RadioTunerControl(QObject *parent = 0); + ~S60RadioTunerControl(); + + QRadioTuner::State state() const; + + QRadioTuner::Band band() const; + void setBand(QRadioTuner::Band b); + bool isBandSupported(QRadioTuner::Band b) const; + + int frequency() const; + int frequencyStep(QRadioTuner::Band b) const; + QPair<int,int> frequencyRange(QRadioTuner::Band b) const; + void setFrequency(int frequency); + + bool isStereo() const; + QRadioTuner::StereoMode stereoMode() const; + void setStereoMode(QRadioTuner::StereoMode mode); + + int signalStrength() const; + + int volume() const; + void setVolume(int volume); + + bool isMuted() const; + void setMuted(bool muted); + + bool isSearching() const; + void searchForward(); + void searchBackward(); + void cancelSearch(); + + bool isValid() const; + + bool isAvailable() const; + QtMultimediaKit::AvailabilityError availabilityError() const; + + void start(); + void stop(); + + QRadioTuner::Error error() const; + QString errorString() const; + + /** + * From MRadioPlayerObserver. + * Called when Radio state changed. + * + * @since S60 3.2 + * @param aState Radio player state + * @param aError A standard system error code, only used when aState is ERadioPlayerIdle + */ + void MrpoStateChange(TPlayerState aState, TInt aError); + + /** + * From MRadioPlayerObserver. + * Called when volume changes. This may be caused by other applications. + * + * @since S60 3.2 + * @param aVolume Current volume. + */ + void MrpoVolumeChange(TInt aVolume); + + /** + * From MRadioPlayerObserver. + * Called when mute setting changes. This may be caused by other applications. + * + * @since S60 3.2 + * @param aMute ETrue indicates audio is muted. + */ + void MrpoMuteChange(TBool aMute); + + /** + * From MRadioPlayerObserver. + * Called when mute setting changes. This may be caused by other applications. + * + * Called when balance setting changes. This may be caused by other applications. + * + * @since S60 3.2 + * Left speaker volume percentage. This can be any value from zero to 100. + * Zero value means left speaker is muted. + * @param aRightPercentage + * Right speaker volume percentage. This can be any value from zero to 100. + * Zero value means right speaker is muted. + */ + void MrpoBalanceChange(TInt aLeftPercentage, TInt aRightPercentage); + + + /** + * From MRadioFmTunerObserver. + * Called when Request for tuner control completes. + * + * @since S60 3.2 + * @param aError A standard system error code or FM tuner error (TFmRadioTunerError). + */ + void MrftoRequestTunerControlComplete(TInt aError); + + /** + * From MRadioFmTunerObserver. + * Set frequency range complete event. This event is asynchronous and is received after + * a call to CRadioFmTunerUtility::SetFrequencyRange. + * + * @since S60 3.2 + * @param aError A standard system error code or FM tuner error (TFmRadioTunerError). + */ + void MrftoSetFrequencyRangeComplete(TInt aError); + + /** + * From MRadioFmTunerObserver. + * Set frequency complete event. This event is asynchronous and is received after a call to + * CRadioFmTunerUtility::SetFrequency. + * + * @since S60 3.2 + * @param aError A standard system error code or FM tuner error (TFmRadioTunerError). + */ + void MrftoSetFrequencyComplete(TInt aError); + + /** + * From MRadioFmTunerObserver. + * Station seek complete event. This event is asynchronous and is received after a call to + * CRadioFmTunerUtility::StationSeek. + * + * @since S60 3.2 + * @param aError A standard system error code or FM tuner error (TFmRadioTunerError). + * @param aFrequency The frequency(Hz) of the radio station that was found. + */ + void MrftoStationSeekComplete(TInt aError, TInt aFrequency); + + /** + * From MRadioFmTunerObserver. + * Called when FM Transmitter status changes (if one is present in the device). Tuner receiver + * is forced to be turned off due to hardware conflicts when FM transmitter is activated. + * + * @since S60 3.2 + * @param aActive ETrue if FM transmitter is active; EFalse otherwise. + */ + void MrftoFmTransmitterStatusChange(TBool aActive); + + /** + * From MRadioFmTunerObserver. + * Called when antenna status changes. + * + * @since S60 3.2 + * @param aAttached ETrue if antenna is attached; EFalse otherwise. + */ + void MrftoAntennaStatusChange(TBool aAttached); + + /** + * From MRadioFmTunerObserver. + * Called when offline mode status changes. + * @since S60 3.2 + * + ** @param aAttached ETrue if offline mode is enabled; EFalse otherwise. + */ + void MrftoOfflineModeStatusChange(TBool aOfflineMode); + + /** + * From MRadioFmTunerObserver. + * Called when the frequency range changes. This may be caused by other applications. + * + * @since S60 3.2 + * @param aNewRange New frequency range. + */ + void MrftoFrequencyRangeChange(TFmRadioFrequencyRange aBand /*, TInt aMinFreq, TInt aMaxFreq*/); + + /** + * From MRadioFmTunerObserver. + * Called when the tuned frequency changes. This may be caused by other + * applications or RDS if AF/TA is enabled. + * + * @since S60 3.2 + * @param aNewFrequency The new tuned frequency(Hz). + */ + void MrftoFrequencyChange(TInt aNewFrequency); + + /** + * From MRadioFmTunerObserver. + * Called when the forced mono status change. This may be caused by other applications. + * + * @since S60 3.2 + * @param aForcedMono ETrue if forced mono mode is enabled; EFalse otherwise. + */ + void MrftoForcedMonoChange(TBool aForcedMono); + + /** + * From MRadioFmTunerObserver. + * Called when the squelch (muting the frequencies without broadcast) status change. + * This may be caused by other applications. + * + * @since S60 3.2 + * @param aSquelch ETrue if squelch is enabled; EFalse otherwise. + */ + void MrftoSquelchChange(TBool aSquelch); + +private: + bool initRadio(); + + mutable int m_error; + + CRadioUtility* m_radioUtility; + CRadioFmTunerUtility* m_fmTunerUtility; + CRadioPlayerUtility* m_playerUtility; + TInt m_maxVolume; + TReal m_volMultiplier; + + bool m_tunerControl; + bool m_audioInitializationComplete; + bool m_muted; + bool m_isStereo; + bool m_available; + int m_vol; + bool m_volChangeRequired; + mutable int m_signal; + int m_previousSignal; + bool m_scanning; + QRadioTuner::Band m_currentBand; + qint64 m_currentFreq; + + QRadioTuner::Error m_radioError; + QRadioTuner::StereoMode m_stereoMode; + QString m_errorString; + QRadioTuner::State m_apiTunerState; + QTimer *m_signalStrengthTimer; + +Q_SIGNALS: + void error(QRadioTuner::Error) const; + +protected slots: + void changeSignalStrength(); +}; + +#endif + diff --git a/src/plugins/symbian/mmf/radio/s60radiotunerservice.cpp b/src/plugins/symbian/mmf/radio/s60radiotunerservice.cpp new file mode 100644 index 000000000..99b0bf0d2 --- /dev/null +++ b/src/plugins/symbian/mmf/radio/s60radiotunerservice.cpp @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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 "DebugMacros.h" + +#include "s60radiotunerservice.h" + + +S60RadioTunerService::S60RadioTunerService(QObject *parent) + : QMediaService(parent) +{ + DP0("S60RadioTunerService::S60RadioTunerService +++"); + + m_playerControl = new S60RadioTunerControl(this); + + DP0("S60RadioTunerService::S60RadioTunerService ---"); +} + +S60RadioTunerService::~S60RadioTunerService() +{ + DP0("S60RadioTunerService::~S60RadioTunerService +++"); + + delete m_playerControl; + + DP0("S60RadioTunerService::~S60RadioTunerService ---"); +} + +QMediaControl *S60RadioTunerService::requestControl(const char* name) +{ + DP0("S60RadioTunerService::requestControl"); + + if (qstrcmp(name, QRadioTunerControl_iid) == 0) + return m_playerControl; + + return 0; +} + +void S60RadioTunerService::releaseControl(QMediaControl *control) +{ + DP0("S60RadioTunerService::releaseControl +++"); + + Q_UNUSED(control); + + DP0("S60RadioTunerService::releaseControl ---"); +} diff --git a/src/plugins/symbian/mmf/radio/s60radiotunerservice.h b/src/plugins/symbian/mmf/radio/s60radiotunerservice.h new file mode 100644 index 000000000..92e3eb7f8 --- /dev/null +++ b/src/plugins/symbian/mmf/radio/s60radiotunerservice.h @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** +****************************************************************************/ + +#ifndef S60RADIOTUNERSERVICE_H +#define S60RADIOTUNERSERVICE_H + +#include <QtCore/qobject.h> + +#include <qmediaservice.h> + +#ifdef TUNERLIBUSED +#include "s60radiotunercontrol_31.h" +#else +#include "s60radiotunercontrol_since32.h" +#endif + +QT_USE_NAMESPACE + +class S60RadioTunerService : public QMediaService +{ + Q_OBJECT +public: + S60RadioTunerService(QObject *parent = 0); + ~S60RadioTunerService(); + + QMediaControl *requestControl(const char* name); + void releaseControl(QMediaControl *control); + +private: + S60RadioTunerControl *m_playerControl; +}; + +#endif diff --git a/src/plugins/symbian/mmf/s60formatsupported.cpp b/src/plugins/symbian/mmf/s60formatsupported.cpp new file mode 100644 index 000000000..e892008ab --- /dev/null +++ b/src/plugins/symbian/mmf/s60formatsupported.cpp @@ -0,0 +1,121 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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 "s60formatsupported.h" + + + +S60FormatSupported::S60FormatSupported() +{} + +S60FormatSupported::~S60FormatSupported() +{ + if (m_controllerparam) { + delete m_controllerparam; + m_controllerparam = NULL; + } +} + +QStringList S60FormatSupported::supportedPlayMimeTypesL() +{ + + RArray<TUid> mediaIds; //search for both audio and video + + RMMFControllerImplInfoArray iControllers; + + m_controllerparam = CMMFControllerPluginSelectionParameters::NewL(); + + m_playformatparam = CMMFFormatSelectionParameters::NewL(); + + mediaIds.Append(KUidMediaTypeAudio); + + mediaIds.Append(KUidMediaTypeVideo); + + m_controllerparam->SetMediaIdsL(mediaIds, CMMFPluginSelectionParameters::EAllowOtherMediaIds); + + m_controllerparam->SetRequiredPlayFormatSupportL(*m_playformatparam); + + m_controllerparam->ListImplementationsL(iControllers); + + CDesC8ArrayFlat* controllerArray = new (ELeave) CDesC8ArrayFlat(1); + + for (TInt i = 0; i < iControllers.Count(); i++) { + for (TInt j = 0; j < (iControllers[i]->PlayFormats()).Count(); j++) { + const CDesC8Array& iarr = (iControllers[i]->PlayFormats()[j]->SupportedMimeTypes()); + + TInt count = iarr.Count(); + + for (TInt k = 0; k < count; k++) { + TPtrC8 ptr = iarr.MdcaPoint(k); + + HBufC8* n = HBufC8::NewL(ptr.Length()); + + TPtr8 ptr1 = n->Des(); + + ptr1.Copy((TUint8*) ptr.Ptr(), ptr.Length()); + + controllerArray->AppendL(ptr1); + } + } + } + +// converting CDesC8Array to QStringList + for (TInt x = 0; x < controllerArray->Count(); x++) { + m_supportedplaymime.append(QString::fromUtf8( + (const char*) (controllerArray->MdcaPoint(x).Ptr()), + controllerArray->MdcaPoint(x).Length())); + } + + // populating the list with only audio and controller mime types + QStringList tempaudio = m_supportedplaymime.filter(QString("audio")); + QStringList tempvideo = m_supportedplaymime.filter(QString("video")); + + m_supportedplaymime.clear(); + + m_supportedplaymime = tempaudio + tempvideo; + + mediaIds.Close(); + delete controllerArray; + iControllers.ResetAndDestroy(); + + return m_supportedplaymime; +} diff --git a/src/plugins/symbian/mmf/s60formatsupported.h b/src/plugins/symbian/mmf/s60formatsupported.h new file mode 100644 index 000000000..3b5a3ffe6 --- /dev/null +++ b/src/plugins/symbian/mmf/s60formatsupported.h @@ -0,0 +1,65 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** +****************************************************************************/ + +#ifndef S60FORMATSUPPORTED_H_ +#define S60FORMATSUPPORTED_H_ + +#include <mmf/common/mmfcontrollerpluginresolver.h> +#include <mmf/server/mmfdatasourcesink.hrh> +#include <qstringlist.h> +#include <badesca.h> +#include <qstring.h> + +class S60FormatSupported +{ +public: + S60FormatSupported(); + ~S60FormatSupported(); + + QStringList supportedPlayMimeTypesL(); + +private: + + CMMFFormatSelectionParameters* m_playformatparam; + CMMFControllerPluginSelectionParameters* m_controllerparam; + QStringList m_supportedplaymime; +}; +#endif /* S60FORMATSUPPORTED_H_ */ diff --git a/src/plugins/symbian/mmf/s60mediaserviceplugin.cpp b/src/plugins/symbian/mmf/s60mediaserviceplugin.cpp new file mode 100644 index 000000000..cfb77255f --- /dev/null +++ b/src/plugins/symbian/mmf/s60mediaserviceplugin.cpp @@ -0,0 +1,115 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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/qdebug.h> + +#include "s60mediaserviceplugin.h" +#if defined(TUNERLIBUSED) || defined(RADIOUTILITYLIBUSED) +#include "s60radiotunerservice.h" +#endif +#ifdef HAS_MEDIA_PLAYER +#include "s60mediaplayerservice.h" +#endif +#ifdef AUDIOSOURCEUSED +#include "s60audiocaptureservice.h" +#endif /* AUDIOSOURCEUSED */ + +QStringList S60MediaServicePlugin::keys() const +{ + QStringList list; +#if defined(TUNERLIBUSED) || defined(RADIOUTILITYLIBUSED) + list << QLatin1String(Q_MEDIASERVICE_RADIO); +#endif + +#ifdef HAS_MEDIA_PLAYER + list << QLatin1String(Q_MEDIASERVICE_MEDIAPLAYER); +#endif +#ifdef AUDIOSOURCEUSED + list << QLatin1String(Q_MEDIASERVICE_AUDIOSOURCE); +#endif /* AUDIOSOURCEUSED */ + return list; +} + +QMediaService* S60MediaServicePlugin::create(QString const& key) +{ +#ifdef HAS_MEDIA_PLAYER + if (key == QLatin1String(Q_MEDIASERVICE_MEDIAPLAYER)) + return new S60MediaPlayerService; +#endif +#ifdef AUDIOSOURCEUSED + if (key == QLatin1String(Q_MEDIASERVICE_AUDIOSOURCE)) + return new S60AudioCaptureService; +#endif /* AUDIOSOURCEUSED */ +#if defined(TUNERLIBUSED) || defined(RADIOUTILITYLIBUSED) + if (key == QLatin1String(Q_MEDIASERVICE_RADIO)) + return new S60RadioTunerService; +#endif + + return 0; +} + +void S60MediaServicePlugin::release(QMediaService *service) +{ + delete service; +} + +QtMultimediaKit::SupportEstimate S60MediaServicePlugin::hasSupport(const QString &mimeType, const QStringList& codecs) const +{ + Q_UNUSED(mimeType); + Q_UNUSED(codecs); + return QtMultimediaKit::PreferredService; +} + +QStringList S60MediaServicePlugin::supportedMimeTypes() const +{ + if (m_supportedmimetypes.isEmpty()) { + TInt err; + S60FormatSupported* formats = new (ELeave) S60FormatSupported(); + if (formats) { + TRAP(err, m_supportedmimetypes = formats->supportedPlayMimeTypesL()); + delete formats; + } + } + return m_supportedmimetypes; +} + +Q_EXPORT_PLUGIN2(qtmultimediakit_mmfengine, S60MediaServicePlugin); diff --git a/src/plugins/symbian/mmf/s60mediaserviceplugin.h b/src/plugins/symbian/mmf/s60mediaserviceplugin.h new file mode 100644 index 000000000..b2140dd6f --- /dev/null +++ b/src/plugins/symbian/mmf/s60mediaserviceplugin.h @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** +****************************************************************************/ + + +#ifndef S60SERVICEPLUGIN_H +#define S60SERVICEPLUGIN_H + +#include <QtCore/qobject.h> +#include <qmediaservice.h> +#include <qmediaserviceproviderplugin.h> +#include "s60formatsupported.h" + +QT_USE_NAMESPACE + +class S60MediaServicePlugin : public QMediaServiceProviderPlugin,public QMediaServiceSupportedFormatsInterface +{ + Q_OBJECT + Q_INTERFACES(QMediaServiceSupportedFormatsInterface) +public: + + QStringList keys() const; + QMediaService* create(QString const& key); + void release(QMediaService *service); + + QtMultimediaKit::SupportEstimate hasSupport(const QString &mimeType, const QStringList& codecs) const; + QStringList supportedMimeTypes() const; +private: + mutable QStringList m_supportedmimetypes; +}; + +#endif // S60SERVICEPLUGIN_H diff --git a/src/plugins/symbian/openmaxal/mediaplayer/mediaplayer.pri b/src/plugins/symbian/openmaxal/mediaplayer/mediaplayer.pri new file mode 100644 index 000000000..7c6843e19 --- /dev/null +++ b/src/plugins/symbian/openmaxal/mediaplayer/mediaplayer.pri @@ -0,0 +1,36 @@ +INCLUDEPATH += $$PWD + +LIBS += \ + -lws32 \ + -lcone + +#DEFINES += USE_VIDEOPLAYERUTILITY + +HEADERS += \ + $$PWD/qxametadatacontrol.h \ + $$PWD/qxamediastreamscontrol.h \ + $$PWD/qxamediaplayercontrol.h \ + $$PWD/qxaplaymediaservice.h \ + $$PWD/qxaplaysession.h \ + $$PWD/xaplaysessioncommon.h \ + $$PWD/qxavideowidgetcontrol.h \ + $$PWD/qxavideowindowcontrol.h \ + $$PWD/qxawidget.h \ + $$PWD/xaplaysessionimpl.h + +SOURCES += \ + $$PWD/qxamediaplayercontrol.cpp \ + $$PWD/qxametadatacontrol.cpp \ + $$PWD/qxamediastreamscontrol.cpp \ + $$PWD/qxaplaymediaservice.cpp \ + $$PWD/qxaplaysession.cpp \ + $$PWD/qxavideowidgetcontrol.cpp \ + $$PWD/qxavideowindowcontrol.cpp \ + $$PWD/qxawidget.cpp \ + $$PWD/xaplaysessionimpl.cpp + +# check for USE_VIDEOPLAYERUTILITY +contains(DEFINES, USE_VIDEOPLAYERUTILITY) { + message("Using VideoPlayerUtility instead of OpenMAX AL.") + LIBS += -lmediaclientvideo +} diff --git a/src/plugins/symbian/openmaxal/mediaplayer/qxamediaplayercontrol.cpp b/src/plugins/symbian/openmaxal/mediaplayer/qxamediaplayercontrol.cpp new file mode 100644 index 000000000..ee192105b --- /dev/null +++ b/src/plugins/symbian/openmaxal/mediaplayer/qxamediaplayercontrol.cpp @@ -0,0 +1,288 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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/qurl.h> +#include "qxamediaplayercontrol.h" +#include "qxaplaysession.h" +#include "qxacommon.h" + +QXAMediaPlayerControl::QXAMediaPlayerControl(QXAPlaySession *session, QObject *parent) + :QMediaPlayerControl(parent), mSession(session) +{ + QT_TRACE_FUNCTION_ENTRY; + connect(mSession, SIGNAL(mediaChanged(const QMediaContent &)), + this, SIGNAL(mediaChanged(const QMediaContent& ))); + connect(mSession, SIGNAL(durationChanged(qint64)), + this, SIGNAL(durationChanged(qint64))); + connect(mSession, SIGNAL(positionChanged(qint64)), + this, SIGNAL(positionChanged(qint64))); + connect(mSession, SIGNAL(stateChanged(QMediaPlayer::State)), + this, SIGNAL(stateChanged(QMediaPlayer::State))); + connect(mSession, SIGNAL(mediaStatusChanged(QMediaPlayer::MediaStatus)), + this, SIGNAL(mediaStatusChanged(QMediaPlayer::MediaStatus))); + connect(mSession, SIGNAL(volumeChanged(int)), + this, SIGNAL(volumeChanged(int))); + connect(mSession, SIGNAL(mutedChanged(bool)), + this, SIGNAL(mutedChanged(bool))); + connect(mSession, SIGNAL(audioAvailableChanged(bool)), + this, SIGNAL(audioAvailableChanged(bool))); + connect(mSession, SIGNAL(videoAvailableChanged(bool)), + this, SIGNAL(videoAvailableChanged(bool))); + connect(mSession,SIGNAL(bufferStatusChanged(int)), + this, SIGNAL(bufferStatusChanged(int))); + connect(mSession, SIGNAL(seekableChanged(bool)), + this, SIGNAL(seekableChanged(bool))); + connect(mSession, SIGNAL(availablePlaybackRangesChanged(const QMediaTimeRange&)), + this, SIGNAL(availablePlaybackRangesChanged(const QMediaTimeRange&))); + connect(mSession, SIGNAL(playbackRateChanged(qreal)), + this, SIGNAL(playbackRateChanged(qreal))); + connect(mSession, SIGNAL(error(int, const QString &)), + this, SIGNAL(error(int, const QString &))); + QT_TRACE_FUNCTION_EXIT; +} + +QXAMediaPlayerControl::~QXAMediaPlayerControl() +{ + QT_TRACE_FUNCTION_ENTRY_EXIT; +} + +QMediaPlayer::State QXAMediaPlayerControl::state() const +{ + QT_TRACE_FUNCTION_ENTRY; + QMediaPlayer::State retVal = QMediaPlayer::StoppedState; + RET_s_IF_p_IS_NULL(mSession, retVal); + retVal = mSession->state(); + QT_TRACE_FUNCTION_EXIT; + return retVal; +} + +QMediaPlayer::MediaStatus QXAMediaPlayerControl::mediaStatus() const +{ + QT_TRACE_FUNCTION_ENTRY; + QMediaPlayer::MediaStatus retVal = QMediaPlayer::NoMedia; + RET_s_IF_p_IS_NULL(mSession, retVal); + retVal = mSession->mediaStatus(); + QT_TRACE_FUNCTION_EXIT; + return retVal; +} + +qint64 QXAMediaPlayerControl::duration() const +{ + QT_TRACE_FUNCTION_ENTRY; + qint64 retVal = 0; + RET_s_IF_p_IS_NULL(mSession, retVal); + retVal = mSession->duration(); + QT_TRACE_FUNCTION_EXIT; + return retVal; +} + +qint64 QXAMediaPlayerControl::position() const +{ + QT_TRACE_FUNCTION_ENTRY; + qint64 retVal = 0; + RET_s_IF_p_IS_NULL(mSession, retVal); + retVal = mSession->position(); + QT_TRACE_FUNCTION_EXIT; + return retVal; +} + +void QXAMediaPlayerControl::setPosition(qint64 pos) +{ + QT_TRACE_FUNCTION_ENTRY; + RET_IF_p_IS_NULL(mSession); + mSession->setPosition(pos); + QT_TRACE_FUNCTION_EXIT; +} + +int QXAMediaPlayerControl::volume() const +{ + QT_TRACE_FUNCTION_ENTRY; + int retVal = 0; + RET_s_IF_p_IS_NULL(mSession, retVal); + retVal = mSession->volume(); + QT_TRACE_FUNCTION_EXIT; + return retVal; +} + +void QXAMediaPlayerControl::setVolume(int volume) +{ + QT_TRACE_FUNCTION_ENTRY; + RET_IF_p_IS_NULL(mSession); + mSession->setVolume(volume); + QT_TRACE_FUNCTION_EXIT; +} + +bool QXAMediaPlayerControl::isMuted() const +{ + QT_TRACE_FUNCTION_ENTRY; + bool retVal = false; + RET_s_IF_p_IS_NULL(mSession, retVal); + retVal = mSession->isMuted(); + QT_TRACE_FUNCTION_EXIT; + return retVal; +} + +void QXAMediaPlayerControl::setMuted(bool muted) +{ + QT_TRACE_FUNCTION_ENTRY; + RET_IF_p_IS_NULL(mSession); + mSession->setMuted(muted); + QT_TRACE_FUNCTION_EXIT; +} + +int QXAMediaPlayerControl::bufferStatus() const +{ + QT_TRACE_FUNCTION_ENTRY; + int retVal = 0; + RET_s_IF_p_IS_NULL(mSession, retVal); + retVal = mSession->bufferStatus(); + QT_TRACE_FUNCTION_EXIT; + return retVal; +} + +bool QXAMediaPlayerControl::isAudioAvailable() const +{ + QT_TRACE_FUNCTION_ENTRY; + bool retVal = false; + RET_s_IF_p_IS_NULL(mSession, retVal); + retVal = mSession->isAudioAvailable(); + QT_TRACE_FUNCTION_EXIT; + return retVal; +} + +bool QXAMediaPlayerControl::isVideoAvailable() const +{ + QT_TRACE_FUNCTION_ENTRY; + bool retVal = false; + RET_s_IF_p_IS_NULL(mSession, retVal); + retVal = mSession->isVideoAvailable(); + QT_TRACE_FUNCTION_EXIT; + return retVal; +} + +bool QXAMediaPlayerControl::isSeekable() const +{ + QT_TRACE_FUNCTION_ENTRY; + bool retVal = false; + RET_s_IF_p_IS_NULL(mSession, retVal); + retVal = mSession->isSeekable(); + QT_TRACE_FUNCTION_EXIT; + return retVal; +} + +QMediaTimeRange QXAMediaPlayerControl::availablePlaybackRanges() const +{ + QT_TRACE_FUNCTION_ENTRY; + QMediaTimeRange retVal; + RET_s_IF_p_IS_NULL(mSession, retVal); + if (mSession->isSeekable()) + retVal.addInterval(0, mSession->duration()); + QT_TRACE_FUNCTION_EXIT; + return retVal; +} + +float QXAMediaPlayerControl::playbackRate() const +{ + QT_TRACE_FUNCTION_ENTRY; + float retVal = 0; + RET_s_IF_p_IS_NULL(mSession, retVal); + retVal = mSession->playbackRate(); + QT_TRACE_FUNCTION_EXIT; + return retVal; +} + +void QXAMediaPlayerControl::setPlaybackRate(float rate) +{ + QT_TRACE_FUNCTION_ENTRY; + RET_IF_p_IS_NULL(mSession); + mSession->setPlaybackRate(rate); + QT_TRACE_FUNCTION_EXIT; +} + +QMediaContent QXAMediaPlayerControl::media() const +{ + QT_TRACE_FUNCTION_ENTRY; + QMediaContent retVal; + RET_s_IF_p_IS_NULL(mSession, retVal); + retVal = mSession->media(); + QT_TRACE_FUNCTION_EXIT; + return retVal; +} + +const QIODevice *QXAMediaPlayerControl::mediaStream() const +{ + QT_TRACE_FUNCTION_ENTRY_EXIT; + return mStream; +} + +void QXAMediaPlayerControl::setMedia(const QMediaContent &content, QIODevice *stream) +{ + QT_TRACE_FUNCTION_ENTRY; + RET_IF_p_IS_NULL(mSession); + mSession->setMedia(content); + mStream = stream; + QT_TRACE_FUNCTION_EXIT; +} + +void QXAMediaPlayerControl::play() +{ + QT_TRACE_FUNCTION_ENTRY; + RET_IF_p_IS_NULL(mSession); + mSession->play(); + QT_TRACE_FUNCTION_EXIT; +} + +void QXAMediaPlayerControl::pause() +{ + QT_TRACE_FUNCTION_ENTRY; + RET_IF_p_IS_NULL(mSession); + mSession->pause(); + QT_TRACE_FUNCTION_EXIT; +} + +void QXAMediaPlayerControl::stop() +{ + QT_TRACE_FUNCTION_ENTRY; + RET_IF_p_IS_NULL(mSession); + mSession->stop(); + QT_TRACE_FUNCTION_EXIT; +} diff --git a/src/plugins/symbian/openmaxal/mediaplayer/qxamediaplayercontrol.h b/src/plugins/symbian/openmaxal/mediaplayer/qxamediaplayercontrol.h new file mode 100644 index 000000000..b9d7802bd --- /dev/null +++ b/src/plugins/symbian/openmaxal/mediaplayer/qxamediaplayercontrol.h @@ -0,0 +1,99 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** +****************************************************************************/ + +#ifndef QXAMEDIAPLAYERCONTROL_H +#define QXAMEDIAPLAYERCONTROL_H + +#include "qmediaplayercontrol.h" +#include "qmediaplayer.h" + +QT_USE_NAMESPACE + +class QXAPlaySession; + +class QXAMediaPlayerControl : public QMediaPlayerControl +{ + Q_OBJECT +public: + QXAMediaPlayerControl(QXAPlaySession *session, QObject *parent = 0); + ~QXAMediaPlayerControl(); + + QMediaPlayer::State state() const; + QMediaPlayer::MediaStatus mediaStatus() const; + + qint64 duration() const; + + qint64 position() const; + void setPosition(qint64 position); + + int volume() const; + void setVolume(int volume); + + bool isMuted() const; + void setMuted(bool muted); + + int bufferStatus() const; + + bool isAudioAvailable() const; + bool isVideoAvailable() const; + + bool isSeekable() const; + + QMediaTimeRange availablePlaybackRanges() const; + + float playbackRate() const; + void setPlaybackRate(float rate); + + QMediaContent media() const; + const QIODevice *mediaStream() const; + void setMedia(const QMediaContent&, QIODevice *); + + void play(); + void pause(); + void stop(); + + +private: + QXAPlaySession *mSession; + QIODevice *mStream; +}; + +#endif /* QXAMEDIAPLAYERCONTROL_H */ diff --git a/src/plugins/symbian/openmaxal/mediaplayer/qxamediastreamscontrol.cpp b/src/plugins/symbian/openmaxal/mediaplayer/qxamediastreamscontrol.cpp new file mode 100644 index 000000000..528fb1837 --- /dev/null +++ b/src/plugins/symbian/openmaxal/mediaplayer/qxamediastreamscontrol.cpp @@ -0,0 +1,98 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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/qurl.h> + +#include "qxamediastreamscontrol.h" +#include "qxaplaysession.h" +#include "qxacommon.h" + +QXAMediaStreamsControl::QXAMediaStreamsControl(QXAPlaySession *session, QObject *parent) + :QMediaStreamsControl(parent), mSession(session) +{ + QT_TRACE_FUNCTION_ENTRY; + connect(mSession, SIGNAL(activeStreamsChanged()), + this, SIGNAL(activeStreamsChanged())); + connect(mSession, SIGNAL(streamsChanged()), + this, SIGNAL(streamsChanged())); + QT_TRACE_FUNCTION_EXIT; +} + +QXAMediaStreamsControl::~QXAMediaStreamsControl() +{ + QT_TRACE_FUNCTION_ENTRY_EXIT; +} + +bool QXAMediaStreamsControl::isActive (int stream) +{ + RET_s_IF_p_IS_NULL(mSession, false); + return mSession->isStreamActive(stream); +} + +QVariant QXAMediaStreamsControl::metaData (int stream, QtMultimediaKit::MetaData key) +{ + QVariant var; + RET_s_IF_p_IS_NULL(mSession, var); + QT_TRACE_FUNCTION_ENTRY; + var = mSession->metaData(stream, key); + QT_TRACE_FUNCTION_EXIT; + return var; +} + +void QXAMediaStreamsControl::setActive (int stream, bool state) +{ + Q_UNUSED(stream); + Q_UNUSED(state); +} + +int QXAMediaStreamsControl::streamCount() +{ + RET_s_IF_p_IS_NULL(mSession, 0); + return mSession->streamCount(); +} + +QMediaStreamsControl::StreamType QXAMediaStreamsControl::streamType (int stream) +{ + RET_s_IF_p_IS_NULL(mSession, QMediaStreamsControl::UnknownStream); + return mSession->streamType(stream); +} + diff --git a/src/plugins/symbian/openmaxal/mediaplayer/qxamediastreamscontrol.h b/src/plugins/symbian/openmaxal/mediaplayer/qxamediastreamscontrol.h new file mode 100644 index 000000000..d77b89ca5 --- /dev/null +++ b/src/plugins/symbian/openmaxal/mediaplayer/qxamediastreamscontrol.h @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** +****************************************************************************/ + + +#ifndef QXAMEDIASTREAMSCONTROL_H +#define QXAMEDIASTREAMSCONTROL_H + + + +#include <QStringList> +#include <QList> +#include <QVariant> +#include <QString> + +#include <qtmedianamespace.h> + +#include <qmediastreamscontrol.h> + +QT_USE_NAMESPACE + +class QXAPlaySession; + +class QXAMediaStreamsControl : public QMediaStreamsControl +{ + Q_OBJECT +public: + QXAMediaStreamsControl(QXAPlaySession *session, QObject *parent = 0); + ~QXAMediaStreamsControl(); + + bool isActive (int stream); + QVariant metaData (int stream, QtMultimediaKit::MetaData key); + void setActive (int stream, bool state); + int streamCount(); + QMediaStreamsControl::StreamType streamType (int stream); +private: + QXAPlaySession *mSession; +}; + +#endif //QXAMEDIASTREAMSCONTROL_H diff --git a/src/plugins/symbian/openmaxal/mediaplayer/qxametadatacontrol.cpp b/src/plugins/symbian/openmaxal/mediaplayer/qxametadatacontrol.cpp new file mode 100644 index 000000000..9c6b906cf --- /dev/null +++ b/src/plugins/symbian/openmaxal/mediaplayer/qxametadatacontrol.cpp @@ -0,0 +1,131 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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/qurl.h> + +#include "qxametadatacontrol.h" +#include "qxaplaysession.h" +#include "qxacommon.h" + +QXAMetaDataControl::QXAMetaDataControl(QXAPlaySession *session, QObject *parent) + :QMetaDataReaderControl(parent), mSession(session) +{ + QT_TRACE_FUNCTION_ENTRY; + connect(mSession, SIGNAL(metaDataAvailableChanged(bool)), + this, SIGNAL(metaDataAvailableChanged(bool))); + connect(mSession, SIGNAL(metaDataChanged()), + this, SIGNAL(metaDataChanged())); + QT_TRACE_FUNCTION_EXIT; +} + +QXAMetaDataControl::~QXAMetaDataControl() +{ + QT_TRACE_FUNCTION_ENTRY_EXIT; +} + +QStringList QXAMetaDataControl::availableExtendedMetaData ()const +{ + QStringList list; + RET_s_IF_p_IS_NULL(mSession, list); + QT_TRACE_FUNCTION_ENTRY; + list = mSession->availableExtendedMetaData(); + QT_TRACE_FUNCTION_EXIT; + return list; +} + +QList<QtMultimediaKit::MetaData> QXAMetaDataControl::availableMetaData () const +{ + QList<QtMultimediaKit::MetaData> list; + RET_s_IF_p_IS_NULL(mSession, list); + QT_TRACE_FUNCTION_ENTRY; + list = mSession->availableMetaData(); + QT_TRACE_FUNCTION_EXIT; + return list; +} + +QVariant QXAMetaDataControl::extendedMetaData(const QString & key ) const +{ + QVariant var; + RET_s_IF_p_IS_NULL(mSession, var); + QT_TRACE_FUNCTION_ENTRY; + var = mSession->extendedMetaData(key); + QT_TRACE_FUNCTION_EXIT; + return var; +} + +bool QXAMetaDataControl::isMetaDataAvailable() const +{ + RET_s_IF_p_IS_NULL(mSession, false); + QT_TRACE_FUNCTION_ENTRY_EXIT; + return mSession->isMetaDataAvailable(); +} + +bool QXAMetaDataControl::isWritable() const +{ + RET_s_IF_p_IS_NULL(mSession, false); + QT_TRACE_FUNCTION_ENTRY_EXIT; + return mSession->isWritable(); +} + +QVariant QXAMetaDataControl::metaData( QtMultimediaKit::MetaData key ) const +{ + QVariant var; + RET_s_IF_p_IS_NULL(mSession, var); + QT_TRACE_FUNCTION_ENTRY; + var = mSession->metaData(key); + QT_TRACE_FUNCTION_ENTRY_EXIT; + return var; +} + +void QXAMetaDataControl::setExtendedMetaData( const QString & key, const QVariant & value ) +{ + RET_IF_p_IS_NULL(mSession); + QT_TRACE_FUNCTION_ENTRY_EXIT; + return mSession->setExtendedMetaData(key,value); +} + +void QXAMetaDataControl::setMetaData( QtMultimediaKit::MetaData key, const QVariant & value ) +{ + RET_IF_p_IS_NULL(mSession); + QT_TRACE_FUNCTION_ENTRY_EXIT; + return mSession->setMetaData(key,value); +} + diff --git a/src/plugins/symbian/openmaxal/mediaplayer/qxametadatacontrol.h b/src/plugins/symbian/openmaxal/mediaplayer/qxametadatacontrol.h new file mode 100644 index 000000000..8904a5ff4 --- /dev/null +++ b/src/plugins/symbian/openmaxal/mediaplayer/qxametadatacontrol.h @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** +****************************************************************************/ + +#ifndef QXAMETADATACONTROL_H +#define QXAMETADATACONTROL_H + + + +#include <QStringList> +#include <QList> +#include <QVariant> +#include <QString> + +#include <qmetadatareadercontrol.h> +#include <qtmedianamespace.h> +QT_USE_NAMESPACE + +class QXAPlaySession; + +class QXAMetaDataControl : public QMetaDataReaderControl +{ + Q_OBJECT +public: + QXAMetaDataControl(QXAPlaySession *session, QObject *parent = 0); + ~QXAMetaDataControl(); + + QStringList availableExtendedMetaData () const; + QList<QtMultimediaKit::MetaData> availableMetaData () const; + QVariant extendedMetaData(const QString & key ) const; + bool isMetaDataAvailable() const; + bool isWritable() const; + QVariant metaData( QtMultimediaKit::MetaData key ) const; + void setExtendedMetaData( const QString & key, const QVariant & value ); + void setMetaData( QtMultimediaKit::MetaData key, const QVariant & value ); + +private: + QXAPlaySession *mSession; +}; + +#endif //QXAMETADATACONTROL_H diff --git a/src/plugins/symbian/openmaxal/mediaplayer/qxaplaymediaservice.cpp b/src/plugins/symbian/openmaxal/mediaplayer/qxaplaymediaservice.cpp new file mode 100644 index 000000000..f2d3c4b15 --- /dev/null +++ b/src/plugins/symbian/openmaxal/mediaplayer/qxaplaymediaservice.cpp @@ -0,0 +1,117 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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 <QString> +#include "qxaplaymediaservice.h" +#include "qxaplaysession.h" +#include "qxamediaplayercontrol.h" +#include "qxacommon.h" +#include "qxavideowidgetcontrol.h" +#include "qxavideowindowcontrol.h" +#include "qxametadatacontrol.h" +#include "qxamediastreamscontrol.h" + +QXAPlayMediaService::QXAPlayMediaService(QObject *parent) : QMediaService(parent) +{ + mSession = NULL; + mMediaPlayerControl = NULL; + mVideowidgetControl = NULL; + mVideoWindowControl = NULL; + mMetaDataControl = NULL; + mMediaStreamsControl = NULL; + + mSession = new QXAPlaySession(this); + mMediaPlayerControl = new QXAMediaPlayerControl(mSession, this); + mMetaDataControl = new QXAMetaDataControl(mSession, this); + mMediaStreamsControl = new QXAMediaStreamsControl(mSession, this); +} + +QXAPlayMediaService::~QXAPlayMediaService() +{ + QT_TRACE_FUNCTION_ENTRY_EXIT; +} + +QMediaControl *QXAPlayMediaService::requestControl(const char *name) +{ + if (qstrcmp(name, QMediaPlayerControl_iid) == 0) { + return mMediaPlayerControl; + } + else if (qstrcmp(name, QVideoWidgetControl_iid) == 0) { + if (!mVideowidgetControl) { + mVideowidgetControl = new QXAVideoWidgetControl(mSession, this); + if (mSession && mVideowidgetControl) + mSession->setVideoWidgetControl(mVideowidgetControl); + } + return mVideowidgetControl; + } + else if (qstrcmp(name, QVideoWindowControl_iid) == 0) { + if (!mVideoWindowControl) { + mVideoWindowControl = new QXAVideoWindowControl(mSession, this); + if (mSession && mVideoWindowControl) + mSession->setVideoWindowControl(mVideoWindowControl); + } + return mVideoWindowControl; + } + else if (qstrcmp(name,QMetaDataReaderControl_iid) == 0) { + return mMetaDataControl; + } + else if (qstrcmp(name,QMediaStreamsControl_iid) == 0) { + return mMediaStreamsControl; + } + + return 0; +} + +void QXAPlayMediaService::releaseControl(QMediaControl *control) +{ + if (control == mVideowidgetControl) { + if (mSession) + mSession->unsetVideoWidgetControl(qobject_cast<QXAVideoWidgetControl*>(control)); + mVideowidgetControl = NULL; + } + else if (control == mVideoWindowControl) { + if (mSession) + mSession->unsetVideoWindowControl(qobject_cast<QXAVideoWindowControl*>(control)); + mVideoWindowControl = NULL; + } +} + diff --git a/src/plugins/symbian/openmaxal/mediaplayer/qxaplaymediaservice.h b/src/plugins/symbian/openmaxal/mediaplayer/qxaplaymediaservice.h new file mode 100644 index 000000000..4a344b087 --- /dev/null +++ b/src/plugins/symbian/openmaxal/mediaplayer/qxaplaymediaservice.h @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** +****************************************************************************/ + +#ifndef QXAPLAYMEDIASERVICE_H +#define QXAPLAYMEDIASERVICE_H + +#include <QtCore/qobject.h> +#include <qmediaservice.h> + +QT_USE_NAMESPACE + +class QXAPlaySession; +class QXAMediaPlayerControl; +class QXAVideoWidgetControl; +class QXAVideoWindowControl; +class QXAMetaDataControl; +class QXAMediaStreamsControl; + +class QXAPlayMediaService : public QMediaService +{ + Q_OBJECT +public: + QXAPlayMediaService(QObject *parent = 0); + ~QXAPlayMediaService(); + QMediaControl *requestControl(const char *name); + void releaseControl( QMediaControl *control); +private: + QXAPlaySession *mSession; + QXAMediaPlayerControl *mMediaPlayerControl; + QXAVideoWidgetControl *mVideowidgetControl; + QXAVideoWindowControl *mVideoWindowControl; + QXAMetaDataControl *mMetaDataControl; + QXAMediaStreamsControl *mMediaStreamsControl; +}; + +#endif /* QXAPLAYMEDIASERVICE_H */ diff --git a/src/plugins/symbian/openmaxal/mediaplayer/qxaplaysession.cpp b/src/plugins/symbian/openmaxal/mediaplayer/qxaplaysession.cpp new file mode 100644 index 000000000..2254a9363 --- /dev/null +++ b/src/plugins/symbian/openmaxal/mediaplayer/qxaplaysession.cpp @@ -0,0 +1,610 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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 <QMetaType> +#include "qxaplaysession.h" +#include "xaplaysessionimpl.h" +#include "qxacommon.h" +#include <COECNTRL.H> + +QXAPlaySession::QXAPlaySession(QObject *parent):QObject(parent), +m_state(QMediaPlayer::StoppedState), +m_mediaStatus(QMediaPlayer::NoMedia), +mSeekable(-1), +mNumStreams(0), +mbAudioAvailable(EFalse), +mbVideoAvailable(EFalse), +mImpl(NULL), +mVideowidgetControl(NULL), +mWidgetCtrlWindow(NULL), +mWidgetCtrlWindowId(NULL), +mVideoWindowControl(NULL), +mWindowCtrlWindow(NULL), +mWindowCtrlWindowId(NULL), +mWsSession(&(CCoeEnv::Static()->WsSession())) +{ + QT_TRACE_FUNCTION_ENTRY; + mImpl = new XAPlaySessionImpl(*this); + + if (mImpl && (mImpl->postConstruct() != KErrNone)) { + delete mImpl; + mImpl = NULL; + QT_TRACE1("Error initializing implementation"); + } + + if (!mImpl) + emit error(QMediaPlayer::ResourceError, tr("Service has not been started")); + + QT_TRACE_FUNCTION_EXIT; +} + +QXAPlaySession::~QXAPlaySession() +{ + QT_TRACE_FUNCTION_ENTRY; + delete mImpl; + QT_TRACE_FUNCTION_EXIT; +} + +void QXAPlaySession::setVideoWidgetControl( QXAVideoWidgetControl * videoWidgetControl ) +{ + QT_TRACE_FUNCTION_ENTRY; + if (mVideowidgetControl) { + disconnect(mVideowidgetControl, SIGNAL(widgetUpdated()), + this, SLOT(videoWidgetControlWidgetUpdated())); + RWindow* window = static_cast<RWindow*>(mVideowidgetControl->videoWidgetWId()->DrawableWindow()); + mImpl->removeNativeDisplay(window, mWsSession); + } + mVideowidgetControl = videoWidgetControl; + if (mVideowidgetControl) + connect(mVideowidgetControl, SIGNAL(widgetUpdated()), + this, SLOT(videoWidgetControlWidgetUpdated())); + QT_TRACE_FUNCTION_EXIT; +} + +void QXAPlaySession::unsetVideoWidgetControl( QXAVideoWidgetControl * videoWidgetControl ) +{ + QT_TRACE_FUNCTION_ENTRY; + if ((mVideowidgetControl == videoWidgetControl) && (mImpl)) { + disconnect(mVideowidgetControl, SIGNAL(widgetUpdated()), + this, SLOT(videoWidgetControlWidgetUpdated())); + RWindow* window = static_cast<RWindow*>(mVideowidgetControl->videoWidgetWId()->DrawableWindow()); + mImpl->removeNativeDisplay(window, mWsSession); + } + mVideowidgetControl = NULL; + mWidgetCtrlWindow = NULL; + mWidgetCtrlWindowId = NULL; + QT_TRACE_FUNCTION_EXIT; +} + +void QXAPlaySession::setVideoWindowControl( QXAVideoWindowControl * videoWindowControl ) +{ + QT_TRACE_FUNCTION_ENTRY; + if (mVideoWindowControl) { + disconnect(mVideoWindowControl, SIGNAL(windowUpdated()), + this, SLOT(videoWindowControlWindowUpdated())); + RWindow* window = static_cast<RWindow*>(mVideoWindowControl->winId()->DrawableWindow()); + mImpl->removeNativeDisplay(window, mWsSession); + } + mVideoWindowControl = videoWindowControl; + if (mVideoWindowControl) { + connect(mVideoWindowControl, SIGNAL(windowUpdated()), + this, SLOT(videoWindowControlWindowUpdated())); + videoWindowControlWindowUpdated(); + } + QT_TRACE_FUNCTION_EXIT; +} + +void QXAPlaySession::unsetVideoWindowControl( QXAVideoWindowControl * videoWindowControl ) +{ + QT_TRACE_FUNCTION_ENTRY; + if ((mVideoWindowControl == videoWindowControl) && (mImpl)) { + disconnect(mVideoWindowControl, SIGNAL(windowUpdated()), + this, SLOT(videoWindowControlWindowUpdated())); + RWindow* window = static_cast<RWindow*>(mVideoWindowControl->winId()->DrawableWindow()); + mImpl->removeNativeDisplay(window, mWsSession); + } + mVideoWindowControl = NULL; + mWindowCtrlWindow = NULL; + mWindowCtrlWindowId = NULL; + QT_TRACE_FUNCTION_EXIT; +} + +qint64 QXAPlaySession::duration() +{ + TInt64 dur(0); + if (mImpl) + mImpl->duration(dur); + + return (qint64)dur; +} + +qint64 QXAPlaySession::position() +{ + TInt64 pos(0); + if (mImpl) + mImpl->position(pos); + + return (qint64)pos; +} + +void QXAPlaySession::setPosition(qint64 ms) +{ + if (mImpl) { + qint64 currPos = position(); + mImpl->seek(ms); + + if(currPos != position()) { + emit positionChanged(position()); + + if(position()>=duration()) { + setMediaStatus(QMediaPlayer::EndOfMedia); + stop(); + } + } + } +} + +int QXAPlaySession::volume() +{ + if(mImpl) { + TInt v(0); + + TInt err = mImpl->volume(v); + if(KErrNone == err) + return v; + } + + return 50; +} + +void QXAPlaySession::setVolume(int v) +{ + if(mImpl) { + if(v != volume()) { + TInt err = mImpl->setVolume(v); + if(KErrNone == err) + emit volumeChanged(volume()); + } + } +} + + +bool QXAPlaySession::isMuted() +{ + if(mImpl) { + TBool bCurrMute = EFalse; + TInt err = mImpl->getMute(bCurrMute); + if(err == KErrNone) + return bCurrMute; + } + + return EFalse; +} + +void QXAPlaySession::setMuted(bool muted) +{ + if(muted != isMuted()) + { + if(mImpl) + { + TInt err = mImpl->setMute(muted); + + if(KErrNone == err) + { + emit mutedChanged(muted); + } + } + } +} + +int QXAPlaySession::bufferStatus() +{ + if(mImpl) { + TInt fillLevel = 0; + TInt err = mImpl->bufferStatus(fillLevel); + if(err == KErrNone) + return fillLevel; + } + + return 100;//default +} + +bool QXAPlaySession::isAudioAvailable() +{ + return mbAudioAvailable; +} + +bool QXAPlaySession::isVideoAvailable() +{ + return mbVideoAvailable; +} + +bool QXAPlaySession::isSeekable() +{ + return ((mSeekable==1) || (mSeekable==-1));//default seekable +} + +float QXAPlaySession::playbackRate() +{ + if(mImpl) { + TReal32 currPBRate = 0.0; + TInt ret = mImpl->getPlaybackRate(currPBRate); + if(ret == KErrNone) + return currPBRate; + } + + return 1.0; +} + +void QXAPlaySession::setPlaybackRate(float rate) +{ + if(mImpl) { + TReal32 currPBRate = 0.0; + TInt ret = mImpl->getPlaybackRate(currPBRate); + if( (ret == KErrNone) && + (rate!=currPBRate)) { + ret = mImpl->setPlaybackRate(rate); + if(ret == KErrNone) + emit playbackRateChanged(rate); + } + } +} + +QMediaContent QXAPlaySession::media() +{ + QT_TRACE_FUNCTION_ENTRY_EXIT; + return mMediaContent; +} + +void QXAPlaySession::setMedia(const QMediaContent& media) +{ + QT_TRACE_FUNCTION_ENTRY; + RET_IF_p_IS_NULL_EMIT_PLAYER_RESOURCE_ERROR(mImpl); + + if (media.isNull() || + mMediaContent == media) { + return; + } + + setMediaStatus(QMediaPlayer::NoMedia); + + QString urlStr = media.canonicalUrl().toString(); + TPtrC16 urlPtr(reinterpret_cast<const TUint16*>(urlStr.utf16())); + + setMediaStatus(QMediaPlayer::LoadingMedia); + if (mImpl->load(urlPtr) == 0) { + setMediaStatus(QMediaPlayer::LoadedMedia); + emit error(QMediaPlayer::NoError, ""); + mMediaContent = media; + setPlayerState(QMediaPlayer::StoppedState); + emit mediaChanged(mMediaContent); + + if(mImpl->isMetaDataAvailable()) { + emit metaDataAvailableChanged(true); + emit metaDataChanged(); + } + else { + emit metaDataAvailableChanged(false); + } + } + else { + setMediaStatus(QMediaPlayer::NoMedia); + emit error(QMediaPlayer::ResourceError, tr("Unable to load media")); + } + QT_TRACE_FUNCTION_EXIT; +} + +void QXAPlaySession::play() +{ + if (mImpl) { + setMediaStatus(QMediaPlayer::BufferingMedia); + + TInt err = mImpl->play(); + if (err != KErrNone) { + setMediaStatus(QMediaPlayer::NoMedia); + RET_IF_ERROR(err); + } + setPlayerState(QMediaPlayer::PlayingState); + + TInt fillLevel = 0; + err = mImpl->bufferStatus(fillLevel); + RET_IF_ERROR(err); + if (fillLevel == 100) { + setMediaStatus(QMediaPlayer::BufferedMedia); + } + } +} + +void QXAPlaySession::pause() +{ + if (mImpl) { + TInt err = mImpl->pause(); + RET_IF_ERROR(err); + setPlayerState(QMediaPlayer::PausedState); + } +} + +void QXAPlaySession::stop() +{ + if (mImpl) { + TInt err = mImpl->stop(); + RET_IF_ERROR(err); + setPlayerState(QMediaPlayer::StoppedState); + } +} + +void QXAPlaySession::cbDurationChanged(TInt64 new_dur) +{ + emit durationChanged((qint64)new_dur); +} + +void QXAPlaySession::cbPositionChanged(TInt64 new_pos) +{ + emit positionChanged((qint64)new_pos); +} + +void QXAPlaySession::cbSeekableChanged(TBool seekable) +{ + if( (mSeekable==-1) || + (seekable != (TBool)mSeekable)) { + mSeekable = seekable?1:0; + emit seekableChanged((bool)seekable); + } +} + +void QXAPlaySession::cbPlaybackStopped(TInt err) +{ + if (err) { + emit error(QMediaPlayer::ResourceError, tr("Resources Unavailable")); + SIGNAL_EMIT_TRACE1("emit error(QMediaPlayer::ResourceError, tr(\"Resources Unavailable\"))"); + emit positionChanged(position()); + setPlayerState(QMediaPlayer::StoppedState); + setMediaStatus(QMediaPlayer::NoMedia); + } + else { + setMediaStatus(QMediaPlayer::EndOfMedia); + /* Set player state to Stopped */ + stop(); + } +} + +void QXAPlaySession::cbPrefetchStatusChanged() +{ + if(mImpl) { + TInt fillLevel = 0; + TInt err = mImpl->bufferStatus(fillLevel); + if(err == KErrNone) { + emit bufferStatusChanged(fillLevel); + + if(fillLevel == 100) + setMediaStatus(QMediaPlayer::BufferedMedia); + else if(fillLevel ==0) + setMediaStatus(QMediaPlayer::StalledMedia); + } + } +} + +void QXAPlaySession::cbStreamInformation(TBool bFirstTime) +{ + updateStreamInfo(bFirstTime); +} + + + +void QXAPlaySession::videoWidgetControlWidgetUpdated() +{ + QT_TRACE_FUNCTION_ENTRY; + if (mVideowidgetControl) { + WId newId = mVideowidgetControl->videoWidgetWId(); + if ((newId != NULL) && (newId != mWidgetCtrlWindowId)) { + mWidgetCtrlWindow = static_cast<RWindow*>(newId->DrawableWindow()); + if (mWidgetCtrlWindowId == NULL) + mImpl->addNativeDisplay(mWidgetCtrlWindow, mWsSession); + else + mImpl->updateNativeDisplay(mWidgetCtrlWindow, mWsSession); + mWidgetCtrlWindowId = newId; + } + } + QT_TRACE_FUNCTION_EXIT; +} + +void QXAPlaySession::videoWindowControlWindowUpdated() +{ + QT_TRACE_FUNCTION_ENTRY; + if (mVideoWindowControl) { + WId newId = mVideoWindowControl->winId(); + if ((newId != NULL) && (newId != mWindowCtrlWindowId)) { + mWidgetCtrlWindow = static_cast<RWindow*>(newId->DrawableWindow()); + if (mWindowCtrlWindowId == NULL) + mImpl->addNativeDisplay(mWidgetCtrlWindow, mWsSession); + else + mImpl->updateNativeDisplay(mWidgetCtrlWindow, mWsSession); + mWindowCtrlWindowId = newId; + } + } + QT_TRACE_FUNCTION_EXIT; +} + +void QXAPlaySession::setMediaStatus(QMediaPlayer::MediaStatus status) +{ + if (m_mediaStatus != status) { + m_mediaStatus = status; + emit mediaStatusChanged(status); + } +} + +void QXAPlaySession::setPlayerState(QMediaPlayer::State state) +{ + if (m_state != state) { + m_state = state; + emit stateChanged(m_state); + } +} + +QStringList QXAPlaySession::availableExtendedMetaData () const +{ + QStringList list; + RET_s_IF_p_IS_NULL(mImpl, list); + list = mImpl->availableExtendedMetaData(); + return list; +} + +QList<QtMultimediaKit::MetaData> QXAPlaySession::availableMetaData () const +{ + QList<QtMultimediaKit::MetaData> list; + RET_s_IF_p_IS_NULL(mImpl, list); + return mImpl->availableMetaData(); +} + +QVariant QXAPlaySession::extendedMetaData(const QString & key ) const +{ + QVariant var; + RET_s_IF_p_IS_NULL(mImpl, var); + return mImpl->extendedMetaData(key); +} + +bool QXAPlaySession::isMetaDataAvailable() const +{ + RET_s_IF_p_IS_NULL(mImpl, false); + return mImpl->isMetaDataAvailable(); +} + +bool QXAPlaySession::isWritable() const +{ + RET_s_IF_p_IS_NULL(mImpl, false); + return mImpl->isWritable(); +} + +QVariant QXAPlaySession::metaData( QtMultimediaKit::MetaData key ) const +{ + QVariant var; + RET_s_IF_p_IS_NULL(mImpl, var); + return mImpl->metaData(key); +} + +void QXAPlaySession::setExtendedMetaData( const QString & key, const QVariant & value ) +{ + RET_IF_p_IS_NULL(mImpl); + mImpl->setExtendedMetaData(key, value); +} + +void QXAPlaySession::setMetaData( QtMultimediaKit::MetaData key, const QVariant & value ) +{ + RET_IF_p_IS_NULL(mImpl); + mImpl->setMetaData(key, value); +} + +void QXAPlaySession::updateStreamInfo(TBool emitSignal) +{ + if(mImpl) { + mNumStreams = 0; + TInt ret = mImpl->numMediaStreams(mNumStreams); + if(ret == KErrNone) { + TBool bAudioAvailable = EFalse;//lcoal variable + TBool bVideoAvailable = EFalse;//lcvoal variable + + for(TUint i = 0; i < mNumStreams; i++) { + QMediaStreamsControl::StreamType strType; + mImpl->streamType(i, strType); + if(strType == QMediaStreamsControl::AudioStream) + bAudioAvailable = ETrue; + else if(strType == QMediaStreamsControl::VideoStream) + bVideoAvailable = ETrue; + } + + if(emitSignal || (bAudioAvailable != mbAudioAvailable)) { + emit audioAvailableChanged(bAudioAvailable); + mbAudioAvailable = bAudioAvailable; + } + + if(emitSignal || (bVideoAvailable != mbVideoAvailable)) { + emit videoAvailableChanged(bVideoAvailable); + mbVideoAvailable = bVideoAvailable; + } + + emit streamsChanged(); + } + } +} + +bool QXAPlaySession::isStreamActive ( int stream ) +{ + RET_s_IF_p_IS_NULL(mImpl, false); + TBool isActive = EFalse; + mImpl->isStreamActive(stream,isActive); + return isActive; +} + +QVariant QXAPlaySession::metaData ( int /*stream*/, QtMultimediaKit::MetaData key ) +{ + return this->metaData(key); +} + +int QXAPlaySession::streamCount() +{ + return mNumStreams; +} + +QMediaStreamsControl::StreamType QXAPlaySession::streamType ( int stream ) +{ + QMediaStreamsControl::StreamType strType = QMediaStreamsControl::UnknownStream; + RET_s_IF_p_IS_NULL(mImpl, strType); + if(mImpl->streamType(stream, strType) == KErrNone) { + return strType; + } + + return QMediaStreamsControl::UnknownStream; +} + +////AspectRatioMode +void QXAPlaySession::setAspectRatioMode(Qt::AspectRatioMode aspectRatioMode) +{ + RET_IF_p_IS_NULL(mImpl); + mImpl->setAspectRatioMode(aspectRatioMode); +} + +Qt::AspectRatioMode QXAPlaySession::getAspectRatioMode() +{ + RET_s_IF_p_IS_NULL(mImpl, Qt::KeepAspectRatio); + return mImpl->getAspectRatioMode(); +} + + diff --git a/src/plugins/symbian/openmaxal/mediaplayer/qxaplaysession.h b/src/plugins/symbian/openmaxal/mediaplayer/qxaplaysession.h new file mode 100644 index 000000000..0d366518f --- /dev/null +++ b/src/plugins/symbian/openmaxal/mediaplayer/qxaplaysession.h @@ -0,0 +1,192 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** +****************************************************************************/ + +#ifndef QXAPLAYSESSION_H +#define QXAPLAYSESSION_H + +#include <QObject> +#include <QUrl> +#include <qtmedianamespace.h> + +#include "qxamediaplayercontrol.h" +#include "qxametadatacontrol.h" +#include "qmediaplayer.h" +#include "xaplaysessioncommon.h" +#include "qxavideowidgetcontrol.h" +#include "qxavideowindowcontrol.h" +#include "qmediastreamscontrol.h" + + +QT_USE_NAMESPACE + +class XAPlaySessionImpl; +class RWindow; +class RWsSession; +class QXAVideoWidgetControl; + +class QXAPlaySession : public QObject, + public XAPlayObserver +{ + Q_OBJECT +public: + QXAPlaySession(QObject *parent); + virtual ~QXAPlaySession(); + + void setVideoWidgetControl( QXAVideoWidgetControl * videoWidgetControl ); + void unsetVideoWidgetControl( QXAVideoWidgetControl * videoWidgetControl ); + void setVideoWindowControl( QXAVideoWindowControl * videoWindowControl ); + void unsetVideoWindowControl( QXAVideoWindowControl * videoWindowControl ); + + //QXAMediaPlayerControl + QMediaPlayer::State state() const { return m_state; } + QMediaPlayer::MediaStatus mediaStatus() const { return m_mediaStatus; } + qint64 duration(); + qint64 position(); + void setPosition(qint64 position); + int volume(); + void setVolume(int volume); + bool isMuted(); + void setMuted(bool muted); + int bufferStatus(); + bool isAudioAvailable(); + bool isVideoAvailable(); + bool isSeekable(); + float playbackRate(); + void setPlaybackRate(float rate); + QMediaContent media(); + void setMedia(const QMediaContent& media); + void play(); + void pause(); + void stop(); + + // Callback from XAPlaySessionImpl + void cbDurationChanged(TInt64 new_dur); + void cbPositionChanged(TInt64 new_pos); + void cbSeekableChanged(TBool seekable); + void cbPlaybackStopped(TInt error); + void cbPrefetchStatusChanged(); + void cbStreamInformation(TBool); + + //MetadataControl methods + QStringList availableExtendedMetaData () const; + QList<QtMultimediaKit::MetaData> availableMetaData () const; + QVariant extendedMetaData(const QString & key ) const; + bool isMetaDataAvailable() const; + bool isWritable() const; + QVariant metaData( QtMultimediaKit::MetaData key ) const; + void setExtendedMetaData( const QString & key, const QVariant & value ); + void setMetaData( QtMultimediaKit::MetaData key, const QVariant & value ); + + //QMediaStreamsControl + bool isStreamActive ( int stream ) ; + QVariant metaData ( int stream, QtMultimediaKit::MetaData key ); + int streamCount(); + QMediaStreamsControl::StreamType streamType ( int stream ); + + //QVideoWidgetControl + void setAspectRatioMode(Qt::AspectRatioMode); + Qt::AspectRatioMode getAspectRatioMode(); + +public Q_SLOTS: + void videoWidgetControlWidgetUpdated(); + void videoWindowControlWindowUpdated(); + +Q_SIGNALS: + void mediaChanged(const QMediaContent& content); + void durationChanged(qint64 duration); + void positionChanged(qint64 position); + void stateChanged(QMediaPlayer::State newState); + void mediaStatusChanged(QMediaPlayer::MediaStatus status); + void volumeChanged(int volume); + void mutedChanged(bool muted); + void audioAvailableChanged(bool audioAvailable); + void videoAvailableChanged(bool videoAvailable); + void bufferStatusChanged(int percentFilled); + void seekableChanged(bool); + void availablePlaybackRangesChanged(const QMediaTimeRange&); + void error(int errorCode, const QString &errorString); + void playbackRateChanged(qreal rate); + + //metadata + void metaDataAvailableChanged(bool); + void metaDataChanged(); + void writableChanged(bool); + + //QMediaStreamsControl + void streamsChanged(); + void activeStreamsChanged(); + +private: + void setMediaStatus(QMediaPlayer::MediaStatus); + void setPlayerState(QMediaPlayer::State state); + void updateStreamInfo(TBool emitSignal = EFalse); + +private: + QMediaPlayer::State m_state; + QMediaPlayer::MediaStatus m_mediaStatus; + + QMap<QString,QVariant> m_tags; + QList< QMap<QString,QVariant> > m_streamProperties; + + //seekable + int mSeekable; //-1 =unintialized, 0=nonseekable, 1=seekable + + //StreamInfo + TUint mNumStreams; + TBool mbAudioAvailable; + TBool mbVideoAvailable; + + //Own + XAPlaySessionImpl* mImpl; + + // Does not own + QXAVideoWidgetControl *mVideowidgetControl; + RWindow *mWidgetCtrlWindow; + WId mWidgetCtrlWindowId; + QXAVideoWindowControl *mVideoWindowControl; + RWindow *mWindowCtrlWindow; + WId mWindowCtrlWindowId; + RWsSession *mWsSession; + + QMediaContent mMediaContent; +}; + +#endif /* QXAPLAYSESSION_H */ diff --git a/src/plugins/symbian/openmaxal/mediaplayer/qxavideowidgetcontrol.cpp b/src/plugins/symbian/openmaxal/mediaplayer/qxavideowidgetcontrol.cpp new file mode 100644 index 000000000..6e9c833fd --- /dev/null +++ b/src/plugins/symbian/openmaxal/mediaplayer/qxavideowidgetcontrol.cpp @@ -0,0 +1,182 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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 "qxavideowidgetcontrol.h" +#include "qxacommon.h" +#include "qxawidget.h" +#include <QEvent> + +QXAVideoWidgetControl::QXAVideoWidgetControl(QXAPlaySession *session, QObject *parent) + : QVideoWidgetControl(parent), mSession(session) +{ + QT_TRACE_FUNCTION_ENTRY; + mWidget = new QXAWidget; + if (mWidget) + mWidget->installEventFilter(this); + QT_TRACE_FUNCTION_EXIT; +} + +QXAVideoWidgetControl::~QXAVideoWidgetControl() +{ + QT_TRACE_FUNCTION_ENTRY; + delete mWidget; + QT_TRACE_FUNCTION_EXIT; +} + +QWidget* QXAVideoWidgetControl::videoWidget() +{ + QT_TRACE_FUNCTION_ENTRY_EXIT; + return mWidget; +} + +Qt::AspectRatioMode QXAVideoWidgetControl::aspectRatioMode() const +{ + QT_TRACE_FUNCTION_ENTRY; + RET_s_IF_p_IS_NULL(mSession, Qt::IgnoreAspectRatio); + QT_TRACE_FUNCTION_EXIT; + return mSession->getAspectRatioMode(); +} + +void QXAVideoWidgetControl::setAspectRatioMode(Qt::AspectRatioMode mode) +{ + QT_TRACE_FUNCTION_ENTRY; + RET_IF_p_IS_NULL(mSession); + mSession->setAspectRatioMode(mode); + QT_TRACE_FUNCTION_EXIT; +} + +bool QXAVideoWidgetControl::isFullScreen() const +{ + QT_TRACE_FUNCTION_ENTRY; + bool retVal = false; + RET_s_IF_p_IS_NULL(mWidget, retVal); + retVal = mWidget->isFullScreen(); + QT_TRACE_FUNCTION_EXIT; + return retVal; +} + +void QXAVideoWidgetControl::setFullScreen(bool fullScreen) +{ + QT_TRACE_FUNCTION_ENTRY; + RET_IF_p_IS_NULL(mWidget); + if (fullScreen == mWidget->isFullScreen()) + return; + else if (fullScreen) + mWidget->showFullScreen(); + else + mWidget->showNormal(); + + emit fullScreenChanged(fullScreen); + + QT_TRACE_FUNCTION_EXIT; +} + +int QXAVideoWidgetControl::brightness() const +{ + QT_TRACE_FUNCTION_ENTRY_EXIT; + return 0; +} + +void QXAVideoWidgetControl::setBrightness(int brightness) +{ + QT_TRACE_FUNCTION_ENTRY_EXIT; + Q_UNUSED(brightness); +} + +int QXAVideoWidgetControl::contrast() const +{ + QT_TRACE_FUNCTION_ENTRY_EXIT; + return 0; +} + +void QXAVideoWidgetControl::setContrast(int contrast) +{ + QT_TRACE_FUNCTION_ENTRY_EXIT; + Q_UNUSED(contrast); +} + +int QXAVideoWidgetControl::hue() const +{ + QT_TRACE_FUNCTION_ENTRY_EXIT; + return 0; +} + +void QXAVideoWidgetControl::setHue(int hue) +{ + QT_TRACE_FUNCTION_ENTRY_EXIT; + Q_UNUSED(hue); +} + +int QXAVideoWidgetControl::saturation() const +{ + QT_TRACE_FUNCTION_ENTRY_EXIT; + return 0; +} + +void QXAVideoWidgetControl::setSaturation(int saturation) +{ + QT_TRACE_FUNCTION_ENTRY_EXIT; + Q_UNUSED(saturation); +} + +bool QXAVideoWidgetControl::eventFilter(QObject *object, QEvent *event) +{ + if (object == mWidget) { + if ( event->type() == QEvent::Resize + || event->type() == QEvent::Move + || event->type() == QEvent::WinIdChange + || event->type() == QEvent::ParentChange + || event->type() == QEvent::Show) { + emit widgetUpdated(); + } + } + return false; +} + +WId QXAVideoWidgetControl::videoWidgetWId() +{ + if (mWidget->internalWinId()) + return mWidget->internalWinId(); + else if (mWidget->effectiveWinId()) + return mWidget->effectiveWinId(); + + return NULL; +} diff --git a/src/plugins/symbian/openmaxal/mediaplayer/qxavideowidgetcontrol.h b/src/plugins/symbian/openmaxal/mediaplayer/qxavideowidgetcontrol.h new file mode 100644 index 000000000..7a0eda765 --- /dev/null +++ b/src/plugins/symbian/openmaxal/mediaplayer/qxavideowidgetcontrol.h @@ -0,0 +1,93 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** +****************************************************************************/ + +#ifndef QXAVIDEOWIDGETCONTROL_H +#define QXAVIDEOWIDGETCONTROL_H + +#include <QObject> +#include <qvideowidgetcontrol.h> +#include "qxaplaysession.h" + +QT_USE_NAMESPACE + +class QXAWidget; + +class QXAVideoWidgetControl : public QVideoWidgetControl +{ + Q_OBJECT +public: + QXAVideoWidgetControl(QXAPlaySession *session, QObject *parent = 0); + ~QXAVideoWidgetControl(); + + QWidget *videoWidget(); + + Qt::AspectRatioMode aspectRatioMode() const; + void setAspectRatioMode(Qt::AspectRatioMode mode); + + bool isFullScreen() const; + void setFullScreen(bool fullScreen); + + int brightness() const; + void setBrightness(int brightness); + + int contrast() const; + void setContrast(int contrast); + + int hue() const; + void setHue(int hue); + + int saturation() const; + void setSaturation(int saturation); + + bool eventFilter(QObject *object, QEvent *event); + + WId videoWidgetWId(); + +Q_SIGNALS: + void widgetUpdated(); + +private: + QXAPlaySession *mSession; + QXAWidget *mWidget; + +}; + +#endif // QXAVIDEOWIDGETCONTROL_H diff --git a/src/plugins/symbian/openmaxal/mediaplayer/qxavideowindowcontrol.cpp b/src/plugins/symbian/openmaxal/mediaplayer/qxavideowindowcontrol.cpp new file mode 100644 index 000000000..c19b949ac --- /dev/null +++ b/src/plugins/symbian/openmaxal/mediaplayer/qxavideowindowcontrol.cpp @@ -0,0 +1,222 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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 "qxavideowindowcontrol.h" +#include "qxacommon.h" +#include <QEvent> +#include "qxaplaysession.h" + +QXAVideoWindowControl::QXAVideoWindowControl(QXAPlaySession* session, QObject *parent) + :QVideoWindowControl(parent), + mWid(NULL), + mWidget(NULL), + mAspectRatioMode(Qt::IgnoreAspectRatio), + mSession(session) +{ + QT_TRACE_FUNCTION_ENTRY_EXIT; +} + +QXAVideoWindowControl::~QXAVideoWindowControl() +{ + QT_TRACE_FUNCTION_ENTRY; + if (mWidget) + mWidget->removeEventFilter(this); + QT_TRACE_FUNCTION_EXIT; +} + +WId QXAVideoWindowControl::winId() const +{ + QT_TRACE_FUNCTION_ENTRY_EXIT; + return mWid; +} + +void QXAVideoWindowControl::setWinId(WId id) +{ + QT_TRACE_FUNCTION_ENTRY; + if (mWid != id) { + if (mWidget) + mWidget->removeEventFilter(this); + mWid = id; + mWidget = QWidget::find(mWid); + if (mWidget) + mWidget->installEventFilter(this); + emit windowUpdated(); + } + QT_TRACE_FUNCTION_EXIT; +} + +QRect QXAVideoWindowControl::displayRect() const +{ + QT_TRACE_FUNCTION_ENTRY_EXIT; + return mDisplayRect; +} + +void QXAVideoWindowControl::setDisplayRect(const QRect &rect) +{ + QT_TRACE_FUNCTION_ENTRY; + mDisplayRect = rect; + QT_TRACE_FUNCTION_EXIT; +} + +bool QXAVideoWindowControl::isFullScreen() const +{ + QT_TRACE_FUNCTION_ENTRY; + bool retVal(false); + if (mWidget) + retVal = mWidget->isFullScreen(); + QT_TRACE_FUNCTION_EXIT; + return retVal; +} + +void QXAVideoWindowControl::setFullScreen(bool fullScreen) +{ + QT_TRACE_FUNCTION_ENTRY; + if (mWidget && (fullScreen != mWidget->isFullScreen())) { + if (fullScreen) + mWidget->showFullScreen(); + else + mWidget->showNormal(); + emit fullScreenChanged(fullScreen); + } + QT_TRACE_FUNCTION_EXIT; +} + +void QXAVideoWindowControl::repaint() +{ +} + +QSize QXAVideoWindowControl::nativeSize() const +{ + QT_TRACE_FUNCTION_ENTRY; + QSize size(0, 0); + RET_s_IF_p_IS_NULL(mSession, size); + QVariant sizeBundle = mSession->metaData(QtMultimediaKit::Resolution); + QString metadata = sizeBundle.toString(); + if (!metadata.isNull() && !metadata.isEmpty()) { + int xIndex = metadata.indexOf('x'); + if (xIndex > 0) { + size.setWidth(metadata.left(xIndex).toInt()); + xIndex = metadata.length() - (xIndex + 1); + if (xIndex > 0) + size.setHeight(metadata.right(xIndex).toInt()); + } + } + QT_TRACE_FUNCTION_EXIT; + return size; +} + +Qt::AspectRatioMode QXAVideoWindowControl::aspectRatioMode() const +{ + QT_TRACE_FUNCTION_ENTRY; + RET_s_IF_p_IS_NULL(mSession, Qt::IgnoreAspectRatio); + QT_TRACE_FUNCTION_EXIT; + return mSession->getAspectRatioMode(); +} + +void QXAVideoWindowControl::setAspectRatioMode(Qt::AspectRatioMode mode) +{ + QT_TRACE_FUNCTION_ENTRY; + RET_IF_p_IS_NULL(mSession); + mSession->setAspectRatioMode(mode); + QT_TRACE_FUNCTION_EXIT; +} + +int QXAVideoWindowControl::brightness() const +{ + QT_TRACE_FUNCTION_ENTRY_EXIT; + return 0; +} + +void QXAVideoWindowControl::setBrightness(int brightness) +{ + QT_TRACE_FUNCTION_ENTRY_EXIT; + Q_UNUSED(brightness); +} + +int QXAVideoWindowControl::contrast() const +{ + QT_TRACE_FUNCTION_ENTRY_EXIT; + return 0; +} + +void QXAVideoWindowControl::setContrast(int contrast) +{ + QT_TRACE_FUNCTION_ENTRY_EXIT; + Q_UNUSED(contrast); +} + +int QXAVideoWindowControl::hue() const +{ + QT_TRACE_FUNCTION_ENTRY_EXIT; + return 0; +} + +void QXAVideoWindowControl::setHue(int hue) +{ + QT_TRACE_FUNCTION_ENTRY_EXIT; + Q_UNUSED(hue); +} + +int QXAVideoWindowControl::saturation() const +{ + QT_TRACE_FUNCTION_ENTRY_EXIT; + return 0; +} + +void QXAVideoWindowControl::setSaturation(int saturation) +{ + QT_TRACE_FUNCTION_ENTRY_EXIT; + Q_UNUSED(saturation); +} + +bool QXAVideoWindowControl::eventFilter(QObject *object, QEvent *event) +{ + if (object == mWidget) { + if (event->type() == QEvent::Resize + || event->type() == QEvent::Move + || event->type() == QEvent::WinIdChange + || event->type() == QEvent::ParentChange + || event->type() == QEvent::Show) { + emit windowUpdated(); + } + } + return false; +} diff --git a/src/plugins/symbian/openmaxal/mediaplayer/qxavideowindowcontrol.h b/src/plugins/symbian/openmaxal/mediaplayer/qxavideowindowcontrol.h new file mode 100644 index 000000000..879349822 --- /dev/null +++ b/src/plugins/symbian/openmaxal/mediaplayer/qxavideowindowcontrol.h @@ -0,0 +1,105 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** +****************************************************************************/ + +#ifndef QXAVIDEOWINDOWCONTROL_H +#define QXAVIDEOWINDOWCONTROL_H + +#include <QObject> +#include <QVideoWindowControl> + +QT_USE_NAMESPACE + +class QXAPlaySession; + +class QXAVideoWindowControl : public QVideoWindowControl +{ + Q_OBJECT + +public: + QXAVideoWindowControl(QXAPlaySession* session, QObject *parent = 0); + ~QXAVideoWindowControl(); + + // QVideoWindowControl virtual functions + WId winId() const; + void setWinId(WId id); + + QRect displayRect() const; + void setDisplayRect(const QRect &rect); + + bool isFullScreen() const; + void setFullScreen(bool fullScreen); + + void repaint(); + + QSize nativeSize() const; + + Qt::AspectRatioMode aspectRatioMode() const; + void setAspectRatioMode(Qt::AspectRatioMode mode); + + int brightness() const; + void setBrightness(int brightness); + + int contrast() const; + void setContrast(int contrast); + + int hue() const; + void setHue(int hue); + + int saturation() const; + void setSaturation(int saturation); + + //Callback function to receive event from Qt framework + //for object represented by mWid + bool eventFilter(QObject *object, QEvent *event); + +Q_SIGNALS: + void windowUpdated(); + +private: + WId mWid; + QWidget* mWidget; /* QWidget represented by mWid */ + QRect mDisplayRect; + Qt::AspectRatioMode mAspectRatioMode; + + QXAPlaySession* mSession; +}; + +#endif /* QXAVIDEOWINDOWCONTROL_H */ diff --git a/src/plugins/symbian/openmaxal/mediaplayer/qxawidget.cpp b/src/plugins/symbian/openmaxal/mediaplayer/qxawidget.cpp new file mode 100644 index 000000000..4685226fd --- /dev/null +++ b/src/plugins/symbian/openmaxal/mediaplayer/qxawidget.cpp @@ -0,0 +1,64 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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 "qxawidget.h" +#include <coemain.h> + +QXAWidget::QXAWidget(QWidget *parent) + : QWidget(parent) +{ + setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + setAttribute(Qt::WA_OpaquePaintEvent, true); + setAttribute(Qt::WA_NoSystemBackground, true); + setAutoFillBackground(false); + setPalette(QPalette(Qt::black)); + /* Initialize the native window*/ + winId(); +} + +QXAWidget::~QXAWidget() +{ +} + +void QXAWidget::paintEvent(QPaintEvent *event) +{ + Q_UNUSED(event); +} diff --git a/src/plugins/symbian/openmaxal/mediaplayer/qxawidget.h b/src/plugins/symbian/openmaxal/mediaplayer/qxawidget.h new file mode 100644 index 000000000..d36be1fa4 --- /dev/null +++ b/src/plugins/symbian/openmaxal/mediaplayer/qxawidget.h @@ -0,0 +1,63 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** +****************************************************************************/ + +#ifndef QXAWIDGET_H +#define QXAWIDGET_H + +#include <QObject> +#include <qwidget.h> + +QT_USE_NAMESPACE + +class QXAWidget : public QWidget +{ + Q_OBJECT + +public: + QXAWidget(QWidget *parent = 0); + virtual ~QXAWidget(); + +protected: + void paintEvent(QPaintEvent *event); +}; + + +#endif /* QXAWIDGET_H */ diff --git a/src/plugins/symbian/openmaxal/mediaplayer/xaplaysessioncommon.h b/src/plugins/symbian/openmaxal/mediaplayer/xaplaysessioncommon.h new file mode 100644 index 000000000..a9497e475 --- /dev/null +++ b/src/plugins/symbian/openmaxal/mediaplayer/xaplaysessioncommon.h @@ -0,0 +1,58 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** +****************************************************************************/ + +#ifndef XAPLAYSESSIONCOMMON_H +#define XAPLAYSESSIONCOMMON_H + +#include <e32base.h> + +class XAPlayObserver + { +public: + virtual void cbDurationChanged(TInt64 new_dur) = 0; + virtual void cbPositionChanged(TInt64 new_pos) = 0; + virtual void cbSeekableChanged(TBool seekable) = 0; + virtual void cbPlaybackStopped(TInt error) = 0; + virtual void cbPrefetchStatusChanged() = 0; + virtual void cbStreamInformation(TBool bFirstTime) = 0; + }; + +#endif /*XAPLAYSESSIONCOMMON_H*/ diff --git a/src/plugins/symbian/openmaxal/mediaplayer/xaplaysessionimpl.cpp b/src/plugins/symbian/openmaxal/mediaplayer/xaplaysessionimpl.cpp new file mode 100644 index 000000000..88a06807f --- /dev/null +++ b/src/plugins/symbian/openmaxal/mediaplayer/xaplaysessionimpl.cpp @@ -0,0 +1,1259 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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 <QString> +#include <QVariant> +#include <QList> +#include <QStringList> +#include <QImage> + +#include "xaplaysessionimpl.h" +#include "xaplaysessioncommon.h" +#include "xacommon.h" + +#ifdef USE_VIDEOPLAYERUTILITY +#include <COECNTRL.H> +#endif + +_LIT8(K8WAVMIMETYPE, "audio/wav"); + +#define RET_ERR_IF_ERR(e) \ + if (e != 0) {\ + return e; \ + } \ + +#define MAX_NUMBER_INTERFACES 20 +const TUint KPlayPosUpdatePeriod = 1000; + +/* Local functions for callback registation */ +void MediaPlayerCallback( XAObjectItf caller, + const void *pContext, + XAuint32 event, + XAresult result, + XAuint32 param, + void *pInterface); + +void PlayItfCallback( XAPlayItf caller, + void *pContext, + XAuint32 event); + +void PrefetchItfCallback( XAPrefetchStatusItf caller, + void * pContext, + XAuint32 event); + +void StreamInformationItfCallback( XAStreamInformationItf caller, + XAuint32 eventId, + XAuint32 streamIndex, + void * pEventData, + void * pContext); + +XAPlaySessionImpl::XAPlaySessionImpl(XAPlayObserver& parent) +:mParent(parent), +mEOEngine(NULL), +mMOPlayer(NULL), +mPlayItf(NULL), +mSeekItf(NULL), +mURIName(NULL), +mWAVMime(NULL), +mbMetadataAvailable(EFalse), +mbVolEnabled(EFalse), +mbMuteEnabled(EFalse), +mbPrefetchStatusChange(EFalse), +mbStreamInfoAvailable(EFalse), +mbPlaybackRateItfAvailable(EFalse), +mbScalable(EFalse), +mCurrAspectRatioMode(Qt::KeepAspectRatio) +#ifdef USE_VIDEOPLAYERUTILITY +, mVideoPlayUtil(NULL) +, mActiveSchedulerWait(NULL) +#endif +{ +} + +XAPlaySessionImpl::~XAPlaySessionImpl() +{ + if (mMOPlayer) + (*mMOPlayer)->Destroy(mMOPlayer); + + if (mEOEngine) + (*mEOEngine)->Destroy(mEOEngine); + + delete mURIName; + delete mWAVMime; + + //clear metadata datastructures + alKeyMap.clear(); + keyMap.clear(); + extendedKeyMap.clear(); + +#ifdef USE_VIDEOPLAYERUTILITY + delete mVideoPlayUtil; + if (mActiveSchedulerWait && \ + mActiveSchedulerWait->IsStarted()) { + mActiveSchedulerWait->AsyncStop(); + } + + delete mActiveSchedulerWait; +#endif + +} + +TInt XAPlaySessionImpl::postConstruct() +{ + TInt retVal; + XAresult xaRes; + XAEngineOption engineOption[] = { (XAuint32) XA_ENGINEOPTION_THREADSAFE, + (XAuint32) XA_BOOLEAN_TRUE + }; + XAEngineItf engineItf; + + mNativeDisplay.locatorType = XA_DATALOCATOR_NATIVEDISPLAY; + mNativeDisplay.hWindow = NULL; + mNativeDisplay.hDisplay = NULL; + mVideoSink.pLocator = (void*)&mNativeDisplay; + mVideoSink.pFormat = NULL; + + // Create and realize Engine object + xaRes = xaCreateEngine (&mEOEngine, 1, engineOption, 0, NULL, NULL); + retVal = mapError(xaRes, ETrue); + RET_ERR_IF_ERR(retVal); + xaRes = (*mEOEngine)->Realize(mEOEngine, XA_BOOLEAN_FALSE); + retVal = mapError(xaRes, ETrue); + RET_ERR_IF_ERR(retVal); + + // Create and realize Output Mix object to be used by player + xaRes = (*mEOEngine)->GetInterface(mEOEngine, XA_IID_ENGINE, (void**) &engineItf); + retVal = mapError(xaRes, ETrue); + RET_ERR_IF_ERR(retVal); + + TRAP(retVal, mWAVMime = HBufC8::NewL(K8WAVMIMETYPE().Length() + 1)); + RET_ERR_IF_ERR(retVal); + TPtr8 ptr = mWAVMime->Des(); + ptr = K8WAVMIMETYPE(); // copy uri name into local variable + ptr.PtrZ(); // append zero terminator to end of URI + +#ifdef USE_VIDEOPLAYERUTILITY + TRAP(retVal, mVideoPlayUtil = + CVideoPlayerUtility2::NewL( *this, + EMdaPriorityNormal, + EMdaPriorityPreferenceTimeAndQuality) + ); + mActiveSchedulerWait = new CActiveSchedulerWait; +#endif + + return retVal; +} + +TInt XAPlaySessionImpl::addNativeDisplay(RWindow* window, RWsSession* wssession) + { + TInt retVal(KErrNotReady); + + if (!mMOPlayer && !mPlayItf) { + // window can only be set before player creation + mNativeDisplay.locatorType = XA_DATALOCATOR_NATIVEDISPLAY; + mNativeDisplay.hWindow = (void*)window; + mNativeDisplay.hDisplay = (void*)wssession; + retVal = KErrNone; + } + return retVal; +} + +TInt XAPlaySessionImpl::updateNativeDisplay(RWindow* /*window*/, RWsSession* /*wssession*/) +{ + return KErrNone; +} + +TInt XAPlaySessionImpl::removeNativeDisplay(RWindow* /*window*/, RWsSession* /*wssession*/) +{ + return KErrNone; +} + +TInt XAPlaySessionImpl::load(const TDesC& aURI) +{ + TInt retVal; + XAresult xaRes; + XAEngineItf engineItf; + XADynamicSourceItf dynamicSourceItf; + XAboolean required[MAX_NUMBER_INTERFACES]; + XAInterfaceID iidArray[MAX_NUMBER_INTERFACES]; + XAuint32 noOfInterfaces = 0; + TInt i; + + XAmillisecond dur(0); + TPtr8 uriPtr(0,0,0); + TPtr8 mimeTypePtr(0,0,0); + +#ifdef USE_VIDEOPLAYERUTILITY + TRAP(m_VPError, mVideoPlayUtil->OpenFileL(_L("C:\\data\\test.3gp"))); + if (m_VPError) + return 0; + + if(!mActiveSchedulerWait->IsStarted()) + mActiveSchedulerWait->Start(); + + if (m_VPError) + return 0; + + mVideoPlayUtil->Prepare(); + + if(!mActiveSchedulerWait->IsStarted()) + mActiveSchedulerWait->Start(); + + return 0; +#endif + + delete mURIName; + mURIName = NULL; + TRAP(retVal, mURIName = HBufC8::NewL(aURI.Length()+1)); + RET_ERR_IF_ERR(retVal); + uriPtr.Set(mURIName->Des()); + + // This has to be done here since we can not destroy the Player + // in the Resource Lost callback. + if (mbMediaPlayerUnrealized) { + if (mMOPlayer) { + (*mMOPlayer)->Destroy(mMOPlayer); + mMOPlayer = NULL; + } + } + + //py uri name into local variable + //TODO fix copy issue from 16 bit to 8 bit + uriPtr.Copy(aURI); + + //If media player object already exists, just switch source + //using dynamic source interface + if (mMOPlayer && mPlayItf) { + dynamicSourceItf = NULL; + xaRes = (*mMOPlayer)->GetInterface(mMOPlayer, XA_IID_DYNAMICSOURCE, &dynamicSourceItf); + retVal = mapError(xaRes, ETrue); + RET_ERR_IF_ERR(retVal); + + //Setup the data source + //TODO Hard coded locator type + mUri.locatorType = XA_DATALOCATOR_URI; + + //append zero terminator to end of URI + mUri.URI = (XAchar*) uriPtr.PtrZ(); + + //TODO Hard coded locator type + mMime.containerType = XA_CONTAINERTYPE_WAV; + + //TODO Hard coded locator type + mMime.formatType = XA_DATAFORMAT_MIME; + mimeTypePtr.Set(mWAVMime->Des()); + mMime.mimeType = (XAchar*)mimeTypePtr.Ptr(); + mDataSource.pFormat = (void*)&mMime; + mDataSource.pLocator = (void*)&mUri; + + xaRes = (*dynamicSourceItf)->SetSource(dynamicSourceItf, &mDataSource); + retVal = mapError(xaRes, ETrue); + RET_ERR_IF_ERR(retVal); + } + else { // Create media player object + + // Setup the data source + // TODO Hard coded locator type + mUri.locatorType = XA_DATALOCATOR_URI; + + //append zero terminator to end of URI + mUri.URI = (XAchar*) uriPtr.PtrZ(); + + //TODO Hard coded locator type + mMime.containerType = XA_CONTAINERTYPE_WAV; + + //TODO Hard coded locator type + mMime.formatType = XA_DATAFORMAT_MIME; + mimeTypePtr.Set(mWAVMime->Des()); + mMime.mimeType = (XAchar*)mimeTypePtr.Ptr(); + mDataSource.pFormat = (void*)&mMime; + mDataSource.pLocator = (void*)&mUri; + + //Setup the audio data sink + mLocatorOutputDevice.locatorType = XA_DATALOCATOR_IODEVICE; + mLocatorOutputDevice.deviceType = 6; + mAudioSink.pLocator = (void*) &mLocatorOutputDevice; + mAudioSink.pFormat = NULL; + + //Init arrays required[] and iidArray[] + for (i = 0; i < MAX_NUMBER_INTERFACES; i++) { + required[i] = XA_BOOLEAN_FALSE; + iidArray[i] = XA_IID_NULL; + } + + noOfInterfaces = 0; + required[noOfInterfaces] = XA_BOOLEAN_FALSE; + iidArray[noOfInterfaces] = XA_IID_SEEK; + noOfInterfaces++; + required[noOfInterfaces] = XA_BOOLEAN_FALSE; + iidArray[noOfInterfaces] = XA_IID_DYNAMICSOURCE; + noOfInterfaces++; + required[noOfInterfaces] = XA_BOOLEAN_FALSE; + iidArray[noOfInterfaces] = XA_IID_METADATAEXTRACTION; + noOfInterfaces++; + required[noOfInterfaces] = XA_BOOLEAN_FALSE; + iidArray[noOfInterfaces] = XA_IID_NOKIALINEARVOLUME; + noOfInterfaces++; + required[noOfInterfaces] = XA_BOOLEAN_FALSE; + iidArray[noOfInterfaces] = XA_IID_NOKIAVOLUMEEXT; + noOfInterfaces++; + required[noOfInterfaces] = XA_BOOLEAN_FALSE; + iidArray[noOfInterfaces] = XA_IID_PREFETCHSTATUS; + noOfInterfaces++; + required[noOfInterfaces] = XA_BOOLEAN_FALSE; + iidArray[noOfInterfaces] = XA_IID_STREAMINFORMATION; + noOfInterfaces++; + required[noOfInterfaces] = XA_BOOLEAN_FALSE; + iidArray[noOfInterfaces] = XA_IID_PLAYBACKRATE; + noOfInterfaces++; + required[noOfInterfaces] = XA_BOOLEAN_FALSE; + iidArray[noOfInterfaces] = XA_IID_VIDEOPOSTPROCESSING; + noOfInterfaces++; + + xaRes = (*mEOEngine)->GetInterface(mEOEngine, XA_IID_ENGINE, (void**) &engineItf); + retVal = mapError(xaRes, ETrue); + RET_ERR_IF_ERR(retVal); + + xaRes = (*engineItf)->CreateMediaPlayer(engineItf, + &mMOPlayer, + &mDataSource, + NULL, + &mAudioSink, + &mVideoSink, + NULL, + NULL, + noOfInterfaces, + iidArray, + required); + retVal = mapError(xaRes, ETrue); + RET_ERR_IF_ERR(retVal); + + xaRes = (*mMOPlayer)->Realize(mMOPlayer, XA_BOOLEAN_FALSE); + retVal = mapError(xaRes, ETrue); + RET_ERR_IF_ERR(retVal); + + mbMediaPlayerUnrealized = FALSE; + + xaRes = (*mMOPlayer)->RegisterCallback(mMOPlayer, MediaPlayerCallback, (void*)this); + retVal = mapError(xaRes, ETrue); + RET_ERR_IF_ERR(retVal); + + xaRes = (*mMOPlayer)->GetInterface(mMOPlayer, XA_IID_PLAY, &mPlayItf); + retVal = mapError(xaRes, ETrue); + RET_ERR_IF_ERR(retVal); + + xaRes = (*mPlayItf)->RegisterCallback(mPlayItf, PlayItfCallback, (void*)this); + retVal = mapError(xaRes, ETrue); + RET_ERR_IF_ERR(retVal); + + xaRes = (*mPlayItf)->SetPositionUpdatePeriod(mPlayItf, (XAmillisecond)KPlayPosUpdatePeriod); + retVal = mapError(xaRes, ETrue); + RET_ERR_IF_ERR(retVal); + + xaRes = (*mPlayItf)->SetCallbackEventsMask( mPlayItf, + ( XA_PLAYEVENT_HEADATEND | + XA_PLAYEVENT_HEADATNEWPOS | + XA_PLAYEVENT_HEADMOVING ) + ); + retVal = mapError(xaRes, ETrue); + RET_ERR_IF_ERR(retVal); + + xaRes = (*mMOPlayer)->GetInterface(mMOPlayer, XA_IID_SEEK, &mSeekItf); + retVal = mapError(xaRes, ETrue); + + //Metadata + xaRes = (*mMOPlayer)->GetInterface(mMOPlayer, XA_IID_METADATAEXTRACTION, &mMetadataExtItf); + if(mapError(xaRes, ETrue)==KErrNone) { + mbMetadataAvailable = ETrue; + setupALKeyMap(); //done only once at creation of meadia player + } + + //volume + xaRes = (*mMOPlayer)->GetInterface(mMOPlayer, XA_IID_NOKIALINEARVOLUME, &mNokiaLinearVolumeItf); + if(mapError(xaRes, ETrue)==KErrNone) + mbVolEnabled = ETrue; + + xaRes = (*mMOPlayer)->GetInterface(mMOPlayer, XA_IID_NOKIAVOLUMEEXT, &mNokiaVolumeExtItf); + if(mapError(xaRes, ETrue)==KErrNone) + mbMuteEnabled = ETrue; + + //buffer status + xaRes = (*mMOPlayer)->GetInterface(mMOPlayer, XA_IID_PREFETCHSTATUS, &mPrefetchStatusItf); + if(mapError(xaRes, ETrue)==KErrNone) { + mbPrefetchStatusChange = ETrue; + (*mPrefetchStatusItf)->RegisterCallback(mPrefetchStatusItf, PrefetchItfCallback, (void*)this); + (*mPrefetchStatusItf)->SetCallbackEventsMask(mPrefetchStatusItf, XA_PREFETCHEVENT_FILLLEVELCHANGE); + } + + //stream information + xaRes = (*mMOPlayer)->GetInterface(mMOPlayer, XA_IID_STREAMINFORMATION, &mStreamInformationItf); + if(mapError(xaRes, ETrue)==KErrNone) { + mbStreamInfoAvailable = ETrue; + mParent.cbStreamInformation(ETrue); //indicate first time + (*mStreamInformationItf)->RegisterStreamChangeCallback(mStreamInformationItf, StreamInformationItfCallback, (void*)this); + } + + //playback rate + xaRes = (*mMOPlayer)->GetInterface(mMOPlayer, XA_IID_PLAYBACKRATE, &mPlaybackRateItf); + if(mapError(xaRes, ETrue)==KErrNone) + mbPlaybackRateItfAvailable = ETrue; + + + //videopostprocessing + xaRes = (*mMOPlayer)->GetInterface(mMOPlayer, XA_IID_VIDEOPOSTPROCESSING, &mVideoPostProcessingItf); + if(mapError(xaRes, ETrue)==KErrNone) + mbScalable = ETrue; + + } + + if(mbMetadataAvailable) { + keyMap.clear(); + extendedKeyMap.clear(); + setupMetaData(); //done every time source is changed + } + else { //send signal for seekable + mParent.cbSeekableChanged(ETrue); + } + + mCurPosition = 0; + mParent.cbPositionChanged(mCurPosition); + + xaRes = (*mPlayItf)->GetDuration(mPlayItf, &dur); + retVal = mapError(xaRes, ETrue); + RET_ERR_IF_ERR(retVal); + + mDuration = dur; + mParent.cbDurationChanged(mDuration); + + return retVal; +} + +void XAPlaySessionImpl::unload() +{ + mPlayItf = NULL; + mSeekItf = NULL; + + //Metadata + mbMetadataAvailable = FALSE; + mMetadataExtItf = NULL; + alKeyMap.clear(); + keyMap.clear(); + extendedKeyMap.clear(); + //Volume + mNokiaLinearVolumeItf = NULL; + mbVolEnabled = FALSE; + mNokiaVolumeExtItf = NULL; + mbMuteEnabled = NULL; + + //buffer status + mPrefetchStatusItf = NULL; + mbPrefetchStatusChange = FALSE; + + //stream information + mStreamInformationItf = NULL; + mbStreamInfoAvailable = FALSE; + mbAudioStream = FALSE; + mbVideoStream = FALSE; + mNumStreams = 0; + + //Playbackrate + mPlaybackRateItf = NULL; + mbPlaybackRateItfAvailable = FALSE; + + mVideoPostProcessingItf = NULL; + mbScalable = FALSE; + mCurrAspectRatioMode = Qt::KeepAspectRatio; + + //internal + mCurPosition = 0; // in milliseconds + mDuration = 0; // in milliseconds + + + mbMediaPlayerUnrealized = TRUE; + + delete mURIName; + mURIName = NULL; + +} + +TInt XAPlaySessionImpl::play() +{ + TInt retVal(KErrGeneral); + XAresult xaRes; + XAuint32 state; + +#ifdef USE_VIDEOPLAYERUTILITY + mVideoPlayUtil->Play(); + return 0; +#endif + + if (!mMOPlayer || !mPlayItf) + return retVal; + + xaRes = (*mPlayItf)->GetPlayState(mPlayItf, &state); + retVal = mapError(xaRes, ETrue); + RET_ERR_IF_ERR(retVal); + + if ((state == XA_PLAYSTATE_STOPPED) || + (state == XA_PLAYSTATE_PAUSED)) { + xaRes = (*mPlayItf)->SetPlayState(mPlayItf, XA_PLAYSTATE_PLAYING); + retVal = mapError(xaRes, ETrue); + RET_ERR_IF_ERR(retVal); + } + return retVal; +} + +TInt XAPlaySessionImpl::pause() +{ + TInt retVal(KErrGeneral); + XAresult xaRes; + XAuint32 state; + +#ifdef USE_VIDEOPLAYERUTILITY + TRAPD(err, mVideoPlayUtil->PauseL()); + return 0; +#endif + + if (!mMOPlayer || !mPlayItf) + return retVal; + + xaRes = (*mPlayItf)->GetPlayState(mPlayItf, &state); + retVal = mapError(xaRes, ETrue); + RET_ERR_IF_ERR(retVal); + + if ((state == XA_PLAYSTATE_STOPPED) || + (state == XA_PLAYSTATE_PLAYING)) { + xaRes = (*mPlayItf)->SetPlayState(mPlayItf, XA_PLAYSTATE_PAUSED); + retVal = mapError(xaRes, ETrue); + RET_ERR_IF_ERR(retVal); + } + + return retVal; +} + +TInt XAPlaySessionImpl::stop() +{ + TInt retVal(KErrGeneral); + XAresult xaRes; + XAuint32 state; + +#ifdef USE_VIDEOPLAYERUTILITY + mVideoPlayUtil->Stop(); + return 0; +#endif + + if (!mMOPlayer || !mPlayItf) + return retVal; + + xaRes = (*mPlayItf)->GetPlayState(mPlayItf, &state); + retVal = mapError(xaRes, ETrue); + RET_ERR_IF_ERR(retVal); + + if ((state == XA_PLAYSTATE_PAUSED) || + (state == XA_PLAYSTATE_PLAYING)) { + xaRes = (*mPlayItf)->SetPlayState(mPlayItf, XA_PLAYSTATE_STOPPED); + retVal = mapError(xaRes, ETrue); + RET_ERR_IF_ERR(retVal); + mCurPosition += KPlayPosUpdatePeriod; + mParent.cbPositionChanged(mCurPosition); + } + + return retVal; +} + +TInt XAPlaySessionImpl::duration(TInt64& aDur) +{ + TInt retVal(KErrGeneral); + +#ifdef USE_VIDEOPLAYERUTILITY + TTimeIntervalMicroSeconds dur(0); + TRAPD(err, mVideoPlayUtil->DurationL()); + if (!err) + aDur = dur.Int64() / 1000; + return 0; +#endif + if (!mMOPlayer || !mPlayItf) + return retVal; + aDur = mDuration; + return retVal; +} + +TInt XAPlaySessionImpl::position(TInt64& aPos) +{ + TInt retVal(KErrGeneral); +#ifdef USE_VIDEOPLAYERUTILITY + TTimeIntervalMicroSeconds dur(0); + TRAPD(err, mVideoPlayUtil->PositionL()); + if (!err) + aPos = dur.Int64() / 1000; + return 0; +#endif + +/* XAresult xaRes; + XAmillisecond pos(0);*/ + + if (!mMOPlayer || !mPlayItf) + return retVal; + + aPos = mCurPosition; + return retVal; +} + +TInt XAPlaySessionImpl::getSeekable(TBool& seekable) +{ + TInt retVal(KErrGeneral); + + if (!mMOPlayer || !mSeekItf) + return retVal; + + retVal = ETrue; + seekable = ETrue; + + return retVal; +} + +TInt XAPlaySessionImpl::seek(TInt64 pos) +{ + TInt retVal(KErrGeneral); + XAresult xaRes; + + if (!mMOPlayer || !mSeekItf) + return retVal; + + xaRes = (*mSeekItf)->SetPosition(mSeekItf, (XAmillisecond)pos, XA_SEEKMODE_FAST); + retVal = mapError(xaRes, ETrue); + RET_ERR_IF_ERR(retVal); + mCurPosition = pos; + + return retVal; +} + +void XAPlaySessionImpl::cbMediaPlayer(XAObjectItf /*caller*/, + const void */*pContext*/, + XAuint32 event, + XAresult result, + XAuint32 /*param*/, + void */*pInterface*/) + +{ + switch (event) { + case XA_OBJECT_EVENT_RESOURCES_LOST: + unload(); + mParent.cbPlaybackStopped(result); + break; + case XA_OBJECT_EVENT_RUNTIME_ERROR: + { + switch (result) { + case XA_RESULT_RESOURCE_LOST: + unload(); + mParent.cbPlaybackStopped(result); + break; + default: + break; + }; /* of switch (result) */ + } + default: + break; + } /* of switch (event) */ +} + +void XAPlaySessionImpl::cbPlayItf(XAPlayItf /*caller*/, + void */*pContext*/, + XAuint32 event) +{ + switch(event) { + case XA_PLAYEVENT_HEADATEND: + mParent.cbPlaybackStopped(KErrNone); + break; + case XA_PLAYEVENT_HEADATMARKER: + break; + case XA_PLAYEVENT_HEADATNEWPOS: + mCurPosition += KPlayPosUpdatePeriod; + mParent.cbPositionChanged(mCurPosition); + break; + case XA_PLAYEVENT_HEADMOVING: + break; + case XA_PLAYEVENT_HEADSTALLED: + break; + default: + break; + } +} + +void XAPlaySessionImpl::cbPrefetchItf(XAuint32 event) +{ + if(event == XA_PREFETCHEVENT_FILLLEVELCHANGE) + mParent.cbPrefetchStatusChanged(); +} + +void XAPlaySessionImpl::cbStreamInformationItf( XAuint32 /*eventId*/, + XAuint32 /*streamIndex*/, + void * /*pEventData*/) +{ + mParent.cbStreamInformation(EFalse); +} + +void XAPlaySessionImpl::setAspectRatioMode(Qt::AspectRatioMode aspectRatioMode) +{ + if( !mbScalable || + (mCurrAspectRatioMode == aspectRatioMode)) { + return; + } + + XAuint32 scaleOptions;; + XAuint32 backgrndColor = 1; + XAuint32 renderingHints = 1; + + switch(aspectRatioMode) { + case Qt::IgnoreAspectRatio: + scaleOptions = XA_VIDEOSCALE_STRETCH; + break; + case Qt::KeepAspectRatio: + scaleOptions = XA_VIDEOSCALE_FIT; + break; + case Qt::KeepAspectRatioByExpanding: + scaleOptions = XA_VIDEOSCALE_CROP; + break; + default: + return; + } + + XAresult xaRes = (*mVideoPostProcessingItf)->SetScaleOptions(mVideoPostProcessingItf, \ + scaleOptions, backgrndColor, renderingHints); + if(mapError(xaRes, ETrue) == KErrNone) + xaRes = (*mVideoPostProcessingItf)->Commit(mVideoPostProcessingItf); + + if(mapError(xaRes, ETrue) == KErrNone) + mCurrAspectRatioMode = aspectRatioMode; +} + +Qt::AspectRatioMode XAPlaySessionImpl::getAspectRatioMode() +{ + return mCurrAspectRatioMode; +} + + +#ifdef USE_VIDEOPLAYERUTILITY +void XAPlaySessionImpl::MvpuoOpenComplete(TInt aError) +{ + TRACE_FUNCTION_ENTRY; + m_VPError = aError; + if (mActiveSchedulerWait->IsStarted()) + mActiveSchedulerWait->AsyncStop(); + TRACE_FUNCTION_EXIT; +} + +void XAPlaySessionImpl::MvpuoPrepareComplete(TInt aError) +{ + TRACE_FUNCTION_ENTRY; + m_VPError = aError; + if (mActiveSchedulerWait->IsStarted()) + mActiveSchedulerWait->AsyncStop(); + + RWindow* window = (RWindow*)mNativeDisplay.hWindow; + RWsSession* wssession = (RWsSession*)mNativeDisplay.hDisplay; + + if (window) { + TRect videoExtent = TRect(window->Size()); + TRect clipRect = TRect(window->Size()); + TRAP_IGNORE(mVideoPlayUtil->AddDisplayWindowL(*wssession, *(CCoeEnv::Static()->ScreenDevice()), *window, videoExtent, clipRect)); + TRAP_IGNORE(mVideoPlayUtil->SetAutoScaleL(*window, EAutoScaleBestFit)); + } + TRACE_FUNCTION_EXIT; +} + +void XAPlaySessionImpl::MvpuoFrameReady(CFbsBitmap& /*aFrame*/,TInt /*aError*/) +{ + TRACE_FUNCTION_ENTRY_EXIT; +} + +void XAPlaySessionImpl::MvpuoPlayComplete(TInt /*aError*/) +{ + TRACE_FUNCTION_ENTRY; + mParent.cbPlaybackStopped_EOS(); + TRACE_FUNCTION_EXIT; +} + +void XAPlaySessionImpl::MvpuoEvent(const TMMFEvent& /*aEvent*/) +{ + TRACE_FUNCTION_ENTRY_EXIT; +} + +#endif + +TInt XAPlaySessionImpl::mapError(XAresult xa_err, TBool /*debPrn*/) +{ + TInt retVal(KErrGeneral); + + switch(xa_err) { + case XA_RESULT_SUCCESS: + retVal = KErrNone; + break; + case XA_RESULT_PRECONDITIONS_VIOLATED: + break; + case XA_RESULT_PARAMETER_INVALID: + break; + case XA_RESULT_MEMORY_FAILURE: + break; + case XA_RESULT_RESOURCE_ERROR: + break; + case XA_RESULT_RESOURCE_LOST: + break; + case XA_RESULT_IO_ERROR: + break; + case XA_RESULT_BUFFER_INSUFFICIENT: + break; + case XA_RESULT_CONTENT_CORRUPTED: + break; + case XA_RESULT_CONTENT_UNSUPPORTED: + break; + case XA_RESULT_CONTENT_NOT_FOUND: + break; + case XA_RESULT_PERMISSION_DENIED: + break; + case XA_RESULT_FEATURE_UNSUPPORTED: + break; + case XA_RESULT_INTERNAL_ERROR: + break; + case XA_RESULT_UNKNOWN_ERROR: + break; + case XA_RESULT_OPERATION_ABORTED: + break; + case XA_RESULT_CONTROL_LOST: + break; + default: + break; + } + + return retVal; +} + + +QStringList XAPlaySessionImpl::availableExtendedMetaData () const +{ + QStringList retList; + + //create a qlist with all keys in keyMap hash + QHashIterator<QString, int> it(extendedKeyMap); + while(it.hasNext()) { + it.next(); + retList << it.key(); + } + + return retList; +} + +QList<QtMultimediaKit::MetaData> XAPlaySessionImpl::availableMetaData () const +{ + QList<QtMultimediaKit::MetaData> retList; + + //create a qlist with all keys in keyMap hash + QHashIterator<QtMultimediaKit::MetaData, int> it(keyMap); + while( it.hasNext() ) { + it.next(); + retList << it.key(); + } + + return retList; +} + +QVariant XAPlaySessionImpl::getMetaData( int alIndex ) const +{ + QVariant ret; //invalid variant + + //find index for the given key + if(mMetadataExtItf) { + XAuint32 valueSize = 0; + XAresult res = (*mMetadataExtItf)->GetValueSize(mMetadataExtItf, alIndex, &valueSize); + if(res == XA_RESULT_SUCCESS) { + XAMetadataInfo * value = (XAMetadataInfo*)calloc(valueSize, 1); + if(value) { + res = (*mMetadataExtItf)->GetValue(mMetadataExtItf, alIndex, valueSize, value); + if(res == XA_RESULT_SUCCESS) { + if(value->encoding == XA_CHARACTERENCODING_ASCII) + ret = QVariant ((const char*)value->data); + else if(value->encoding == XA_CHARACTERENCODING_UTF16LE) + ret = QVariant(QString::fromUtf16((ushort*)value->data, (value->size/2)-1)); //dont include null terminating character + else if(value->encoding == XA_CHARACTERENCODING_BINARY) + ret = QVariant(QImage::fromData(value->data, value->size)); + } + + free(value); + } + } + } + + return ret; +} + +QVariant XAPlaySessionImpl::metaData( QtMultimediaKit::MetaData key ) const +{ + QVariant ret; + if(keyMap.contains(key)) + ret = getMetaData(keyMap[key]); + return ret; +} + +QVariant XAPlaySessionImpl::extendedMetaData(const QString & key ) const +{ + QVariant ret; + if(extendedKeyMap.contains(key)) + ret = getMetaData(extendedKeyMap[key]); + + return ret; +} + +bool XAPlaySessionImpl::isMetaDataAvailable() const +{ + return ((keyMap.size()>0) || (extendedKeyMap.size()>0)); +} + +bool XAPlaySessionImpl::isWritable() const +{ + return false; +} + +void XAPlaySessionImpl::setExtendedMetaData( const QString&, const QVariant&) +{ + //Do Nothing +} + +void XAPlaySessionImpl::setMetaData( QtMultimediaKit::MetaData, const QVariant& ) +{ + //Do Nothing +} + +void XAPlaySessionImpl::setupALKeyMap() +{ + alKeyMap["KhronosTitle"] = QtMultimediaKit::Title; + alKeyMap["KhronosComment"] = QtMultimediaKit::Comment; + alKeyMap["KhronosTrackNumber"] = QtMultimediaKit::TrackNumber; + alKeyMap["KhronosAlbumArtJPEG"] = QtMultimediaKit::CoverArtImage; + alKeyMap["KhronosAlbumArtPNG"] = QtMultimediaKit::CoverArtImage; + alKeyMap["KhronosAlbum"] = QtMultimediaKit::AlbumTitle; + alKeyMap["KhronosArtist"] = QtMultimediaKit::AlbumArtist; + alKeyMap["KhronosGenre"] = QtMultimediaKit::Genre; + alKeyMap["KhronosYear"] = QtMultimediaKit::Year; + alKeyMap["KhronosYear"] = QtMultimediaKit::Date; + alKeyMap["KhronosRating"] = QtMultimediaKit::UserRating; + alKeyMap["KhronosCopyright"] = QtMultimediaKit::Copyright; + alKeyMap["Author"] = QtMultimediaKit::Author; + alKeyMap["Duration"] = QtMultimediaKit::Duration; + alKeyMap["Stream Count"] = QtMultimediaKit::ChannelCount; + alKeyMap["Composer"] = QtMultimediaKit::Composer; + alKeyMap["Resolution"] = QtMultimediaKit::Resolution; + alKeyMap["FrameRate"] = QtMultimediaKit::VideoFrameRate; + alKeyMap["ClipBitRate"] = QtMultimediaKit::VideoBitRate; + alKeyMap["Codec"] = QtMultimediaKit::VideoCodec; + alKeyMap["attachedpicture"] = QtMultimediaKit::CoverArtImage; + + /*Keys not available + QtMedia::SubTitle + QtMedia::Description + QtMedia::Category + QtMedia::Keywords + QtMedia::Language + QtMedia::Publisher + QtMedia::ParentalRating + QtMedia::RatingOrganisation + QtMedia::Size + QtMedia::MediaType + QtMedia::AudioBitrate + QtMedia::AudioCodec + QtMedia::AverageLevel + QtMedia::PeakValue + QtMedia::Frequency + QtMedia::ContributingArtist + QtMedia::Conductor + QtMedia::Lyrics + QtMedia::Mood + QtMedia::TrackCount + QtMedia::PixelAspectRatio + QtMedia::PosterUri + QtMedia::ChapterNumber + QtMedia::Director + QtMedia::LeadPerformer + QtMedia::Writer */ +} + +TInt XAPlaySessionImpl::mapMetaDataKey(const char* asckey, QtMultimediaKit::MetaData& key) +{ + if(alKeyMap.contains(asckey)) { + key = alKeyMap[asckey]; + return KErrNone; + } + + return KErrNotFound; +} + +TInt XAPlaySessionImpl::setupMetaData() +{ + XAresult res; + if(mMetadataExtItf) { + XAuint32 numItems = 0; + res = (*mMetadataExtItf)->GetItemCount(mMetadataExtItf, &numItems); + RET_ERR_IF_ERR(mapError(res, ETrue)); + + for(int i=0; i<numItems; ++i) { + XAuint32 keySize; + res = (*mMetadataExtItf)->GetKeySize(mMetadataExtItf, i, &keySize); + RET_ERR_IF_ERR(mapError(res, ETrue)); + + XAMetadataInfo *key = (XAMetadataInfo *)calloc(keySize,1); + if(key) { + res = (*mMetadataExtItf)->GetKey(mMetadataExtItf, i, keySize, key); + RET_ERR_IF_ERR(mapError(res, ETrue)); + + if(key->encoding == XA_CHARACTERENCODING_ASCII) { //only handle ASCII keys ignore others + QtMultimediaKit::MetaData qtKey; + if(mapMetaDataKey((const char*)key->data, qtKey) == KErrNone)//qt metadata + keyMap[qtKey] = i; + else //extended metadata + extendedKeyMap[(const char*)key->data] = i; + } + + free(key); + } + } + + //check for seek property to generate seekable signal + QVariant var = extendedMetaData("Seekable"); + if(!var.isValid() || (var.toString() == "1")) + mParent.cbSeekableChanged(ETrue); + else + mParent.cbSeekableChanged(EFalse); + + } + + return KErrGeneral; +} + +//Volume +TInt XAPlaySessionImpl::volume(TInt& v) +{ + if(mbVolEnabled) { + XAresult res = (*mNokiaLinearVolumeItf)->GetVolumeLevel(mNokiaLinearVolumeItf, (XAuint32 *)&v); + return mapError(res, ETrue); + } + + return KErrNotFound; +} + +TInt XAPlaySessionImpl::setVolume(TInt v) +{ + if(mbVolEnabled) { + XAresult res = (*mNokiaLinearVolumeItf)->SetVolumeLevel(mNokiaLinearVolumeItf, (XAuint32*)&v); + return mapError(res, ETrue); + } + + return KErrNotFound; +} + +TInt XAPlaySessionImpl::setMute(TBool bMute) +{ + if(mbMuteEnabled) { + XAresult res = (*mNokiaVolumeExtItf)->SetMute(mNokiaVolumeExtItf, (XAboolean)bMute); + return mapError(res, ETrue); + } + + return KErrNotFound; + +} + +TInt XAPlaySessionImpl::getMute(TBool& bIsMute) +{ + if(mbMuteEnabled) { + XAboolean xaMute; + XAresult res = (*mNokiaVolumeExtItf)->GetMute(mNokiaVolumeExtItf, &xaMute); + bIsMute = xaMute; + return mapError(res, ETrue); + } + + return KErrNotFound; +} + + +TInt XAPlaySessionImpl::bufferStatus(TInt &bs) +{ + TInt ret = KErrNotFound; + + if(mbPrefetchStatusChange) { + XApermille satusPerThousand; + XAresult res = (*mPrefetchStatusItf)->GetFillLevel(mPrefetchStatusItf, &satusPerThousand); + ret = mapError(res, ETrue); + if(ret == KErrNone) + bs = satusPerThousand/10.0; //convert to parts per hundred + } + return ret; +} + +QMediaStreamsControl::StreamType XAPlaySessionImpl::mapStreamType(XAuint32& alStreamType) +{ + switch(alStreamType) { + case XA_DOMAINTYPE_AUDIO: + return QMediaStreamsControl::AudioStream; + case XA_DOMAINTYPE_VIDEO: + return QMediaStreamsControl::VideoStream; + case XA_DOMAINTYPE_IMAGE: + return QMediaStreamsControl::DataStream; + } + return QMediaStreamsControl::UnknownStream; +} + + +TInt XAPlaySessionImpl::numMediaStreams(TUint& numStreams) +{ + TInt ret = KErrNotFound; + numStreams = 0; + if(mbStreamInfoAvailable) { + XAMediaContainerInformation mediaContainerInfo; + XAresult res = (*mStreamInformationItf)->QueryMediaContainerInformation(mStreamInformationItf, &mediaContainerInfo); + ret = mapError(res, ETrue); + if(ret == KErrNone) + numStreams = mediaContainerInfo.numStreams; + } + return ret; +} + +TInt XAPlaySessionImpl::streamType(TUint index, QMediaStreamsControl::StreamType& type) +{ + TInt ret = KErrNotFound; + type = QMediaStreamsControl::UnknownStream; + if(mbStreamInfoAvailable) { + XAuint32 strType; + XAresult res = (*mStreamInformationItf)->QueryStreamType(mStreamInformationItf, (XAuint32)(index+1), &strType); + ret = mapError(res, ETrue); + if(ret == KErrNone) + type = mapStreamType(strType); + } + return ret; +} + +TInt XAPlaySessionImpl::isStreamActive(TUint index, TBool& isActive) +{ + TUint numStreams; + TInt ret = numMediaStreams(numStreams); + if((ret == KErrNone) && (index < numStreams)) { + isActive = EFalse; + if(numStreams > 0) { + //create array of bools + XAboolean *activeStreams = new XAboolean[numStreams+1]; + XAresult res = (*mStreamInformationItf)->QueryActiveStreams(mStreamInformationItf, (XAuint32*)&numStreams, activeStreams); + ret = mapError(res, ETrue); + if(ret == KErrNone) + isActive = activeStreams[index+1]; + delete[] activeStreams; + } + } + return ret; +} + +TInt XAPlaySessionImpl::getPlaybackRate(TReal32 &rate) +{ + TInt ret = KErrNotFound; + + if(mbPlaybackRateItfAvailable) { + XApermille perMilleRate = 0; + ret = (*mPlaybackRateItf)->GetRate(mPlaybackRateItf, &perMilleRate); + rate = perMilleRate / 1000.0; + } + return ret; +} + +TInt XAPlaySessionImpl::setPlaybackRate(TReal32 rate) +{ + TInt ret = KErrNotFound; + if(mbPlaybackRateItfAvailable) + ret = (*mPlaybackRateItf)->SetRate(mPlaybackRateItf, (XApermille)(rate * 1000.0)); + return ret; +} + + +/* Local function implementation */ +void MediaPlayerCallback( XAObjectItf caller, + const void *pContext, + XAuint32 event, + XAresult result, + XAuint32 param, + void *pInterface) +{ + if (pContext) + ((XAPlaySessionImpl*)pContext)->cbMediaPlayer( caller, + pContext, + event, + result, + param, + pInterface); +} + +void PlayItfCallback( XAPlayItf caller, + void *pContext, + XAuint32 event) +{ + if (pContext) + ((XAPlaySessionImpl*)pContext)->cbPlayItf(caller, + pContext, + event); +} + +void PrefetchItfCallback( XAPrefetchStatusItf /*caller*/, + void *pContext, + XAuint32 event) +{ + if (pContext) + ((XAPlaySessionImpl*)pContext)->cbPrefetchItf(event); +} + +void StreamInformationItfCallback( XAStreamInformationItf /*caller*/, + XAuint32 eventId, + XAuint32 streamIndex, + void * pEventData, + void * pContext) +{ + if (pContext) + ((XAPlaySessionImpl*)pContext)->cbStreamInformationItf( eventId, + streamIndex, + pEventData); +} + + + +// End of file diff --git a/src/plugins/symbian/openmaxal/mediaplayer/xaplaysessionimpl.h b/src/plugins/symbian/openmaxal/mediaplayer/xaplaysessionimpl.h new file mode 100644 index 000000000..30144712a --- /dev/null +++ b/src/plugins/symbian/openmaxal/mediaplayer/xaplaysessionimpl.h @@ -0,0 +1,210 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** +****************************************************************************/ + +#ifndef XAPLAYSESSIONIMPL_H +#define XAPLAYSESSIONIMPL_H + +#include <OpenMAXAL.h> +#include <xanokiavolumeextitf.h> +#include <xanokialinearvolumeitf.h> +#ifdef USE_VIDEOPLAYERUTILITY +#include <VideoPlayer2.h> +#endif + +#include "qtmedianamespace.h" +#include "qmediastreamscontrol.h" + +class XAPlayObserver; +class RWindow; +class RWsSession; + +class XAPlaySessionImpl +#ifdef USE_VIDEOPLAYERUTILITY + : public MVideoPlayerUtilityObserver +#endif +{ +public: + XAPlaySessionImpl(XAPlayObserver& parent); + ~XAPlaySessionImpl(); + TInt postConstruct(); + TInt addNativeDisplay(RWindow* window, RWsSession* wssession); + TInt updateNativeDisplay(RWindow* window, RWsSession* wssession); + TInt removeNativeDisplay(RWindow* window, RWsSession* wssession); + TInt load(const TDesC& aURI); + void unload(); + TInt play(); + TInt pause(); + TInt stop(); + TInt duration(TInt64& aDur); + TInt position(TInt64& aPos); + TInt getSeekable(TBool& seekable); + TInt seek(TInt64 pos); + + //Metadata + QStringList availableExtendedMetaData () const; + QList<QtMultimediaKit::MetaData> availableMetaData () const; + QVariant extendedMetaData(const QString & key ) const; + bool isMetaDataAvailable() const; + bool isWritable() const; + QVariant metaData( QtMultimediaKit::MetaData key ) const; + void setExtendedMetaData( const QString & key, const QVariant & value ); + void setMetaData( QtMultimediaKit::MetaData key, const QVariant & value ); + + TInt volume(TInt&); + TInt setVolume(TInt); + TInt setMute(TBool); + TInt getMute(TBool&); + + TInt bufferStatus(TInt &); + + + TInt numMediaStreams(TUint& numStreams); + TInt streamType(TUint index, QMediaStreamsControl::StreamType& type); + TInt isStreamActive(TUint index, TBool& isActive); + + TInt getPlaybackRate(TReal32 &rate); + TInt setPlaybackRate(TReal32 rate); + + //AspectRatioMode + void setAspectRatioMode(Qt::AspectRatioMode); + Qt::AspectRatioMode getAspectRatioMode(); + +public: + void cbMediaPlayer( XAObjectItf caller, + const void *pContext, + XAuint32 event, + XAresult result, + XAuint32 param, + void *pInterface); + + void cbPlayItf(XAPlayItf caller, + void *pContext, + XAuint32 event); + + + void cbPrefetchItf(XAuint32); + + void cbStreamInformationItf(XAuint32, XAuint32, void*); + +#ifdef USE_VIDEOPLAYERUTILITY + //MVideoPlayerUtilityObserver + void MvpuoOpenComplete(TInt aError); + void MvpuoPrepareComplete(TInt aError); + void MvpuoFrameReady(CFbsBitmap& aFrame,TInt aError); + void MvpuoPlayComplete(TInt aError); + void MvpuoEvent(const TMMFEvent& aEvent); +#endif + +private: + TInt mapError(XAresult xa_err, + TBool debPrn); + void setupALKeyMap(); + TInt setupMetaData(); + TInt mapMetaDataKey(const char* asckey, QtMultimediaKit::MetaData& key); + QVariant getMetaData( int alIndex ) const; + + QMediaStreamsControl::StreamType mapStreamType(XAuint32& alStreamType); + + +private: + XAPlayObserver& mParent; + XAObjectItf mEOEngine; + XAObjectItf mMOPlayer; + XAPlayItf mPlayItf; + XASeekItf mSeekItf; + HBufC8* mURIName; + HBufC8* mWAVMime; + // Audio Source + XADataSource mDataSource; + XADataFormat_MIME mMime; + XADataLocator_URI mUri; + //Audio Sink + XADataSink mAudioSink; + XADataLocator_IODevice mLocatorOutputDevice; + //Video Sink + XADataSink mVideoSink; + XADataLocator_NativeDisplay mNativeDisplay; + + //Metadata + TBool mbMetadataAvailable; + XAMetadataExtractionItf mMetadataExtItf; + QHash<QString, QtMultimediaKit::MetaData> alKeyMap; + QHash<QtMultimediaKit::MetaData, int> keyMap; + QHash<QString,int> extendedKeyMap; + + //Volume + XANokiaLinearVolumeItf mNokiaLinearVolumeItf; + TBool mbVolEnabled; + XANokiaVolumeExtItf mNokiaVolumeExtItf; + TBool mbMuteEnabled; + + //buffer status + XAPrefetchStatusItf mPrefetchStatusItf; + TBool mbPrefetchStatusChange; + + //stream information + XAStreamInformationItf mStreamInformationItf; + TBool mbStreamInfoAvailable; + TBool mbAudioStream; + TBool mbVideoStream; + TInt mNumStreams; + + //Playbackrate + XAPlaybackRateItf mPlaybackRateItf; + TBool mbPlaybackRateItfAvailable; + + XAVideoPostProcessingItf mVideoPostProcessingItf; + TBool mbScalable; + Qt::AspectRatioMode mCurrAspectRatioMode; + + //internal + TInt64 mCurPosition; // in milliseconds + TInt64 mDuration; // in milliseconds + + TBool mbMediaPlayerUnrealized; +#ifdef USE_VIDEOPLAYERUTILITY + CVideoPlayerUtility2* mVideoPlayUtil; + CActiveSchedulerWait* mActiveSchedulerWait; + TInt m_VPError; +#endif +}; + +#endif /* XAPLAYSESSIONIMPL_H */ diff --git a/src/plugins/symbian/openmaxal/mediarecorder/mediarecorder.pri b/src/plugins/symbian/openmaxal/mediarecorder/mediarecorder.pri new file mode 100644 index 000000000..ee78e8348 --- /dev/null +++ b/src/plugins/symbian/openmaxal/mediarecorder/mediarecorder.pri @@ -0,0 +1,24 @@ +INCLUDEPATH += $$PWD + +# Input +HEADERS += \ + $$PWD/qxarecordmediaservice.h \ + $$PWD/qxarecordsession.h \ + $$PWD/qxaaudioendpointselector.h \ + $$PWD/qxaaudioencodercontrol.h \ + $$PWD/qxamediacontainercontrol.h \ + $$PWD/qxamediarecordercontrol.h \ + $$PWD/xarecordsessionimpl.h \ + $$PWD/xarecordsessioncommon.h + +SOURCES += \ + $$PWD/qxarecordmediaservice.cpp \ + $$PWD/qxarecordsession.cpp \ + $$PWD/qxaaudioendpointselector.cpp \ + $$PWD/qxaaudioencodercontrol.cpp \ + $$PWD/qxamediacontainercontrol.cpp \ + $$PWD/qxamediarecordercontrol.cpp \ + $$PWD/xarecordsessionimpl.cpp + +LIBS += \ + -lbafl diff --git a/src/plugins/symbian/openmaxal/mediarecorder/qxaaudioencodercontrol.cpp b/src/plugins/symbian/openmaxal/mediarecorder/qxaaudioencodercontrol.cpp new file mode 100644 index 000000000..2826f79a2 --- /dev/null +++ b/src/plugins/symbian/openmaxal/mediarecorder/qxaaudioencodercontrol.cpp @@ -0,0 +1,111 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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 "qxaaudioencodercontrol.h" +#include "qxarecordsession.h" +#include "qxacommon.h" + +QXAAudioEncoderControl::QXAAudioEncoderControl(QXARecordSession *session, QObject *parent) +:QAudioEncoderControl(parent), m_session(session) +{ +} + +QXAAudioEncoderControl::~QXAAudioEncoderControl() +{ + QT_TRACE_FUNCTION_ENTRY_EXIT; +} + +QStringList QXAAudioEncoderControl::supportedAudioCodecs() const +{ + if (m_session) + return m_session->supportedAudioCodecs(); + return QStringList(); +} + +QString QXAAudioEncoderControl::codecDescription(const QString &codecName) const +{ + if (m_session) + return m_session->codecDescription(codecName); + return QString(); +} + +QList<int> QXAAudioEncoderControl::supportedSampleRates( + const QAudioEncoderSettings &settings, + bool *continuous) const +{ + if (m_session) + return m_session->supportedSampleRates(settings, continuous); + return QList<int>(); +} + +QAudioEncoderSettings QXAAudioEncoderControl::audioSettings() const +{ + if (m_session) + return m_session->audioSettings(); + return QAudioEncoderSettings(); +} + +void QXAAudioEncoderControl::setAudioSettings(const QAudioEncoderSettings &settings) +{ + if (m_session) + m_session->setAudioSettings(settings); +} + +QStringList QXAAudioEncoderControl::supportedEncodingOptions(const QString &codec) const +{ + if (m_session) + return m_session->supportedEncodingOptions(codec); + return QStringList(); +} + +QVariant QXAAudioEncoderControl::encodingOption(const QString &codec, const QString &name) const +{ + if (m_session) + return m_session->encodingOption(codec, name); + return QVariant(); +} + +void QXAAudioEncoderControl::setEncodingOption( + const QString &codec, const QString &name, const QVariant &value) +{ + if (m_session) + m_session->setEncodingOption(codec, name, value); +} diff --git a/src/plugins/symbian/openmaxal/mediarecorder/qxaaudioencodercontrol.h b/src/plugins/symbian/openmaxal/mediarecorder/qxaaudioencodercontrol.h new file mode 100644 index 000000000..117d36fdc --- /dev/null +++ b/src/plugins/symbian/openmaxal/mediarecorder/qxaaudioencodercontrol.h @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** +****************************************************************************/ + +#ifndef QXAAUDIOENCODERCONTROL_H +#define QXAAUDIOENCODERCONTROL_H + +#include <qaudioencodercontrol.h> + +QT_USE_NAMESPACE + +/* + * This class implements QAudioEncoderControl interface. + */ +class QXARecordSession; + +class QXAAudioEncoderControl : public QAudioEncoderControl +{ + Q_OBJECT + +public: + QXAAudioEncoderControl(QXARecordSession *session, QObject *parent = 0); + virtual ~QXAAudioEncoderControl(); + + QStringList supportedAudioCodecs() const; + QString codecDescription(const QString &codecName) const; + + QList<int> supportedSampleRates(const QAudioEncoderSettings &settings, + bool *continuous = 0) const; + + QAudioEncoderSettings audioSettings() const; + void setAudioSettings(const QAudioEncoderSettings &settings); + + QStringList supportedEncodingOptions(const QString &codec) const; + QVariant encodingOption(const QString &codec, const QString &name) const; + void setEncodingOption(const QString &codec, const QString &name, const QVariant &value); + +private: + QXARecordSession *m_session; +}; + +#endif /* QXAAUDIOENCODERCONTROL_H */ diff --git a/src/plugins/symbian/openmaxal/mediarecorder/qxaaudioendpointselector.cpp b/src/plugins/symbian/openmaxal/mediarecorder/qxaaudioendpointselector.cpp new file mode 100644 index 000000000..7e546595c --- /dev/null +++ b/src/plugins/symbian/openmaxal/mediarecorder/qxaaudioendpointselector.cpp @@ -0,0 +1,98 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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 "qxaaudioendpointselector.h" +#include "qxarecordsession.h" +#include "qxacommon.h" + +QXAAudioEndpointSelector::QXAAudioEndpointSelector(QXARecordSession *session, QObject *parent) +:QAudioEndpointSelector(parent), m_session(session) +{ + connect(m_session, SIGNAL(availableAudioInputsChanged()), + this, SLOT(availableAudioInputsChanged())); + connect(m_session, SIGNAL(activeEndpointChanged(QString)), + this, SIGNAL(activeEndpointChanged(QString))); +} + +QXAAudioEndpointSelector::~QXAAudioEndpointSelector() +{ + QT_TRACE_FUNCTION_ENTRY_EXIT; +} + +QList<QString> QXAAudioEndpointSelector::availableEndpoints() const +{ + if (m_session) + return m_session->availableEndpoints(); + return QList<QString>(); +} + +QString QXAAudioEndpointSelector::endpointDescription(const QString &name) const +{ + if (m_session) + return m_session->endpointDescription(name); + return QString(); +} + +QString QXAAudioEndpointSelector::defaultEndpoint() const +{ + if (m_session) + return m_session->defaultEndpoint(); + return QString(); +} + +QString QXAAudioEndpointSelector::activeEndpoint() const +{ + if (m_session) + return m_session->activeEndpoint(); + return QString(); +} + +void QXAAudioEndpointSelector::setActiveEndpoint(const QString &name) +{ + if (m_session) + m_session->setActiveEndpoint(name); +} + +void QXAAudioEndpointSelector::availableAudioInputsChanged() + { + emit availableEndpointsChanged(); + } + diff --git a/src/plugins/symbian/openmaxal/mediarecorder/qxaaudioendpointselector.h b/src/plugins/symbian/openmaxal/mediarecorder/qxaaudioendpointselector.h new file mode 100644 index 000000000..5fbadbc64 --- /dev/null +++ b/src/plugins/symbian/openmaxal/mediarecorder/qxaaudioendpointselector.h @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** +****************************************************************************/ + +#ifndef QXAAUDIOENDPOINTSELECTOR_H +#define QXAAUDIOENDPOINTSELECTOR_H + +#include <qaudioendpointselector.h> + +QT_USE_NAMESPACE + +/* + * This class implements QAudioEncoderControl interface. + */ +class QXARecordSession; + +class QXAAudioEndpointSelector : public QAudioEndpointSelector +{ + Q_OBJECT + +public: + QXAAudioEndpointSelector(QXARecordSession *session, QObject *parent); + ~QXAAudioEndpointSelector(); + + QList<QString> availableEndpoints() const; + QString endpointDescription(const QString &name) const; + QString defaultEndpoint() const; + QString activeEndpoint() const; + +public Q_SLOTS: + void setActiveEndpoint(const QString &name); + +private Q_SLOTS: + void availableAudioInputsChanged(); + +private: + QXARecordSession *m_session; +}; + +#endif /* QXAAUDIOENDPOINTSELECTOR_H */ diff --git a/src/plugins/symbian/openmaxal/mediarecorder/qxamediacontainercontrol.cpp b/src/plugins/symbian/openmaxal/mediarecorder/qxamediacontainercontrol.cpp new file mode 100644 index 000000000..0d97fd5e5 --- /dev/null +++ b/src/plugins/symbian/openmaxal/mediarecorder/qxamediacontainercontrol.cpp @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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 "qxamediacontainercontrol.h" +#include "qxarecordsession.h" +#include "qxacommon.h" + +QXAMediaContainerControl::QXAMediaContainerControl(QXARecordSession *session, QObject *parent) +:QMediaContainerControl(parent), m_session(session) +{ +} + +QXAMediaContainerControl::~QXAMediaContainerControl() +{ + QT_TRACE_FUNCTION_ENTRY_EXIT; +} + +QStringList QXAMediaContainerControl::supportedContainers() const +{ + if (m_session) + return m_session->supportedContainers(); + return QStringList(); +} + +QString QXAMediaContainerControl::containerMimeType() const +{ + if (m_session) + return m_session->containerMimeType(); + return QString(); +} + +void QXAMediaContainerControl::setContainerMimeType(const QString &formatMimeType) +{ + if (m_session) + m_session->setContainerMimeType(formatMimeType); +} + +QString QXAMediaContainerControl::containerDescription(const QString &formatMimeType) const +{ + if (m_session) + return m_session->containerDescription(formatMimeType); + return QString(); +} diff --git a/src/plugins/symbian/openmaxal/mediarecorder/qxamediacontainercontrol.h b/src/plugins/symbian/openmaxal/mediarecorder/qxamediacontainercontrol.h new file mode 100644 index 000000000..4b05fc190 --- /dev/null +++ b/src/plugins/symbian/openmaxal/mediarecorder/qxamediacontainercontrol.h @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** +****************************************************************************/ + +#ifndef QXAMEDIACONTAINERCONTROL_H +#define QXAMEDIACONTAINERCONTROL_H + +#include <qmediacontainercontrol.h> + +QT_USE_NAMESPACE + +/* + * This class implements QMediaContainerControl interface. + */ +class QXARecordSession; + +class QXAMediaContainerControl : public QMediaContainerControl +{ + Q_OBJECT + +public: + QXAMediaContainerControl(QXARecordSession *session, QObject *parent = 0); + virtual ~QXAMediaContainerControl(); + + QStringList supportedContainers() const; + QString containerMimeType() const; + void setContainerMimeType(const QString &formatMimeType); + QString containerDescription(const QString &formatMimeType) const; + +private: + QXARecordSession *m_session; +}; + +#endif /* QXAMEDIACONTAINERCONTROL_H */ diff --git a/src/plugins/symbian/openmaxal/mediarecorder/qxamediarecordercontrol.cpp b/src/plugins/symbian/openmaxal/mediarecorder/qxamediarecordercontrol.cpp new file mode 100644 index 000000000..330edf008 --- /dev/null +++ b/src/plugins/symbian/openmaxal/mediarecorder/qxamediarecordercontrol.cpp @@ -0,0 +1,122 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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 "qxamediarecordercontrol.h" +#include "qxarecordsession.h" +#include "qxacommon.h" + +QXAMediaRecoderControl::QXAMediaRecoderControl(QXARecordSession *session, QObject *parent) +:QMediaRecorderControl(parent), m_session(session) +{ + connect(m_session, SIGNAL(stateChanged(QMediaRecorder::State)), + this, SIGNAL(stateChanged(QMediaRecorder::State))); + connect(m_session, SIGNAL(error(int,QString)), + this,SIGNAL(error(int,QString))); + connect(m_session, SIGNAL(durationChanged(qint64)), + this, SIGNAL(durationChanged(qint64))); +} + +QXAMediaRecoderControl::~QXAMediaRecoderControl() +{ + QT_TRACE_FUNCTION_ENTRY_EXIT; +} + +QUrl QXAMediaRecoderControl::outputLocation() const +{ + if (m_session) + return m_session->outputLocation(); + return QUrl(); +} + +bool QXAMediaRecoderControl::setOutputLocation(const QUrl &location) +{ + if (m_session) + return m_session->setOutputLocation(location); + return false; +} + +QMediaRecorder::State QXAMediaRecoderControl::state() const +{ + if (m_session) + return m_session->state(); + return QMediaRecorder::StoppedState; +} + +qint64 QXAMediaRecoderControl::duration() const +{ + if (m_session) + return m_session->duration(); + return 0; +} + +void QXAMediaRecoderControl::record() +{ + if (m_session) + m_session->record(); +} + +void QXAMediaRecoderControl::pause() +{ + if (m_session) + m_session->pause(); +} + +void QXAMediaRecoderControl::stop() +{ + if (m_session) + m_session->stop(); +} + +void QXAMediaRecoderControl::applySettings() +{ + if (m_session) + m_session->applySettings(); +} + +bool QXAMediaRecoderControl::isMuted() const +{ + return false; +} + +void QXAMediaRecoderControl::setMuted(bool) +{ + +} diff --git a/src/plugins/symbian/openmaxal/mediarecorder/qxamediarecordercontrol.h b/src/plugins/symbian/openmaxal/mediarecorder/qxamediarecordercontrol.h new file mode 100644 index 000000000..c6495f2e4 --- /dev/null +++ b/src/plugins/symbian/openmaxal/mediarecorder/qxamediarecordercontrol.h @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** +****************************************************************************/ + +#ifndef QXAMEDIARECORDERCONTROL_H +#define QXAMEDIARECORDERCONTROL_H + +#include <qmediarecorder.h> +#include <qmediarecordercontrol.h> + +QT_USE_NAMESPACE + +/* + * This class implements QMediaRecorderControl interface. + */ + +class QXARecordSession; + +class QXAMediaRecoderControl : public QMediaRecorderControl +{ + Q_OBJECT + +public: + QXAMediaRecoderControl(QXARecordSession *session, QObject *parent = 0); + virtual ~QXAMediaRecoderControl(); + + QUrl outputLocation() const; + bool setOutputLocation(const QUrl &location); + + QMediaRecorder::State state() const; + + qint64 duration() const; + bool isMuted() const; + void applySettings(); + +public Q_SLOTS: + void record(); + void pause(); + void stop(); + void setMuted(bool); + +private: + QXARecordSession *m_session; +}; + +#endif /* QXAMEDIARECORDERCONTROL_H */ diff --git a/src/plugins/symbian/openmaxal/mediarecorder/qxarecordmediaservice.cpp b/src/plugins/symbian/openmaxal/mediarecorder/qxarecordmediaservice.cpp new file mode 100644 index 000000000..05c57feb7 --- /dev/null +++ b/src/plugins/symbian/openmaxal/mediarecorder/qxarecordmediaservice.cpp @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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 <QString> + +#include "qxarecordmediaservice.h" +#include "qxarecordsession.h" +#include "qxamediarecordercontrol.h" +#include "qxaaudioendpointselector.h" +#include "qxaaudioencodercontrol.h" +#include "qxamediacontainercontrol.h" +#include "qxacommon.h" + +QXARecodMediaService::QXARecodMediaService(QObject *parent) +:QMediaService(parent) +{ + QT_TRACE_FUNCTION_ENTRY; + m_session = new QXARecordSession(this); + m_control = new QXAMediaRecoderControl(m_session, this); + m_endpoint = new QXAAudioEndpointSelector(m_session, this); + m_encoder = new QXAAudioEncoderControl(m_session, this); + m_container = new QXAMediaContainerControl(m_session, this); +} + +QXARecodMediaService::~QXARecodMediaService() +{ + QT_TRACE_FUNCTION_ENTRY_EXIT; +} + +QMediaControl* QXARecodMediaService::requestControl(const char *name) +{ + QT_TRACE_FUNCTION_ENTRY; + if (qstrcmp(name, QMediaRecorderControl_iid) == 0) + return m_control; + else if (qstrcmp(name, QAudioEndpointSelector_iid) == 0) + return m_endpoint; + else if (qstrcmp(name, QAudioEncoderControl_iid) == 0) + return m_encoder; + else if (qstrcmp(name, QMediaContainerControl_iid) == 0) + return m_container; + QT_TRACE_FUNCTION_EXIT; + return 0; +} + +void QXARecodMediaService::releaseControl(QMediaControl *control) +{ + Q_UNUSED(control) +} diff --git a/src/plugins/symbian/openmaxal/mediarecorder/qxarecordmediaservice.h b/src/plugins/symbian/openmaxal/mediarecorder/qxarecordmediaservice.h new file mode 100644 index 000000000..98f5136e8 --- /dev/null +++ b/src/plugins/symbian/openmaxal/mediarecorder/qxarecordmediaservice.h @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** +****************************************************************************/ + +#ifndef QXARECORDMEDIASERVICE_H +#define QXARECORDMEDIASERVICE_H + +#include <QtCore/qobject.h> +#include <qmediaservice.h> + +QT_USE_NAMESPACE + +/* + * This class implements QMediaService interface. + */ + +class QXARecordSession; +class QXAMediaRecoderControl; +class QXAAudioEndpointSelector; +class QXAAudioEncoderControl; +class QXAMediaContainerControl; + +class QXARecodMediaService : public QMediaService +{ + + Q_OBJECT + +public: + QXARecodMediaService(QObject *parent = 0); + ~QXARecodMediaService(); + QMediaControl *requestControl(const char *name); + void releaseControl( QMediaControl *control); +private: + QXARecordSession *m_session; + QXAMediaRecoderControl *m_control; + QXAAudioEndpointSelector *m_endpoint; + QXAAudioEncoderControl *m_encoder; + QXAMediaContainerControl *m_container; +}; + +#endif /* QXARECORDMEDIASERVICE_H */ diff --git a/src/plugins/symbian/openmaxal/mediarecorder/qxarecordsession.cpp b/src/plugins/symbian/openmaxal/mediarecorder/qxarecordsession.cpp new file mode 100644 index 000000000..76cdfc3da --- /dev/null +++ b/src/plugins/symbian/openmaxal/mediarecorder/qxarecordsession.cpp @@ -0,0 +1,766 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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 <QVariant> +#include <QtCore/qdir.h> +#include <qtmedianamespace.h> +#include "qxarecordsession.h" +#include "xarecordsessionimpl.h" +#include "qxacommon.h" + +/* The following declaration is required to allow QList<int> to be added to + * QVariant + */ +Q_DECLARE_METATYPE(QList<uint>) + +/* This macro checks for m_impl null pointer. If it is, emits an error signal + * error(QMediaRecorder::ResourceError, tr("Service has not been started")); + * and returns from function immediately with value 's'. + */ + +#define RETURN_s_IF_m_impl_IS_NULL(s) \ + if (!m_impl) { \ + emit error(QMediaRecorder::ResourceError, QXARecordSession::tr("Service has not been started")); \ + SIGNAL_EMIT_TRACE1("emit error(QMediaRecorder::ResourceError, tr(\"Service has not been started\"))"); \ + return s; \ + } + +/* This macro checks for m_impl null pointer. If it is, emits an error signal + * error(QMediaRecorder::ResourceError, tr("Service has not been started")); + * and returns from function immediately. + */ +#define RETURN_IF_m_impl_IS_NULL \ + if (!m_impl) { \ + emit error(QMediaRecorder::ResourceError, QXARecordSession::tr("Service has not been started")); \ + SIGNAL_EMIT_TRACE1("emit error(QMediaRecorder::ResourceError, tr(\"Service has not been started\"))"); \ + return; \ + } + +QXARecordSession::QXARecordSession(QObject *parent) +:QObject(parent), +m_state(QMediaRecorder::StoppedState), +m_previousState(QMediaRecorder::StoppedState) +{ + QT_TRACE_FUNCTION_ENTRY; + m_impl = NULL; + m_impl = new XARecordSessionImpl(*this); + if (m_impl) { + if (m_impl->postConstruct() == KErrNone) { + initCodecsList(); + initContainersList(); + m_containerMimeType = QString("audio/wav"); + m_audioencodersettings.setCodec("pcm"); + m_audioencodersettings.setBitRate(0); + m_audioencodersettings.setChannelCount(-1); + m_audioencodersettings.setEncodingMode(QtMultimediaKit::ConstantQualityEncoding); + m_audioencodersettings.setQuality(QtMultimediaKit::NormalQuality); + m_audioencodersettings.setSampleRate(-1); + setEncoderSettingsToImpl(); + m_URItoImplSet = false; + QT_TRACE1("Initialized implementation"); + } + else { + delete m_impl; + m_impl = NULL; + QT_TRACE1("Error initializing implementation"); + } + } + else { + emit error(QMediaRecorder::ResourceError, tr("Unable to start Service")); + } + QT_TRACE_FUNCTION_EXIT; +} + +QXARecordSession::~QXARecordSession() +{ + QT_TRACE_FUNCTION_ENTRY; + delete m_impl; + QT_TRACE_FUNCTION_EXIT; +} + +QUrl QXARecordSession::outputLocation() +{ + return m_outputLocation; +} + +bool QXARecordSession::setOutputLocation(const QUrl &location) +{ + QT_TRACE_FUNCTION_ENTRY; + + RETURN_s_IF_m_impl_IS_NULL(false); + + // Location can be set only when recorder is in stopped state. + if (state() != QMediaRecorder::StoppedState) + return false; + + // Validate URL + if (!location.isValid()) + return false; + + // If old and new locations are same, do nothing. + QString newUrlStr = (QUrl::fromUserInput(location.toString())).toString(); + QString curUrlStr = (QUrl::fromUserInput(m_outputLocation.toString())).toString(); + if (curUrlStr.compare(newUrlStr) == KErrNone) + return true; + + QT_TRACE2("Location:", newUrlStr); + m_outputLocation = location; + /* New file, so user can set new settings */ + m_previousState = QMediaRecorder::StoppedState; + m_URItoImplSet = false; + + QT_TRACE_FUNCTION_EXIT; + return true; +} + +QMediaRecorder::State QXARecordSession::state() +{ + return m_state; +} + +qint64 QXARecordSession::duration() +{ + TInt64 dur(0); + + QT_TRACE_FUNCTION_ENTRY; + + RETURN_s_IF_m_impl_IS_NULL(dur); + + m_impl->duration(dur); + + QT_TRACE_FUNCTION_EXIT; + return (qint64)dur; +} + +void QXARecordSession::applySettings() +{ + /* Settings can only be applied when the recorder is in the stopped + * state after creation. */ + if ((state() == QMediaRecorder::StoppedState) && (m_state == m_previousState)) { + if (m_appliedaudioencodersettings != m_audioencodersettings) + setEncoderSettingsToImpl(); + } + else { + emit error(QMediaRecorder::FormatError, tr("Settings cannot be changed once recording started")); + SIGNAL_EMIT_TRACE1("emit error(QMediaRecorder::FormatError, tr(\"Settings cannot be changed once recording started\"))"); + } +} + +void QXARecordSession::record() +{ + QT_TRACE_FUNCTION_ENTRY; + + RETURN_IF_m_impl_IS_NULL; + + /* No op if object is already in recording state */ + if (state() == QMediaRecorder::RecordingState) + return; + + /* 1. Set encoder settings here */ + if (m_appliedaudioencodersettings != m_audioencodersettings) + RET_IF_FALSE(setEncoderSettingsToImpl()); + + /* 2. Set URI to impl */ + RET_IF_FALSE(setURIToImpl()); + + /* 3. Start recording... + * If successful, setRecorderState(QMediaRecorder::RecordingState); + * will be called from the callback cbRecordingStarted() + */ + if (m_impl->record() != KErrNone) { + emit error(QMediaRecorder::ResourceError, tr("Generic error")); + SIGNAL_EMIT_TRACE1("emit error(QMediaRecorder::ResourceError, tr(\"Generic error\"))"); + } + + QT_TRACE_FUNCTION_EXIT; +} + +void QXARecordSession::pause() +{ + QT_TRACE_FUNCTION_ENTRY; + + RETURN_IF_m_impl_IS_NULL; + + /* No op if object is already in paused/stopped state */ + if ((state() == QMediaRecorder::PausedState) || (state() == QMediaRecorder::StoppedState)) { + return; + } + + if (m_impl->pause() == KErrNone) { + setRecorderState(QMediaRecorder::PausedState); + } + else { + emit error(QMediaRecorder::ResourceError, tr("Unable to pause")); + SIGNAL_EMIT_TRACE1("emit error(QMediaRecorder::ResourceError, tr(\"Unable to pause\"))"); + } + + QT_TRACE_FUNCTION_EXIT; +} + +void QXARecordSession::stop() +{ + QT_TRACE_FUNCTION_ENTRY; + + RETURN_IF_m_impl_IS_NULL; + + /* No op if object is already in paused state */ + if (state() == QMediaRecorder::StoppedState) + return; + + if ((m_impl->stop() == KErrNone)) { + setRecorderState(QMediaRecorder::StoppedState); + } + else { + emit error(QMediaRecorder::ResourceError, tr("Unable to stop")); + SIGNAL_EMIT_TRACE1("emit error(QMediaRecorder::ResourceError, tr(\"Unable to stop\"))"); + } + + QT_TRACE_FUNCTION_EXIT; +} + +void QXARecordSession::cbDurationChanged(TInt64 new_pos) +{ + QT_TRACE_FUNCTION_ENTRY; + + emit durationChanged((qint64)new_pos); + SIGNAL_EMIT_TRACE1("emit durationChanged((qint64)new_pos);"); + + QT_TRACE_FUNCTION_EXIT; +} + +void QXARecordSession::cbAvailableAudioInputsChanged() +{ + QT_TRACE_FUNCTION_ENTRY; + + emit availableAudioInputsChanged(); + SIGNAL_EMIT_TRACE1("emit availableAudioInputsChanged();"); + + QT_TRACE_FUNCTION_EXIT; +} + +void QXARecordSession::cbRecordingStarted() +{ + QT_TRACE_FUNCTION_ENTRY; + + setRecorderState(QMediaRecorder::RecordingState); + + QT_TRACE_FUNCTION_EXIT; +} + +void QXARecordSession::cbRecordingStopped() +{ + QT_TRACE_FUNCTION_ENTRY; + + emit error(QMediaRecorder::ResourceError, tr("Resources Unavailable")); + SIGNAL_EMIT_TRACE1("emit error(QMediaRecorder::ResourceError, tr(\"Resources Unavailable\"))"); + setRecorderState(QMediaRecorder::StoppedState); + /* Set record state to Stopped */ + if (m_impl) + m_impl->stop(); + + QT_TRACE_FUNCTION_EXIT; +} + +/* For QAudioEndpointSelector begin */ +QList<QString> QXARecordSession::availableEndpoints() +{ + QT_TRACE_FUNCTION_ENTRY; + + QList<QString> strList; + + RETURN_s_IF_m_impl_IS_NULL(strList); + + QString str; + RArray<TPtrC> names; + m_impl->getAudioInputDeviceNames(names); + for (TInt index = 0; index < names.Count(); index++) { + str = QString((QChar*)names[index].Ptr(), names[index].Length()); + strList.append(str); + } + + QT_TRACE_FUNCTION_EXIT; + return strList; +} + +QString QXARecordSession::endpointDescription(const QString &name) +{ + /* From AL we get only device name */ + return name; +} + +QString QXARecordSession::defaultEndpoint() +{ + QT_TRACE_FUNCTION_ENTRY; + + QString str; + + RETURN_s_IF_m_impl_IS_NULL(str); + + TPtrC name; + if(m_impl->defaultAudioInputDevice(name) == KErrNone) + str = QString((QChar*)name.Ptr(), name.Length()); + + QT_TRACE_FUNCTION_EXIT; + return str; +} + +QString QXARecordSession::activeEndpoint() +{ + QT_TRACE_FUNCTION_ENTRY; + + QString str; + + RETURN_s_IF_m_impl_IS_NULL(str); + + TPtrC name; + if(m_impl->activeAudioInputDevice(name) == KErrNone) + str = QString((QChar*)name.Ptr(), name.Length()); + + QT_TRACE_FUNCTION_EXIT; + return str; +} + +void QXARecordSession::setActiveEndpoint(const QString &name) +{ + QT_TRACE_FUNCTION_ENTRY; + + RETURN_IF_m_impl_IS_NULL; + + if (name.isNull() || name.isEmpty()) + return; + + TPtrC16 tempPtr(reinterpret_cast<const TUint16*>(name.utf16())); + if (m_impl->setAudioInputDevice(tempPtr) == true) { + emit activeEndpointChanged(name); + SIGNAL_EMIT_TRACE1("emit activeEndpointChanged(name)"); + } + else { + emit error(QMediaRecorder::ResourceError, tr("Invalid endpoint")); + SIGNAL_EMIT_TRACE1("emit error(QMediaRecorder::ResourceError, tr(\"Invalid endpoint\"))"); + } + + QT_TRACE_FUNCTION_EXIT; +} +/* For QAudioEndpointSelector end */ + +/* For QAudioEncoderControl begin */ +QStringList QXARecordSession::supportedAudioCodecs() +{ + return m_codecs; +} + +QString QXARecordSession::codecDescription(const QString &codecName) +{ + if (m_codecs.contains(codecName)) + return QString(codecName); + return QString(); +} + +QList<int> QXARecordSession::supportedSampleRates( + const QAudioEncoderSettings &settings, + bool *continuous) +{ + QT_TRACE_FUNCTION_ENTRY; + + QList<int> srList; + + RETURN_s_IF_m_impl_IS_NULL(srList); + + QString selectedCodec = settings.codec(); + if (selectedCodec.isNull() || selectedCodec.isEmpty()) + selectedCodec = QString("pcm"); + + if (m_codecs.indexOf(selectedCodec) >= 0) { + RArray<TInt32> sampleRates; + TBool isContinuous; + TPtrC16 tempPtr(reinterpret_cast<const TUint16*>(selectedCodec.utf16())); + if (m_impl->getSampleRates(tempPtr, sampleRates, isContinuous) == KErrNone) { + for (TInt index = 0; index < sampleRates.Count(); index++) + srList.append(sampleRates[index]); + sampleRates.Close(); + if (continuous) + { + *continuous = false; + if (isContinuous == true) + *continuous = true; + } + } + } + + QT_TRACE_FUNCTION_EXIT; + return srList; +} + +QAudioEncoderSettings QXARecordSession::audioSettings() +{ + return m_appliedaudioencodersettings; +} + +void QXARecordSession::setAudioSettings(const QAudioEncoderSettings &settings) +{ + /* Settings can only be set when the recorder is in the stopped + * state after creation. */ + if ((state() == QMediaRecorder::StoppedState) && (m_state == m_previousState)) { + /* Validate and ignore rest of the settings */ + m_audioencodersettings = settings; + } + else { + emit error(QMediaRecorder::FormatError, tr("Settings cannot be changed once recording started")); + SIGNAL_EMIT_TRACE1("emit error(QMediaRecorder::FormatError, tr(\"Settings cannot be changed once recording started\"))"); + } +} + +QStringList QXARecordSession::supportedEncodingOptions(const QString &codec) +{ + QT_TRACE_FUNCTION_ENTRY; + Q_UNUSED(codec); + QStringList options; + if ((codec.compare("aac") == 0) || + (codec.compare("amr") == 0)) + { + options << "bitrate" << "quality"; + } + + + QT_TRACE_FUNCTION_EXIT; + return options; +} + +QVariant QXARecordSession::encodingOption(const QString &codec, const QString &name) +{ + QT_TRACE_FUNCTION_ENTRY; + + QVariant encodingOption; + QMap<QString, QVariant> map; + RETURN_s_IF_m_impl_IS_NULL(encodingOption); + + if (name.compare("bitrate") == 0) { + TPtrC16 tempPtr(reinterpret_cast<const TUint16*>(codec.utf16())); + QList<uint> bitrateList; + RArray<TUint32> bitrates; + TBool continuous; + if (m_impl->getBitrates(tempPtr, bitrates, continuous) == KErrNone) { + for (TInt index = 0; index < bitrates.Count(); index++) + bitrateList.append(bitrates[index]); + bitrates.Close(); + } + encodingOption.setValue(bitrateList); + map.insert("continuous", QVariant(continuous)); + map.insert("bitrates", encodingOption); + } + + QT_TRACE_FUNCTION_EXIT; + return map; +} + +void QXARecordSession::setEncodingOption( + const QString &codec, + const QString &name, + const QVariant &value) +{ + /* + * Currently nothing can be set via this function. + * Bitrate is set via QAudioEncoderSettings::setBitrate(). + */ + Q_UNUSED(codec); + Q_UNUSED(name); + Q_UNUSED(value); +} +/* For QAudioEncoderControl end */ + +QStringList QXARecordSession::supportedContainers() +{ + return m_containers; +} + +QString QXARecordSession::containerMimeType() +{ + return m_containerMimeType; +} + +void QXARecordSession::setContainerMimeType(const QString &formatMimeType) +{ + if (formatMimeType.isNull() || formatMimeType.isEmpty()) + return; + else if (m_containers.indexOf(formatMimeType) >= 0 ) + m_containerMimeType = formatMimeType; + else { + emit error(QMediaRecorder::FormatError, tr("Invalid container")); + SIGNAL_EMIT_TRACE1("emit error(QMediaRecorder::FormatError, tr(\"Invalid container\"))"); + } +} + +QString QXARecordSession::containerDescription(const QString &formatMimeType) +{ + int index = m_containers.indexOf(formatMimeType); + if (index >= 0) { + return m_containersDesc.at(index); + } + else { + emit error(QMediaRecorder::FormatError, tr("Invalid container")); + SIGNAL_EMIT_TRACE1("emit error(QMediaRecorder::FormatError, tr(\"Invalid container\"))"); + } + return QString(); +} + +void QXARecordSession::setRecorderState(QMediaRecorder::State state) +{ + if (state != m_state) { + m_previousState = m_state; + m_state = state; + emit stateChanged(m_state); + SIGNAL_EMIT_TRACE1("emit stateChanged(m_state);"); + } +} + +void QXARecordSession::initCodecsList() +{ + QT_TRACE_FUNCTION_ENTRY; + + RETURN_IF_m_impl_IS_NULL; + + m_codecs.clear(); + + const RArray<TPtrC>& names = m_impl->getAudioEncoderNames(); + QString str; + + for (TInt index = 0; index < names.Count(); index++) { + str = QString((QChar*)names[index].Ptr(), names[index].Length()); + m_codecs.append(str); + } + QT_TRACE_FUNCTION_EXIT; +} + +void QXARecordSession::initContainersList() +{ + QT_TRACE_FUNCTION_ENTRY; + + RETURN_IF_m_impl_IS_NULL; + + m_containers.clear(); + m_containersDesc.clear(); + + const RArray<TPtrC>& names = m_impl->getContainerNames(); + const RArray<TPtrC>& descs = m_impl->getContainerDescs(); + QString str; + + for (TInt32 index = 0; index < names.Count(); index++) { + str = QString((QChar*)names[index].Ptr(), names[index].Length()); + m_containers.append(str); + str = QString((QChar*)descs[index].Ptr(), descs[index].Length()); + m_containersDesc.append(str); + } + QT_TRACE_FUNCTION_EXIT; +} + +bool QXARecordSession::setEncoderSettingsToImpl() +{ + QT_TRACE_FUNCTION_ENTRY; + + RETURN_s_IF_m_impl_IS_NULL(false); + + m_impl->resetEncoderAttributes(); + + /* m_containerMimeType is alredy validated in ::setContainerMimeType() */ + QString tempStr = m_containerMimeType; + TPtrC16 tempPtr(reinterpret_cast<const TUint16 *>(tempStr.utf16())); + m_impl->setContainerType(tempPtr); + + /* vaidate and assign codec */ + if (m_audioencodersettings.codec().isNull() || m_audioencodersettings.codec().isEmpty()) { + m_audioencodersettings.setCodec(m_appliedaudioencodersettings.codec()); + } + tempStr = m_audioencodersettings.codec(); + if (m_codecs.indexOf(tempStr) >= 0) { + tempPtr.Set(reinterpret_cast<const TUint16*>(tempStr.utf16())); + /* We already did validation above, so function always returns true */ + m_impl->setCodec(tempPtr); + } + else { + QT_TRACE2("Codec selected is :", m_audioencodersettings.codec()); + emit error(QMediaRecorder::FormatError, tr("Invalid codec")); + SIGNAL_EMIT_TRACE1("emit error(QMediaRecorder::FormatError, tr(\"Invalid codec\"));"); + return false; + } + + /* Validate and set bitrate only if encoding mode is other than quality encoding and container type is not wav*/ + if ((m_audioencodersettings.encodingMode() != QtMultimediaKit::ConstantQualityEncoding) && + (m_containerMimeType.compare("audio/wav") != 0)) { + m_impl->setBitRate(m_audioencodersettings.bitRate()); + m_audioencodersettings.setBitRate(m_impl->getBitRate()); + } + + if (m_audioencodersettings.channelCount() == -1) { + m_impl->setOptimalChannelCount(); + } + else { + m_impl->setChannels(m_audioencodersettings.channelCount()); + m_audioencodersettings.setChannelCount(m_impl->getChannels()); + } + + switch (m_audioencodersettings.encodingMode()) { + case QtMultimediaKit::ConstantQualityEncoding: { + switch (m_audioencodersettings.quality()) { + case QtMultimediaKit::VeryLowQuality: + m_impl->setVeryLowQuality(); + m_audioencodersettings.setBitRate(m_impl->getBitRate()); + break; + case QtMultimediaKit::LowQuality: + m_impl->setLowQuality(); + m_audioencodersettings.setBitRate(m_impl->getBitRate()); + break; + case QtMultimediaKit::NormalQuality: + m_impl->setNormalQuality(); + m_audioencodersettings.setBitRate(m_impl->getBitRate()); + break; + case QtMultimediaKit::HighQuality: + m_impl->setHighQuality(); + m_audioencodersettings.setBitRate(m_impl->getBitRate()); + break; + case QtMultimediaKit::VeryHighQuality: + m_impl->setVeryHighQuality(); + m_audioencodersettings.setBitRate(m_impl->getBitRate()); + break; + default: + break; + }; /* end of switch (m_audioencodersettings.quality())*/ + } + break; + case QtMultimediaKit::ConstantBitRateEncoding: { + TInt32 status = m_impl->setCBRMode(); + if (status == KErrNotSupported) { + emit error(QMediaRecorder::FormatError, tr("Invalid encoding mode setting")); + SIGNAL_EMIT_TRACE1("emit error(QMediaRecorder::FormatError, tr(\"Invalid encoding mode setting\"));"); + return false; + } + else if (status != KErrNone) { + emit error(QMediaRecorder::ResourceError, tr("Internal error")); + SIGNAL_EMIT_TRACE1("emit error(QMediaRecorder::ResourceError, tr(\"Internal error\"));"); + return false; + } + } + break; + case QtMultimediaKit::AverageBitRateEncoding: { + TInt32 status = m_impl->setVBRMode(); + if (status == KErrNotSupported) { + emit error(QMediaRecorder::FormatError, tr("Invalid encoding mode setting")); + SIGNAL_EMIT_TRACE1("emit error(QMediaRecorder::FormatError, tr(\"Invalid encoding mode setting\"));"); + return false; + } + else if (status != KErrNone) { + emit error(QMediaRecorder::ResourceError, tr("Internal error")); + SIGNAL_EMIT_TRACE1("emit error(QMediaRecorder::ResourceError, tr(\"Internal error\"));"); + return false; + } + } + break; + case QtMultimediaKit::TwoPassEncoding: + // fall through + default: { + emit error(QMediaRecorder::FormatError, tr("Invalid encoding mode setting")); + SIGNAL_EMIT_TRACE1("emit error(QMediaRecorder::FormatError, tr(\"Invalid encoding mode setting\"));"); + return false; + } + }; /* switch (m_audioencodersettings.encodingMode()) */ + + if (m_audioencodersettings.sampleRate() == -1) { + m_impl->setOptimalSampleRate(); + } + else { + m_impl->setSampleRate(m_audioencodersettings.sampleRate()); + m_audioencodersettings.setSampleRate(m_impl->getSampleRate()); + } + m_appliedaudioencodersettings = m_audioencodersettings; + + QT_TRACE_FUNCTION_EXIT; + return true; +} + +bool QXARecordSession::setURIToImpl() +{ + QT_TRACE_FUNCTION_ENTRY; + if (m_URItoImplSet) + return true; + + /* If m_outputLocation is null, set a default location */ + if (m_outputLocation.isEmpty()) { + QDir outputDir(QDir::rootPath()); + + int lastImage = 0; + int fileCount = 0; + foreach(QString fileName, outputDir.entryList(QStringList() << "recordclip_*")) { + int imgNumber = fileName.mid(5, fileName.size() - 9).toInt(); + lastImage = qMax(lastImage, imgNumber); + if (outputDir.exists(fileName)) + fileCount += 1; + } + lastImage += fileCount; + m_outputLocation = QUrl(QDir::toNativeSeparators(outputDir.canonicalPath() + QString("/recordclip_%1").arg(lastImage + 1, 4, 10, QLatin1Char('0')))); + } + + QString newUrlStr = (QUrl::fromUserInput(m_outputLocation.toString())).toString(); + // append file prefix if required + if (newUrlStr.lastIndexOf('.') == -1) { + QString fileExtension; + if ((m_containerMimeType.compare("audio/wav")) == KErrNone) { + fileExtension = QString(".wav"); + } + else if ((m_containerMimeType.compare("audio/amr")) == KErrNone) { + fileExtension = QString(".amr"); + } + else if ((m_containerMimeType.compare("audio/mpeg")) == KErrNone) { + fileExtension = QString(".mp4"); + } + newUrlStr.append(fileExtension); + } + + QT_TRACE2("Filename selected is :", newUrlStr); + TPtrC16 tempPtr(reinterpret_cast<const TUint16 *>(newUrlStr.utf16())); + if (m_impl->setURI(tempPtr) != 0) { + emit error(QMediaRecorder::ResourceError, tr("Generic error")); + SIGNAL_EMIT_TRACE1("emit error(QMediaRecorder::ResourceError, tr(\"Generic error\"))"); + return false; + } + m_URItoImplSet = true; + m_outputLocation = QUrl(newUrlStr); + QT_TRACE_FUNCTION_EXIT; + return true; +} diff --git a/src/plugins/symbian/openmaxal/mediarecorder/qxarecordsession.h b/src/plugins/symbian/openmaxal/mediarecorder/qxarecordsession.h new file mode 100644 index 000000000..cabe58fc9 --- /dev/null +++ b/src/plugins/symbian/openmaxal/mediarecorder/qxarecordsession.h @@ -0,0 +1,144 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** +****************************************************************************/ + +#ifndef QXARECORDSESSION_H +#define QXARECORDSESSION_H + +#include <QObject> +#include <QUrl> +#include "qmediarecorder.h" +#include "xarecordsessioncommon.h" + +QT_USE_NAMESPACE + +class XARecordSessionImpl; + +/* + * This is a backend class for all QXXXControl objects. + * This class contains actual implementation of recording functionality + * from the control object's perspective. + */ + + +class QXARecordSession : public QObject, + public XARecordObserver +{ +Q_OBJECT + +public: + QXARecordSession(QObject *parent); + virtual ~QXARecordSession(); + + /* For QMediaRecorderControl begin */ + QUrl outputLocation(); + bool setOutputLocation(const QUrl &location); + QMediaRecorder::State state(); + qint64 duration(); + void applySettings(); + + void record(); + void pause(); + void stop(); + + void cbDurationChanged(TInt64 new_pos); + void cbAvailableAudioInputsChanged(); + void cbRecordingStarted(); + void cbRecordingStopped(); + /* For QMediaRecorderControl end */ + + /* For QAudioEndpointSelector begin */ + QList<QString> availableEndpoints(); + QString endpointDescription(const QString &name); + QString defaultEndpoint(); + QString activeEndpoint(); + void setActiveEndpoint(const QString &name); + /* For QAudioEndpointSelector end */ + + /* For QAudioEncoderControl begin */ + QStringList supportedAudioCodecs(); + QString codecDescription(const QString &codecName); + QList<int> supportedSampleRates( + const QAudioEncoderSettings &settings, + bool *continuous); + QAudioEncoderSettings audioSettings(); + void setAudioSettings(const QAudioEncoderSettings &settings); + QStringList supportedEncodingOptions(const QString &codec); + QVariant encodingOption(const QString &codec, const QString &name); + void setEncodingOption(const QString &codec, const QString &name, const QVariant &value); + /* For QAudioEncoderControl end */ + + /* For QMediaContainerControl begin */ + QStringList supportedContainers(); + QString containerMimeType(); + void setContainerMimeType(const QString &formatMimeType); + QString containerDescription(const QString &formatMimeType); + /* For QMediaContainerControl end */ + +Q_SIGNALS: + void stateChanged(QMediaRecorder::State state); + void durationChanged(qint64 duration); + void error(int error, const QString &errorString); + void activeEndpointChanged(const QString& name); + void availableAudioInputsChanged(); + +private: + void setRecorderState(QMediaRecorder::State state); + void initCodecsList(); + void initContainersList(); + bool setEncoderSettingsToImpl(); + bool setURIToImpl(); + +private: + /* Own */ + XARecordSessionImpl *m_impl; + QUrl m_outputLocation; + bool m_URItoImplSet; + QMediaRecorder::State m_state; + QMediaRecorder::State m_previousState; + QStringList m_codecs; + QAudioEncoderSettings m_audioencodersettings; + QAudioEncoderSettings m_appliedaudioencodersettings; + QStringList m_containers; + QStringList m_containersDesc; + QString m_containerMimeType; +}; + +#endif /* QXARECORDSESSION_H */ diff --git a/src/plugins/symbian/openmaxal/mediarecorder/xarecordsessioncommon.h b/src/plugins/symbian/openmaxal/mediarecorder/xarecordsessioncommon.h new file mode 100644 index 000000000..cdf8c1886 --- /dev/null +++ b/src/plugins/symbian/openmaxal/mediarecorder/xarecordsessioncommon.h @@ -0,0 +1,67 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** +****************************************************************************/ + +#ifndef XARECORDSESSIONCOMMON_H +#define XARECORDSESSIONCOMMON_H + +#include <e32base.h> +#include "xacommon.h" + +#define MAX_NUMBER_INTERFACES 20 +#define MAX_NUMBER_INPUT_DEVICES 10 +#define MAX_NUMBER_ENCODERS 10 + +//const TInt32 KExtErr = (TInt32)(-2147483648); +const TInt32 KExtErr = -32768; +const TInt32 KExtErrUnspecifiedCodecForContainer = (KExtErr+1); +const TInt32 KExtErrUnsupportedCodecForContainer = (KExtErr+2); +const TInt32 KExtErrUnsupportedURISuffixForContainer = (KExtErr+3); + +class XARecordObserver +{ +public: + virtual void cbDurationChanged(TInt64 new_pos) = 0; + virtual void cbAvailableAudioInputsChanged() = 0; + virtual void cbRecordingStarted() = 0; + virtual void cbRecordingStopped() = 0; +}; + +#endif /* XARECORDSESSIONCOMMON_H */ diff --git a/src/plugins/symbian/openmaxal/mediarecorder/xarecordsessionimpl.cpp b/src/plugins/symbian/openmaxal/mediarecorder/xarecordsessionimpl.cpp new file mode 100644 index 000000000..d18c781d4 --- /dev/null +++ b/src/plugins/symbian/openmaxal/mediarecorder/xarecordsessionimpl.cpp @@ -0,0 +1,1378 @@ +/**************************************************************************** + ** + ** Copyright (C) 2010 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 "xarecordsessionimpl.h" +#include "xarecordsessioncommon.h" +_LIT8(K8WAVMIMETYPE, "audio/x-wav"); +/* + * These codec names are not part of AL. Hence we need to define names here. + * */ +_LIT(KAUDIOCODECPCM, "pcm"); +_LIT(KAUDIOCODECAMR, "amr"); +_LIT(KAUDIOCODECAAC, "aac"); +_LIT(KCONTAINERWAV, "audio/wav"); +_LIT(KCONTAINERWAVDESC, "wav container"); +_LIT(KCONTAINERAMR, "audio/amr"); +_LIT(KCONTAINERAMRDESC, "amr File format"); +_LIT(KCONTAINERMP4, "audio/mpeg"); +_LIT(KCONTAINERMP4DESC, "mpeg container"); + +const TUint KRecordPosUpdatePeriod = 1000; +const TUint KMilliToHz = 1000; +const TUint KMaxNameLength = 256; + +/* Local functions for callback registation */ +void cbXAObjectItf( + XAObjectItf caller, + const void *pContext, + XAuint32 event, + XAresult result, + XAuint32 param, + void *pInterface); + +void cbXARecordItf( + XARecordItf caller, + void *pContext, + XAuint32 event); + +void cbXAAvailableAudioInputsChanged( + XAAudioIODeviceCapabilitiesItf caller, + void *pContext, + XAuint32 deviceID, + XAint32 numInputs, + XAboolean isNew); + +XARecordSessionImpl::XARecordSessionImpl(XARecordObserver &parent) : + m_Parent(parent), + m_EOEngine(NULL), + m_MORecorder(NULL), + m_RecordItf(NULL), + m_AudioEncItf(NULL), + m_WAVMime(NULL), + m_URIName(NULL), + m_InputDeviceId(0), + m_ContainerType(0), + m_BitRate(0), + m_RateControl(0), + m_ChannelsOut(1), + m_SampleRate(0), + m_AudioIODevCapsItf(NULL), + m_AudioInputDeviceNames(NULL), + m_DefaultAudioInputDeviceNames(NULL), + m_AudioEncCapsItf(NULL) +{ + TRACE_FUNCTION_ENTRY_EXIT; +} + +XARecordSessionImpl::~XARecordSessionImpl() +{ + TRACE_FUNCTION_ENTRY; + + if (m_MORecorder) + (*m_MORecorder)->Destroy(m_MORecorder); + + if (m_EOEngine) + (*m_EOEngine)->Destroy(m_EOEngine); + + delete m_WAVMime; + delete m_URIName; + + m_InputDeviceIDs.Close(); + if (m_AudioInputDeviceNames) + m_AudioInputDeviceNames->Reset(); + delete m_AudioInputDeviceNames; + m_DefaultInputDeviceIDs.Close(); + if (m_DefaultAudioInputDeviceNames) + m_DefaultAudioInputDeviceNames->Reset(); + delete m_DefaultAudioInputDeviceNames; + m_EncoderIds.Close(); + m_EncoderNames.Close(); + m_ContainerNames.Close(); + m_ContainerDescs.Close(); + + TRACE_FUNCTION_EXIT; +} + +TInt32 XARecordSessionImpl::postConstruct() +{ + TRACE_FUNCTION_ENTRY; + + XAEngineOption engineOption[] = { (XAuint32) XA_ENGINEOPTION_THREADSAFE, (XAuint32) XA_BOOLEAN_TRUE}; + + /* Create and realize Engine object */ + TRACE_LOG(_L("XARecordSessionImpl: Creating Engine...")); + XAresult xa_result = xaCreateEngine(&m_EOEngine, 1, engineOption, 0, NULL, NULL); + TInt returnValue = mapError(xa_result, ETrue); + RET_ERR_IF_ERR(returnValue); + TRACE_LOG(_L("XARecordSessionImpl: Realizing engine...")); + xa_result = (*m_EOEngine)->Realize(m_EOEngine, XA_BOOLEAN_FALSE); + returnValue = mapError(xa_result, ETrue); + RET_ERR_IF_ERR(returnValue); + TRACE_LOG(_L("XARecordSessionImpl: OMX AL Engine realized successfully")); + + XAEngineItf engineItf; + xa_result = (*m_EOEngine)->GetInterface(m_EOEngine, XA_IID_ENGINE, (void**) &engineItf); + returnValue = mapError(xa_result, ETrue); + RET_ERR_IF_ERR(returnValue); + + xa_result = (*m_EOEngine)->GetInterface(m_EOEngine, + XA_IID_AUDIOIODEVICECAPABILITIES, + (void**) &m_AudioIODevCapsItf); + returnValue = mapError(xa_result, ETrue); + RET_ERR_IF_ERR(returnValue); + xa_result = (*m_AudioIODevCapsItf)->RegisterAvailableAudioInputsChangedCallback( + m_AudioIODevCapsItf, + cbXAAvailableAudioInputsChanged, + (void*)this); + + xa_result = (*m_EOEngine)->GetInterface( + m_EOEngine, + XA_IID_AUDIOENCODERCAPABILITIES, + (void**) &m_AudioEncCapsItf); + returnValue = mapError(xa_result, ETrue); + RET_ERR_IF_ERR(returnValue); + + TRAP(returnValue, m_WAVMime = HBufC8::NewL(K8WAVMIMETYPE().Length() + 1)); + RET_ERR_IF_ERR(returnValue); + TPtr8 ptr = m_WAVMime->Des(); + ptr = K8WAVMIMETYPE(); // copy uri name into local variable + ptr.PtrZ(); // append zero terminator to end of URI + + m_AudioInputDeviceNames = new CDesC16ArrayFlat(2); + if (m_AudioInputDeviceNames == NULL) + returnValue = KErrNoMemory; + RET_ERR_IF_ERR(returnValue); + + m_DefaultAudioInputDeviceNames = new CDesC16ArrayFlat(2); + if (m_DefaultAudioInputDeviceNames == NULL) + returnValue = KErrNoMemory; + RET_ERR_IF_ERR(returnValue); + + returnValue = initContainersList(); + RET_ERR_IF_ERR(returnValue); + returnValue = initAudioEncodersList(); + RET_ERR_IF_ERR(returnValue); + returnValue = initAudioInputDevicesList(); + RET_ERR_IF_ERR(returnValue); + + TRACE_FUNCTION_EXIT; + return returnValue; +} + +TInt32 XARecordSessionImpl::setURI(const TDesC &aURI) +{ + TRACE_FUNCTION_ENTRY; + + /* This function will only get called when aURI is different than m_URIName + * and only when recorder is in stopped state. + * If the recorder object was created for a different URI (than aURI), we + * need to tear it down here. + */ + if (m_MORecorder) { + (*m_MORecorder)->Destroy(m_MORecorder); + m_MORecorder = NULL; + m_RecordItf = NULL; + } + + delete m_URIName; + m_URIName = NULL; + TRAPD(returnValue, m_URIName = HBufC8::NewL(aURI.Length()+1)); + RET_ERR_IF_ERR(returnValue); + + TPtr8 uriPtr = m_URIName->Des(); + /* copy uri name into local variable */ + uriPtr.Copy(aURI); + + TRACE_FUNCTION_EXIT; + return returnValue; +} + +TInt32 XARecordSessionImpl::record() +{ + TRACE_FUNCTION_ENTRY; + + TInt32 returnValue(KErrGeneral); + if (!m_MORecorder || !m_RecordItf) { + TRACE_LOG(_L("XARecordSessionImpl::Record: MORecorder/RecordItf is not created")); + returnValue = createMediaRecorderObject(); + RET_ERR_IF_ERR(returnValue); + + returnValue = setEncoderSettingsToMediaRecorder(); + RET_ERR_IF_ERR(returnValue); + } + + XAuint32 state; + XAresult xa_result = (*m_RecordItf)->GetRecordState(m_RecordItf, &state); + returnValue = mapError(xa_result, ETrue); + RET_ERR_IF_ERR(returnValue); + + if ((state == XA_RECORDSTATE_STOPPED) + || (state == XA_RECORDSTATE_PAUSED)) { + TRACE_LOG(_L("XARecordSessionImpl::Record: Setting State to Recording...")); + xa_result = (*m_RecordItf)->SetRecordState(m_RecordItf, XA_RECORDSTATE_RECORDING); + returnValue = mapError(xa_result, ETrue); + RET_ERR_IF_ERR(returnValue); + TRACE_LOG(_L("XARecordSessionImpl::Record: SetState to Recording")); + } + + TRACE_FUNCTION_EXIT; + return returnValue; +} + +TInt32 XARecordSessionImpl::pause() +{ + TRACE_FUNCTION_ENTRY; + + TInt32 returnValue(KErrGeneral); + if (!m_MORecorder || !m_RecordItf) { + TRACE_LOG(_L("XARecordSessionImpl::Record: MORecorder/RecordItf is not created")); + return returnValue; + } + + XAuint32 state; + XAresult xa_result = (*m_RecordItf)->GetRecordState(m_RecordItf, &state); + returnValue = mapError(xa_result, ETrue); + RET_ERR_IF_ERR(returnValue); + + if ((state == XA_RECORDSTATE_STOPPED) + || (state == XA_RECORDSTATE_RECORDING)) { + TRACE_LOG(_L("XARecordSessionImpl::Record: Setting State to Paused...")); + xa_result = (*m_RecordItf)->SetRecordState(m_RecordItf, XA_RECORDSTATE_PAUSED); + returnValue = mapError(xa_result, ETrue); + RET_ERR_IF_ERR(returnValue); + TRACE_LOG(_L("XARecordSessionImpl::Record: SetState to Paused")); + } + + TRACE_FUNCTION_EXIT; + return returnValue; +} + +TInt32 XARecordSessionImpl::stop() +{ + TRACE_FUNCTION_ENTRY; + + TInt32 returnValue(KErrGeneral); + if (!m_MORecorder || !m_RecordItf) { + TRACE_LOG(_L("XARecordSessionImpl::Record: MORecorder/RecordItf is not created")); + return returnValue; + } + + XAuint32 state; + XAresult xa_result = (*m_RecordItf)->GetRecordState(m_RecordItf, &state); + returnValue = mapError(xa_result, ETrue); + RET_ERR_IF_ERR(returnValue); + + if ((state == XA_RECORDSTATE_PAUSED) + || (state == XA_RECORDSTATE_RECORDING)) { + TRACE_LOG(_L("XARecordSessionImpl::Record: Setting State to Stopped...")); + xa_result = (*m_RecordItf)->SetRecordState(m_RecordItf, XA_RECORDSTATE_STOPPED); + returnValue = mapError(xa_result, ETrue); + RET_ERR_IF_ERR(returnValue); + TRACE_LOG(_L("XARecordSessionImpl::Record: SetState to Stopped")); + } + + TRACE_FUNCTION_EXIT; + return returnValue; +} + +TInt32 XARecordSessionImpl::duration(TInt64 &aDur) +{ + TRACE_FUNCTION_ENTRY; + + TInt32 returnValue(KErrGeneral); + + if (!m_MORecorder || !m_RecordItf) { + TRACE_LOG(_L("XARecordSessionImpl::Duration: MORecoder/RecordItf is not created")); + return returnValue; + } + + XAmillisecond milliSec; + XAresult xa_result = (*m_RecordItf)->GetPosition(m_RecordItf, &milliSec); + returnValue = mapError(xa_result, ETrue); + if (returnValue == KErrNone) + aDur = (TInt64)milliSec; + + TRACE_FUNCTION_EXIT; + return returnValue; +} + +void XARecordSessionImpl::cbMediaRecorder( + XAObjectItf /*caller*/, + const void */*pContext*/, + XAuint32 event, + XAresult result, + XAuint32 /*param*/, + void */*pInterface*/) +{ + TRACE_FUNCTION_ENTRY; + + switch (event) { + case XA_OBJECT_EVENT_RESOURCES_LOST: + m_Parent.cbRecordingStopped(); + break; + case XA_OBJECT_EVENT_RUNTIME_ERROR: { + switch (result) { + case XA_RESULT_RESOURCE_LOST: + m_Parent.cbRecordingStopped(); + break; + default: + break; + }; /* of switch (result) */ + } + default: + break; + } /* of switch (event) */ + + TRACE_FUNCTION_EXIT; +} + +void XARecordSessionImpl::cbRecordItf( + XARecordItf /*caller*/, + void */*pContext*/, + XAuint32 event) +{ + TRACE_FUNCTION_ENTRY; + + switch(event) { + case XA_RECORDEVENT_HEADATLIMIT: + TRACE_LOG(_L("XA_RECORDEVENT_HEADATLIMIT")); + break; + case XA_RECORDEVENT_HEADATMARKER: + TRACE_LOG(_L("XA_RECORDEVENT_HEADATMARKER")); + break; + case XA_RECORDEVENT_HEADATNEWPOS: { + TInt32 returnValue; + XAresult xa_result; + XAmillisecond milliSec; + xa_result = (*m_RecordItf)->GetPosition(m_RecordItf, &milliSec); + returnValue = mapError(xa_result, ETrue); + if (returnValue == KErrNone) + m_Parent.cbDurationChanged((TInt64) milliSec); + } + break; + case XA_RECORDEVENT_HEADMOVING: + TRACE_LOG(_L("XA_RECORDEVENT_HEADMOVING")); + m_Parent.cbRecordingStarted(); + break; + case XA_RECORDEVENT_HEADSTALLED: + TRACE_LOG(_L("XA_RECORDEVENT_HEADSTALLED")); + break; + case XA_RECORDEVENT_BUFFER_FULL: + TRACE_LOG(_L("XA_RECORDEVENT_BUFFER_FULL")); + break; + default: + TRACE_LOG(_L("UNKNOWN RECORDEVENT EVENT")); + break; + } /* of switch(event) */ + + TRACE_FUNCTION_EXIT; +} + +/* For QAudioEndpointSelector begin */ +void XARecordSessionImpl::getAudioInputDeviceNames(RArray<TPtrC> &aArray) +{ + TRACE_FUNCTION_ENTRY; + + for (TInt index = 0; index < m_AudioInputDeviceNames->MdcaCount(); index++) + aArray.Append(m_AudioInputDeviceNames->MdcaPoint(index)); + TRACE_FUNCTION_EXIT; +} + +TInt32 XARecordSessionImpl::defaultAudioInputDevice(TPtrC &endPoint) +{ + TRACE_FUNCTION_ENTRY; + + TInt32 err(KErrGeneral); + if (m_DefaultAudioInputDeviceNames->MdcaCount() >= 0) { + endPoint.Set(m_DefaultAudioInputDeviceNames->MdcaPoint(0)); + err = KErrNone; + } + + TRACE_FUNCTION_EXIT; + return err; +} + +TInt32 XARecordSessionImpl::activeAudioInputDevice(TPtrC &endPoint) +{ + TRACE_FUNCTION_ENTRY; + + TInt32 returnValue(KErrGeneral); + TBool found(EFalse); + TInt index = 0; + for (; index < m_InputDeviceIDs.Count(); index++) { + if (m_InputDeviceIDs[index] == m_InputDeviceId) { + found = ETrue; + break; + } + } + + /* Comparing found with ETrue produces linker error */ + if (found == true) { + endPoint.Set(m_AudioInputDeviceNames->MdcaPoint(index)); + returnValue = KErrNone; + } + + TRACE_FUNCTION_EXIT; + return returnValue; +} + +TBool XARecordSessionImpl::setAudioInputDevice(const TDesC &aDevice) +{ + TRACE_FUNCTION_ENTRY; + + /* validate if we can set input device id */ + TBool found(EFalse); + m_InputDeviceId = 0; + TInt index = 0; + for (; index < m_AudioInputDeviceNames->MdcaCount(); index++) { + if (m_AudioInputDeviceNames->MdcaPoint(index).Compare(aDevice) == 0) { + found = ETrue; + break; + } + } + if (found == true) { + m_InputDeviceId = m_InputDeviceIDs[index]; + } + + TRACE_FUNCTION_EXIT; + return found; +} + +void XARecordSessionImpl::cbAvailableAudioInputsChanged( + XAAudioIODeviceCapabilitiesItf /*caller*/, + void */*pContext*/, + XAuint32 deviceID, + XAint32 /*numInputs*/, + XAboolean isNew) +{ + TRACE_FUNCTION_ENTRY; + + /* If a new device is added into the system, append it to available input list */ + if (isNew == XA_BOOLEAN_TRUE) { + XAAudioInputDescriptor audioInputDescriptor; + m_InputDeviceIDs.Append(deviceID); + + XAresult xa_result = (*m_AudioIODevCapsItf)->QueryAudioInputCapabilities( + m_AudioIODevCapsItf, + deviceID, + &audioInputDescriptor); + + if ((mapError(xa_result, ETrue)) == KErrNone) { + TUint8* inDevNamePtr = audioInputDescriptor.deviceName; + TUint8* tempPtr = audioInputDescriptor.deviceName; + TInt32 inDevNameLength = 0; + while (*tempPtr++) + inDevNameLength++; + TPtrC8 ptr(inDevNamePtr, inDevNameLength); + /* Convert 8 bit to 16 bit */ + TBuf16<KMaxNameLength> name; + name.Copy(ptr); + /* Using TRAP with returnValue results in compiler error */ + TRAP_IGNORE(m_AudioInputDeviceNames->AppendL(name)); + } + } + else { + /* an available device has been removed from the the system, remove it from + * available input list and also default list */ + TBool found(EFalse); + TInt index = 0; + for (; index < m_InputDeviceIDs.Count(); index++) { + if (deviceID == m_InputDeviceIDs[index]) { + found = ETrue; + break; + } + } + if (found == true) { + m_InputDeviceIDs.Remove(index); + m_AudioInputDeviceNames->Delete(index); + } + if (deviceID == m_InputDeviceId) + m_InputDeviceId = 0; + + found = EFalse; + for (index = 0; index < m_DefaultInputDeviceIDs.Count(); index++) { + if (deviceID == m_DefaultInputDeviceIDs[index]) { + found = ETrue; + break; + } + } + if (found == true) { + m_DefaultInputDeviceIDs.Remove(index); + m_DefaultAudioInputDeviceNames->Delete(index); + } + } + m_Parent.cbAvailableAudioInputsChanged(); + + TRACE_FUNCTION_EXIT; +} +/* For QAudioEndpointSelector end */ + +/* For QAudioEncoderControl begin */ +const RArray<TPtrC>& XARecordSessionImpl::getAudioEncoderNames() +{ + TRACE_FUNCTION_ENTRY_EXIT; + return m_EncoderNames; +} + +TInt32 XARecordSessionImpl::getSampleRates( + const TDesC& aEncoder, + RArray<TInt32> &aSampleRates, + TBool &aIsContinuous) +{ + TRACE_FUNCTION_ENTRY; + + aSampleRates.Reset(); + aIsContinuous = EFalse; + + XAuint32 encoderId = 0; + TBool found(EFalse); + for (TInt index = 0; index < m_EncoderIds.Count(); index++) { + if (m_EncoderNames[index].Compare(aEncoder) == 0) { + found = ETrue; + encoderId = m_EncoderIds[index]; + break; + } + } + + TInt32 returnValue(KErrGeneral); + if (found == false) + return returnValue; + + returnValue = getSampleRatesByAudioCodecID(encoderId, aSampleRates); + + TRACE_FUNCTION_EXIT; + return returnValue; +} + +TInt32 XARecordSessionImpl::getBitrates( + const TDesC& aEncoder, + RArray<TUint32> &aBitrates, + TBool& aContinuous) +{ + TRACE_FUNCTION_ENTRY; + + aBitrates.Reset(); + + XAuint32 encoderId = 0; + TBool found(EFalse); + for (TInt index = 0; index < m_EncoderIds.Count(); index++) { + if (m_EncoderNames[index].Compare(aEncoder) == 0) { + found = ETrue; + encoderId = m_EncoderIds[index]; + break; + } + } + + TInt32 returnValue(KErrNotSupported); + XAboolean cont; + if (found == false) + return returnValue; + + returnValue = getBitratesByAudioCodecID(encoderId, aBitrates, cont); + aContinuous = cont; + + TRACE_FUNCTION_EXIT; + return returnValue; +} + +/* For QAudioEncoderControl end */ + +/* For QMediaContainerControl begin */ +const RArray<TPtrC>& XARecordSessionImpl::getContainerNames() +{ + TRACE_FUNCTION_ENTRY_EXIT; + return m_ContainerNames; +} + +const RArray<TPtrC>& XARecordSessionImpl::getContainerDescs() +{ + TRACE_FUNCTION_ENTRY_EXIT; + return m_ContainerDescs; +} + +/* For QMediaContainerControl end */ + +void XARecordSessionImpl::resetEncoderAttributes() +{ + m_ContainerType = 0; + m_AudioEncoderId = 0; + m_ProfileSetting = 0; + m_BitRate = 0; + m_ChannelsOut = 1; + m_SampleRate = 0; + m_RateControl = 0; +} + +void XARecordSessionImpl::setContainerType(const TDesC &aURI) +{ + TRACE_FUNCTION_ENTRY; + + if (aURI.Compare(KCONTAINERWAV()) == 0) + m_ContainerType = XA_CONTAINERTYPE_WAV; + else if (aURI.Compare(KCONTAINERAMR()) == 0) + m_ContainerType = XA_CONTAINERTYPE_AMR; + else if (aURI.Compare(KCONTAINERMP4()) == 0) + m_ContainerType = XA_CONTAINERTYPE_MP4; + + TRACE_FUNCTION_EXIT; +} + +TBool XARecordSessionImpl::setCodec(const TDesC &aCodec) +{ + TRACE_FUNCTION_ENTRY; + + TBool returnValue(EFalse); + if (aCodec.Compare(KAUDIOCODECPCM()) == 0) { + m_AudioEncoderId = XA_AUDIOCODEC_PCM; + m_ProfileSetting = XA_AUDIOPROFILE_PCM; + returnValue = ETrue; + } + else if (aCodec.Compare(KAUDIOCODECAAC()) == 0) { + m_AudioEncoderId = XA_AUDIOCODEC_AAC; + m_ProfileSetting = XA_AUDIOPROFILE_AAC_AAC; + returnValue = ETrue; + } + else if (aCodec.Compare(KAUDIOCODECAMR()) == 0) { + m_AudioEncoderId = XA_AUDIOCODEC_AMR; + m_ProfileSetting = XA_AUDIOPROFILE_AMR; + returnValue = ETrue; + } + + TRACE_FUNCTION_EXIT; + return returnValue; +} + +TUint32 XARecordSessionImpl::getBitRate() +{ + return m_BitRate; +} + +void XARecordSessionImpl::setBitRate(TUint32 aBitRate) +{ + TRACE_FUNCTION_ENTRY; + RArray<TUint32> bitrates; + XAboolean isContinuous; + m_BitRate = 0; + if (getBitratesByAudioCodecID(m_AudioEncoderId, bitrates, isContinuous) == KErrNone) { + bitrates.SortUnsigned(); + TInt loopIndex(0); + while (loopIndex < bitrates.Count() + && aBitRate <= bitrates[loopIndex]) { + m_BitRate = bitrates[loopIndex]; + loopIndex++; + } + bitrates.Close(); + } + TRACE_LOG((_L("BitRate[%d]"), m_BitRate)); + TRACE_FUNCTION_EXIT; +} + +TUint32 XARecordSessionImpl::getChannels() +{ + return m_ChannelsOut; +} + +void XARecordSessionImpl::setChannels(TUint32 aChannels) +{ + TRACE_FUNCTION_ENTRY; + switch (m_AudioEncoderId) { + case XA_AUDIOCODEC_PCM: + case XA_AUDIOCODEC_AAC: + m_ChannelsOut = 1; + if ((aChannels >= 1) && (aChannels <= 2)) + m_ChannelsOut = aChannels; + break; + case XA_AUDIOCODEC_AMR: + m_ChannelsOut = 1; + break; + default: + break; + } + TRACE_LOG((_L("ChannelCount[%d]"), m_ChannelsOut)); + TRACE_FUNCTION_EXIT; +} + +void XARecordSessionImpl::setOptimalChannelCount() +{ + TRACE_FUNCTION_ENTRY; + m_ChannelsOut = 1; + TRACE_FUNCTION_EXIT; +} + +TUint32 XARecordSessionImpl::getSampleRate() +{ + return m_SampleRate; +} + +void XARecordSessionImpl::setSampleRate(TUint32 aSampleRate) +{ + TRACE_FUNCTION_ENTRY; + + m_SampleRate = 0; + + RArray<TInt32> samplerates; + if (getSampleRatesByAudioCodecID(m_AudioEncoderId, samplerates) == KErrNone) { + samplerates.SortUnsigned(); + TInt loopIndex(0); + while (loopIndex < samplerates.Count()) { + m_SampleRate = samplerates[loopIndex]; + if (samplerates[loopIndex] > aSampleRate) + break; + loopIndex++; + } + samplerates.Close(); + } + + /* convert Hz to MilliHz */ + m_SampleRate *= KMilliToHz; + TRACE_LOG((_L("SampleRate[%d]"), m_SampleRate)); + TRACE_FUNCTION_EXIT; +} + +void XARecordSessionImpl::setOptimalSampleRate() +{ + TRACE_FUNCTION_ENTRY; + m_SampleRate = 0; + + if (m_AudioEncoderId == XA_AUDIOCODEC_AAC) { + m_SampleRate = 32000 * KMilliToHz; + } + else if (m_AudioEncoderId == XA_AUDIOCODEC_AMR) { + m_SampleRate = 8000 * KMilliToHz; + } + else { + RArray<TInt32> sampleRates; + TInt res = getSampleRatesByAudioCodecID(m_AudioEncoderId, sampleRates); + if ((res == KErrNone) && (sampleRates.Count() > 0)) { + /* Sort the array and pick the middle range sample rate */ + sampleRates.SortUnsigned(); + m_SampleRate = sampleRates[sampleRates.Count() / 2] * KMilliToHz; + } + sampleRates.Close(); + } + + TRACE_FUNCTION_EXIT; +} + +TInt32 XARecordSessionImpl::setCBRMode() +{ + TRACE_FUNCTION_ENTRY; + + m_RateControl = XA_RATECONTROLMODE_CONSTANTBITRATE; + + TRACE_FUNCTION_EXIT; + return KErrNone; +} + +TInt32 XARecordSessionImpl::setVBRMode() +{ + TRACE_FUNCTION_ENTRY; + + m_RateControl = XA_RATECONTROLMODE_VARIABLEBITRATE; + + TRACE_FUNCTION_EXIT; + return KErrNone; +} + +void XARecordSessionImpl::setVeryLowQuality() +{ + /* Set to very low quality encoder preset */ + RArray<TUint32> bitrates; + XAboolean continuous; + TInt res = getBitratesByAudioCodecID(m_AudioEncoderId, bitrates, continuous); + if ((res == KErrNone) && (bitrates.Count() > 0)) { + /* Sort the array and pick the lowest bit rate */ + bitrates.SortUnsigned(); + m_BitRate = bitrates[0]; + } + bitrates.Close(); +} + +void XARecordSessionImpl::setLowQuality() +{ + /* Set to low quality encoder preset */ + RArray<TUint32> bitrates; + XAboolean continuous; + TInt res = getBitratesByAudioCodecID(m_AudioEncoderId, bitrates, continuous); + if ((res == KErrNone) && (bitrates.Count() > 0)) { + /* Sort the array and pick the low quality bit rate */ + bitrates.SortUnsigned(); + if (continuous == XA_BOOLEAN_FALSE) + m_BitRate = bitrates[bitrates.Count() / 4]; + else + m_BitRate = (bitrates[1] - bitrates[0]) / 4; + } + bitrates.Close(); +} + +void XARecordSessionImpl::setNormalQuality() +{ + /* Set to normal quality encoder preset */ + RArray<TUint32> bitrates; + XAboolean continuous; + TInt res = getBitratesByAudioCodecID(m_AudioEncoderId, bitrates, continuous); + if ((res == KErrNone) && (bitrates.Count() > 0)) { + /* Sort the array and pick the middle range bit rate */ + bitrates.SortUnsigned(); + if (continuous == XA_BOOLEAN_FALSE) + m_BitRate = bitrates[bitrates.Count() / 2]; + else + m_BitRate = (bitrates[1] - bitrates[0]) / 2; + } + bitrates.Close(); +} + +void XARecordSessionImpl::setHighQuality() +{ + /* Set to high quality encoder preset */ + RArray<TUint32> bitrates; + XAboolean continuous; + TInt res = getBitratesByAudioCodecID(m_AudioEncoderId, bitrates, continuous); + if ((res == KErrNone) && (bitrates.Count() > 0)) { + /* Sort the array and pick the high quality bit rate */ + bitrates.SortUnsigned(); + if (continuous == XA_BOOLEAN_FALSE) + m_BitRate = bitrates[bitrates.Count() * 3 / 4]; + else + m_BitRate = (bitrates[1] - bitrates[0]) * 3 / 4; + } + bitrates.Close(); +} + +void XARecordSessionImpl::setVeryHighQuality() +{ + /* Set to very high quality encoder preset */ + RArray<TUint32> bitrates; + XAboolean continuous; + TInt res = getBitratesByAudioCodecID(m_AudioEncoderId, bitrates, continuous); + if ((res == KErrNone) && (bitrates.Count() > 0)) { + /* Sort the array and pick the highest bit rate */ + bitrates.SortUnsigned(); + m_BitRate = bitrates[bitrates.Count() - 1]; + } + bitrates.Close(); +} + +/* Internal function */ +TInt32 XARecordSessionImpl::createMediaRecorderObject() +{ + TRACE_FUNCTION_ENTRY; + + if (!m_EOEngine) + return KErrGeneral; + + TInt32 returnValue(KErrNone); + + TRACE_LOG(_L("XARecordSessionImpl::CreateMediaRecorderObject")); + if (!m_MORecorder && !m_RecordItf) { + + /* Setup the data source */ + m_LocatorMic.locatorType = XA_DATALOCATOR_IODEVICE; + m_LocatorMic.deviceType = XA_IODEVICE_AUDIOINPUT; + m_LocatorMic.deviceID = m_InputDeviceId; + m_LocatorMic.device = NULL; + m_DataSource.pLocator = (void*) &m_LocatorMic; + m_DataSource.pFormat = NULL; + + /* Setup the data sink structure */ + m_Uri.locatorType = XA_DATALOCATOR_URI; + /* append zero terminator to end of URI */ + TPtr8 uriPtr = m_URIName->Des(); + m_Uri.URI = (XAchar*) uriPtr.PtrZ(); + m_Mime.formatType = XA_DATAFORMAT_MIME; + m_Mime.containerType = m_ContainerType; + TPtr8 mimeTypePtr(m_WAVMime->Des()); + m_Mime.mimeType = (XAchar*) mimeTypePtr.Ptr(); + m_DataSink.pLocator = (void*) &m_Uri; + m_DataSink.pFormat = (void*) &m_Mime; + + /* Init arrays required[] and iidArray[] */ + XAboolean required[MAX_NUMBER_INTERFACES]; + XAInterfaceID iidArray[MAX_NUMBER_INTERFACES]; + for (TInt32 i = 0; i < MAX_NUMBER_INTERFACES; i++) { + required[i] = XA_BOOLEAN_FALSE; + iidArray[i] = XA_IID_NULL; + } + XAuint32 noOfInterfaces = 0; + required[noOfInterfaces] = XA_BOOLEAN_FALSE; + iidArray[noOfInterfaces] = XA_IID_RECORD; + noOfInterfaces++; + required[noOfInterfaces] = XA_BOOLEAN_FALSE; + iidArray[noOfInterfaces] = XA_IID_AUDIOENCODER; + noOfInterfaces++; + + XAEngineItf engineItf; + XAresult xa_result = (*m_EOEngine)->GetInterface(m_EOEngine, XA_IID_ENGINE, (void**) &engineItf); + returnValue = mapError(xa_result, ETrue); + RET_ERR_IF_ERR(returnValue); + + TRACE_LOG(_L("XARecordSessionImpl::CreateMediaRecorderObject: Create Media Recorder...")); + + /* Create recorder with NULL for a the image/video source, since this is for audio-only recording */ + xa_result = (*engineItf)->CreateMediaRecorder( + engineItf, + &m_MORecorder, + &m_DataSource, + NULL, + &m_DataSink, + noOfInterfaces, + iidArray, + required); + returnValue = mapError(xa_result, ETrue); + RET_ERR_IF_ERR(returnValue); + + TRACE_LOG(_L("XARecordSessionImpl::CreateMediaRecorderObject: Realize Media Recorder...")); + xa_result = (*m_MORecorder)->Realize(m_MORecorder, XA_BOOLEAN_FALSE); + returnValue = mapError(xa_result, ETrue); + RET_ERR_IF_ERR(returnValue); + + TRACE_LOG(_L("XARecordSessionImpl::CreateMediaRecorderObject: Register Callback on recorder...")); + xa_result = (*m_MORecorder)->RegisterCallback(m_MORecorder, cbXAObjectItf, (void*) this); + returnValue = mapError(xa_result, ETrue); + RET_ERR_IF_ERR(returnValue); + + TRACE_LOG(_L("XARecordSessionImpl::CreateMediaRecorderObject: Getting Record Interface...")); + xa_result = (*m_MORecorder)->GetInterface(m_MORecorder, XA_IID_RECORD, &m_RecordItf); + returnValue = mapError(xa_result, ETrue); + RET_ERR_IF_ERR(returnValue); + + TRACE_LOG(_L("XARecordSessionImpl::CreateMediaRecorderObject: Registering Callback on record Interface...")); + xa_result = (*m_RecordItf)->RegisterCallback(m_RecordItf, cbXARecordItf, (void*) this); + returnValue = mapError(xa_result, ETrue); + RET_ERR_IF_ERR(returnValue); + + TRACE_LOG(_L("XARecordSessionImpl::CreateMediaRecorderObject: SetPositionUpdatePeriod on record Interface...")); + xa_result = (*m_RecordItf)->SetPositionUpdatePeriod(m_RecordItf, (XAmillisecond)KRecordPosUpdatePeriod); + returnValue = mapError(xa_result, ETrue); + RET_ERR_IF_ERR(returnValue); + + TRACE_LOG(_L("XARecordSessionImpl::CreateMediaRecorderObject: SetCallbackEventsMask on record Interface...")); + xa_result = (*m_RecordItf)->SetCallbackEventsMask(m_RecordItf, XA_RECORDEVENT_HEADATNEWPOS | + XA_RECORDEVENT_HEADMOVING | + XA_RECORDEVENT_HEADSTALLED); + returnValue = mapError(xa_result, ETrue); + RET_ERR_IF_ERR(returnValue); + + TRACE_LOG(_L("XARecordSessionImpl::CreateMediaRecorderObject: Getting Audio Encoder Interface...")); + xa_result = (*m_MORecorder)->GetInterface(m_MORecorder, XA_IID_AUDIOENCODER, &m_AudioEncItf); + returnValue = mapError(xa_result, ETrue); + RET_ERR_IF_ERR(returnValue); + } + + TRACE_FUNCTION_EXIT; + return returnValue; +} + +TInt32 XARecordSessionImpl::mapError(XAresult xa_err, TBool debPrn) +{ + TInt32 returnValue(KErrGeneral); + switch (xa_err) { + case XA_RESULT_SUCCESS: + returnValue = KErrNone; + break; + case XA_RESULT_PRECONDITIONS_VIOLATED: + if (debPrn) + TRACE_LOG(_L("XA_RESULT_PRECONDITIONS_VIOLATED")); + break; + case XA_RESULT_PARAMETER_INVALID: + if (debPrn) + TRACE_LOG(_L("XA_RESULT_PARAMETER_INVALID")); + break; + case XA_RESULT_MEMORY_FAILURE: + if (debPrn) + TRACE_LOG(_L("XA_RESULT_MEMORY_FAILURE")); + break; + case XA_RESULT_RESOURCE_ERROR: + if (debPrn) + TRACE_LOG(_L("XA_RESULT_RESOURCE_ERROR")); + break; + case XA_RESULT_RESOURCE_LOST: + if (debPrn) + TRACE_LOG(_L("XA_RESULT_RESOURCE_LOST")); + break; + case XA_RESULT_IO_ERROR: + if (debPrn) + TRACE_LOG(_L("XA_RESULT_IO_ERROR")); + break; + case XA_RESULT_BUFFER_INSUFFICIENT: + if (debPrn) + TRACE_LOG(_L("XA_RESULT_BUFFER_INSUFFICIENT")); + break; + case XA_RESULT_CONTENT_CORRUPTED: + if (debPrn) + TRACE_LOG(_L("XA_RESULT_CONTENT_CORRUPTED")); + break; + case XA_RESULT_CONTENT_UNSUPPORTED: + if (debPrn) + TRACE_LOG(_L("XA_RESULT_CONTENT_UNSUPPORTED")); + break; + case XA_RESULT_CONTENT_NOT_FOUND: + if (debPrn) + TRACE_LOG(_L("XA_RESULT_CONTENT_NOT_FOUND")); + break; + case XA_RESULT_PERMISSION_DENIED: + if (debPrn) + TRACE_LOG(_L("XA_RESULT_PERMISSION_DENIED")); + break; + case XA_RESULT_FEATURE_UNSUPPORTED: + if (debPrn) + TRACE_LOG(_L("XA_RESULT_FEATURE_UNSUPPORTED")); + break; + case XA_RESULT_INTERNAL_ERROR: + if (debPrn) + TRACE_LOG(_L("XA_RESULT_INTERNAL_ERROR")); + break; + case XA_RESULT_UNKNOWN_ERROR: + if (debPrn) + TRACE_LOG(_L("XA_RESULT_UNKNOWN_ERROR")); + break; + case XA_RESULT_OPERATION_ABORTED: + if (debPrn) + TRACE_LOG(_L("XA_RESULT_OPERATION_ABORTED")); + break; + case XA_RESULT_CONTROL_LOST: + if (debPrn) + TRACE_LOG(_L("XA_RESULT_CONTROL_LOST")); + break; + default: + if (debPrn) + TRACE_LOG(_L("Unknown Error!!!")); + break; + } + return returnValue; +} + +TInt32 XARecordSessionImpl::initContainersList() +{ + TRACE_FUNCTION_ENTRY; + + m_ContainerNames.Reset(); + m_ContainerDescs.Reset(); + + m_ContainerNames.Append(KCONTAINERWAV()); + m_ContainerNames.Append(KCONTAINERAMR()); + m_ContainerNames.Append(KCONTAINERMP4()); + + m_ContainerDescs.Append(KCONTAINERWAVDESC()); + m_ContainerDescs.Append(KCONTAINERAMRDESC()); + m_ContainerDescs.Append(KCONTAINERMP4DESC()); + + TRACE_FUNCTION_EXIT; + return KErrNone; +} + +TInt32 XARecordSessionImpl::initAudioEncodersList() +{ + TRACE_FUNCTION_ENTRY; + + m_EncoderIds.Reset(); + m_EncoderNames.Reset(); + + XAuint32 encoderIds[MAX_NUMBER_ENCODERS]; + + for (TInt index = 0; index < MAX_NUMBER_ENCODERS; index++) + encoderIds[index] = 0; + + XAuint32 numEncoders = MAX_NUMBER_ENCODERS; + XAresult xa_result = (*m_AudioEncCapsItf)->GetAudioEncoders( + m_AudioEncCapsItf, + &numEncoders, + encoderIds); + TInt32 returnValue = mapError(xa_result, ETrue); + RET_ERR_IF_ERR(returnValue); + + for (TInt index = 0; index < numEncoders; index++) { + m_EncoderIds.Append(encoderIds[index]); + switch (encoderIds[index]) { + case XA_AUDIOCODEC_PCM: + m_EncoderNames.Append(KAUDIOCODECPCM()); + break; + case XA_AUDIOCODEC_AMR: + m_EncoderNames.Append(KAUDIOCODECAMR()); + break; + case XA_AUDIOCODEC_AAC: + m_EncoderNames.Append(KAUDIOCODECAAC()); + break; + default: + break; + }; + } + + TRACE_FUNCTION_EXIT; + return returnValue; +} + +TInt32 XARecordSessionImpl::initAudioInputDevicesList() +{ + TRACE_FUNCTION_ENTRY; + + m_InputDeviceIDs.Reset(); + + XAuint32 deviceIds[MAX_NUMBER_INPUT_DEVICES]; + for (TInt index = 0; index < MAX_NUMBER_INPUT_DEVICES; index++) + deviceIds[index] = 0; + + XAint32 numInputs = MAX_NUMBER_INPUT_DEVICES; + XAresult xa_result = (*m_AudioIODevCapsItf)->GetAvailableAudioInputs( + m_AudioIODevCapsItf, + &numInputs, + deviceIds); + TInt32 returnValue = mapError(xa_result, ETrue); + RET_ERR_IF_ERR(returnValue); + + XAAudioInputDescriptor audioInputDescriptor; + for (TInt index = 0; index < numInputs; index++) { + xa_result = (*m_AudioIODevCapsItf)->QueryAudioInputCapabilities( + m_AudioIODevCapsItf, + deviceIds[index], + &audioInputDescriptor); + returnValue = mapError(xa_result, ETrue); + if (returnValue != KErrNone) + continue; + + TUint8 * inDevNamePtr = audioInputDescriptor.deviceName; + TUint8 * tempPtr = audioInputDescriptor.deviceName; + TInt32 inDevNameLength = 0; + while (*tempPtr++) + inDevNameLength++; + TPtrC8 ptr(inDevNamePtr, inDevNameLength); + /* Convert 8 bit to 16 bit */ + TBuf16<KMaxNameLength> name; + name.Copy(ptr); + /* Using TRAP with returnValue results in compiler error */ + TRAPD(err2, m_AudioInputDeviceNames->AppendL(name)); + returnValue = err2; + if (returnValue != KErrNone) + continue; + m_InputDeviceIDs.Append(deviceIds[index]); + } + + numInputs = MAX_NUMBER_INPUT_DEVICES; + for (TInt index = 0; index < MAX_NUMBER_INPUT_DEVICES; index++) + deviceIds[index] = 0; + xa_result = (*m_AudioIODevCapsItf)->GetDefaultAudioDevices( + m_AudioIODevCapsItf, + XA_DEFAULTDEVICEID_AUDIOINPUT, + &numInputs, + deviceIds); + returnValue = mapError(xa_result, ETrue); + RET_ERR_IF_ERR(returnValue); + + for (TInt index = 0; index < numInputs; index++) { + xa_result = (*m_AudioIODevCapsItf)->QueryAudioInputCapabilities( + m_AudioIODevCapsItf, + deviceIds[index], + &audioInputDescriptor); + returnValue = mapError(xa_result, ETrue); + if (returnValue != KErrNone) + continue; + TUint8* inDevNamePtr = audioInputDescriptor.deviceName; + TUint8* tempPtr = audioInputDescriptor.deviceName; + TInt32 inDevNameLength = 0; + while (*tempPtr++) + inDevNameLength++; + TPtrC8 ptr(inDevNamePtr, inDevNameLength); + /* Convert 8 bit to 16 bit */ + TBuf16<KMaxNameLength> name; + name.Copy(ptr); + /* Using TRAP with returnValue results in compiler error */ + TRAPD(err2, m_DefaultAudioInputDeviceNames->AppendL(name)); + returnValue = err2; + if (returnValue != KErrNone) + continue; + m_DefaultInputDeviceIDs.Append(deviceIds[index]); + m_InputDeviceId = deviceIds[index]; + } + + TRACE_FUNCTION_EXIT; + return returnValue; +} + +TInt32 XARecordSessionImpl::setEncoderSettingsToMediaRecorder() +{ + TRACE_FUNCTION_EXIT; + + /* Get current settings */ + XAAudioEncoderSettings settings; + XAresult xa_result = (*m_AudioEncItf)->GetEncoderSettings( + m_AudioEncItf, + &settings); + TInt32 returnValue = mapError(xa_result, ETrue); + + settings.encoderId = m_AudioEncoderId; + settings.channelsOut = m_ChannelsOut; + if ((m_SampleRate != 0) && (m_SampleRate != 0xffffffff)) + settings.sampleRate = m_SampleRate; + if ((m_BitRate != 0) && (m_BitRate != 0xffffffff)) + settings.bitRate = m_BitRate; + if (m_RateControl != 0) + settings.rateControl = m_RateControl; + settings.profileSetting = m_ProfileSetting; + xa_result = (*m_AudioEncItf)->SetEncoderSettings( + m_AudioEncItf, + &settings); + returnValue = mapError(xa_result, ETrue); + + TRACE_FUNCTION_EXIT; + return returnValue; +} + +TInt32 XARecordSessionImpl::getBitratesByAudioCodecID( + XAuint32 encoderId, + RArray<TUint32> &aBitrates, + XAboolean& aContinuous) +{ + TRACE_FUNCTION_ENTRY; + + if (!m_AudioEncCapsItf) + return KErrGeneral; + + XAuint32 numCaps = 0; + XAAudioCodecDescriptor codecDesc; + XAresult xa_result = (*m_AudioEncCapsItf)->GetAudioEncoderCapabilities( + m_AudioEncCapsItf, + encoderId, + &numCaps, + &codecDesc); + TInt32 returnValue = mapError(xa_result, ETrue); + RET_ERR_IF_ERR(returnValue); + aContinuous = codecDesc.isBitrateRangeContinuous; + /* TODO What do we do if we have more than one caps?? */ + if (codecDesc.isBitrateRangeContinuous == XA_BOOLEAN_TRUE) { + aBitrates.Append(codecDesc.minBitRate); + aBitrates.Append(codecDesc.maxBitRate); + } + else { + XAuint32 numBrSupported = codecDesc.numBitratesSupported; + XAuint32 * pBitratesSupported(NULL); + pBitratesSupported = codecDesc.pBitratesSupported; + TInt32 index = 0; + for (index = 0; index < numBrSupported; index++) + aBitrates.Append(*(pBitratesSupported + index)); + } + + TRACE_FUNCTION_ENTRY; + return returnValue; +} + +TInt32 XARecordSessionImpl::getSampleRatesByAudioCodecID(XAuint32 encoderId, + RArray<TInt32> &aSampleRates) +{ + TRACE_FUNCTION_ENTRY; + + if (!m_AudioEncCapsItf) + return KErrGeneral; + + XAuint32 numCaps = 0; + XAAudioCodecDescriptor codecDesc; + XAresult xa_result = (*m_AudioEncCapsItf)->GetAudioEncoderCapabilities( + m_AudioEncCapsItf, + encoderId, + &numCaps, + &codecDesc); + TInt returnValue = mapError(xa_result, ETrue); + RET_ERR_IF_ERR(returnValue); + + /* TODO What do we do if we have more than one caps?? */ + if (codecDesc.isFreqRangeContinuous == XA_BOOLEAN_TRUE) { + aSampleRates.Append(codecDesc.minSampleRate / KMilliToHz); + aSampleRates.Append(codecDesc.maxSampleRate / KMilliToHz); + } + else { + XAuint32 numSRSupported = codecDesc.numSampleRatesSupported; + XAmilliHertz *pSampleRatesSupported(NULL); + pSampleRatesSupported = codecDesc.pSampleRatesSupported; + for (TInt index = 0; index < numSRSupported; index++) + aSampleRates.Append((*(pSampleRatesSupported + index)) / KMilliToHz); + } + + TRACE_FUNCTION_ENTRY; + return returnValue; +} + +/* Local function implementation */ +void cbXAObjectItf( + XAObjectItf caller, + const void *pContext, + XAuint32 event, + XAresult result, + XAuint32 param, + void *pInterface) +{ + if (pContext) { + ((XARecordSessionImpl*)pContext)->cbMediaRecorder( + caller, + pContext, + event, + result, + param, + pInterface); + } +} + +void cbXARecordItf( + XARecordItf caller, + void *pContext, + XAuint32 event) +{ + if (pContext) { + ((XARecordSessionImpl*)pContext)->cbRecordItf( + caller, + pContext, + event); + } +} + +void cbXAAvailableAudioInputsChanged( + XAAudioIODeviceCapabilitiesItf caller, + void * pContext, + XAuint32 deviceID, + XAint32 numInputs, + XAboolean isNew) +{ + if (pContext) { + ((XARecordSessionImpl*)pContext)->cbAvailableAudioInputsChanged( + caller, + pContext, + deviceID, + numInputs, + isNew); + } +} diff --git a/src/plugins/symbian/openmaxal/mediarecorder/xarecordsessionimpl.h b/src/plugins/symbian/openmaxal/mediarecorder/xarecordsessionimpl.h new file mode 100644 index 000000000..81e4ac763 --- /dev/null +++ b/src/plugins/symbian/openmaxal/mediarecorder/xarecordsessionimpl.h @@ -0,0 +1,179 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** +****************************************************************************/ + +#ifndef XARECORDSESSIONIMPL_H +#define XARECORDSESSIONIMPL_H + +#include <OpenMAXAL.h> +#include <badesca.h> + + +class XARecordObserver; +class XARecordSessionImpl +{ +public: + XARecordSessionImpl(XARecordObserver &parent); + ~XARecordSessionImpl(); + TInt32 postConstruct(); + + /* For QMediaRecorderControl begin */ + TInt32 setURI(const TDesC &aURI); + TInt32 record(); + TInt32 pause(); + TInt32 stop(); + TInt32 duration(TInt64 &aDur); + /* For QMediaRecorderControl end */ + + void cbMediaRecorder(XAObjectItf caller, + const void *pContext, + XAuint32 event, + XAresult result, + XAuint32 param, + void *pInterface); + void cbRecordItf(XARecordItf caller, + void *pContext, + XAuint32 event); + + /* For QAudioEndpointSelector begin */ + void getAudioInputDeviceNames(RArray<TPtrC> &aArray); + TInt32 defaultAudioInputDevice(TPtrC &endPoint); + TInt32 activeAudioInputDevice(TPtrC &endPoint); + TBool setAudioInputDevice(const TDesC &aDevice); + void cbAvailableAudioInputsChanged(XAAudioIODeviceCapabilitiesItf caller, + void *pContext, + XAuint32 deviceID, + XAint32 numInputs, + XAboolean isNew); + /* For QAudioEndpointSelector end */ + + /* For QAudioEncoderControl begin */ + const RArray<TPtrC>& getAudioEncoderNames(); + TInt32 getSampleRates(const TDesC &aEncoder, + RArray<TInt32> &aSampleRates, + TBool &aIsContinuous); + TInt32 getBitrates(const TDesC &aEncoder, + RArray<TUint32> &aBitrates, + TBool& aContinuous); + /* For QAudioEncoderControl end */ + + /* For QMediaContainerControl begin */ + const RArray<TPtrC>& getContainerNames(); + const RArray<TPtrC>& getContainerDescs(); + /* For QMediaContainerControl end */ + + void resetEncoderAttributes(); + void setContainerType(const TDesC &aURI); + TBool setCodec(const TDesC &aURI); + TUint32 getBitRate(); + void setBitRate(TUint32 aBitRate); + TUint32 getChannels(); + void setChannels(TUint32 aChannels); + void setOptimalChannelCount(); + TUint32 getSampleRate(); + void setSampleRate(TUint32 aSampleRate); + void setOptimalSampleRate(); + TInt32 setCBRMode(); + TInt32 setVBRMode(); + void setVeryLowQuality(); + void setLowQuality(); + void setNormalQuality(); + void setHighQuality(); + void setVeryHighQuality(); + +private: + TInt32 createMediaRecorderObject(); + TInt32 mapError(XAresult xa_err, + TBool debPrn); + TInt32 initContainersList(); + TInt32 initAudioEncodersList(); + TInt32 initAudioInputDevicesList(); + TInt32 setEncoderSettingsToMediaRecorder(); + TInt32 getBitratesByAudioCodecID(XAuint32 encoderId, + RArray<TUint32> &aBitrates, + XAboolean& aContinuous); + TInt32 getSampleRatesByAudioCodecID(XAuint32 encoderId, + RArray<TInt32> &aSampleRates); + + +private: + XARecordObserver &m_Parent; + XAObjectItf m_EOEngine; + XAObjectItf m_MORecorder; + XARecordItf m_RecordItf; + XAAudioEncoderItf m_AudioEncItf; + /* Audio Source */ + XADataSource m_DataSource; + XADataLocator_IODevice m_LocatorMic; + XADataFormat_MIME m_Mime; + XADataLocator_URI m_Uri; + /*Audio Sink*/ + XADataSink m_DataSink; + HBufC8 *m_WAVMime; + + /* Set by client*/ + HBufC8 *m_URIName; + XAuint32 m_AudioEncoderId; + XAuint32 m_InputDeviceId; + XAuint32 m_ContainerType; + XAuint32 m_BitRate; + XAuint32 m_RateControl; + XAuint32 m_ProfileSetting; + XAuint32 m_ChannelsOut; + XAuint32 m_SampleRate; + + /* For QAudioEndpointSelector begin */ + XAAudioIODeviceCapabilitiesItf m_AudioIODevCapsItf; + RArray<TUint32> m_InputDeviceIDs; + CDesC16ArrayFlat *m_AudioInputDeviceNames; + RArray<TUint32> m_DefaultInputDeviceIDs; + CDesC16ArrayFlat *m_DefaultAudioInputDeviceNames; + /* For QAudioEndpointSelector end */ + + /* For QAudioEncoderControl begin */ + XAAudioEncoderCapabilitiesItf m_AudioEncCapsItf; + RArray<XAuint32> m_EncoderIds; + RArray<TPtrC> m_EncoderNames; + RArray<TPtrC> m_ContainerNames; + RArray<TPtrC> m_ContainerDescs; + /* For QAudioEncoderControl begin */ +}; + +#endif /* XARECORDSESSIONIMPL_H */ diff --git a/src/plugins/symbian/openmaxal/openmaxal.pro b/src/plugins/symbian/openmaxal/openmaxal.pro new file mode 100644 index 000000000..0565536a4 --- /dev/null +++ b/src/plugins/symbian/openmaxal/openmaxal.pro @@ -0,0 +1,58 @@ +TEMPLATE = lib + +CONFIG += plugin +TARGET = $$qtLibraryTarget(qtmultimediakit_openmaxalengine) +PLUGIN_TYPE = mediaservice +include (../../../../common.pri) +qtAddLibrary(QtMultimediaKit) + +#includes here so that all defines are added here also +include(mediaplayer/mediaplayer.pri) +include(mediarecorder/mediarecorder.pri) +include(radiotuner/radiotuner.pri) + +DEPENDPATH += . + +HEADERS += qxamediaserviceproviderplugin.h \ + qxacommon.h \ + xacommon.h + +SOURCES += qxamediaserviceproviderplugin.cpp + +# Input parameters for the generated bld.inf file +# ----------------------------------------------- +SYMBIAN_PLATFORMS = DEFAULT + +# Input parameters for the generated mmp file +# ------------------------------------------- +load(data_caging_paths) +TARGET.UID3 = 0x10207CA1 +TARGET.CAPABILITY = ALL -TCB +TARGET.EPOCALLOWDLLDATA = 1 +MMP_RULES += EXPORTUNFROZEN + +# Macros controlling debug traces +#DEFINES += PROFILE_TIME +#DEFINES += PROFILE_RAM_USAGE +#DEFINES += PROFILE_HEAP_USAGE +#DEFINES += PLUGIN_QT_TRACE_ENABLED +#DEFINES += PLUGIN_QT_SIGNAL_EMIT_TRACE_ENABLED +#DEFINES += PLUGIN_SYMBIAN_TRACE_ENABLED + +INCLUDEPATH += $$MW_LAYER_SYSTEMINCLUDE +INCLUDEPATH += /epoc32/include/platform/mw/khronos + + +# Input parameters for qmake to make the dll a qt plugin +pluginDep.sources = $${TARGET}.dll +pluginDep.path = $${QT_PLUGINS_BASE_DIR}/$${PLUGIN_TYPE} +DEPLOYMENT += pluginDep + +LIBS += \ + -lQtMultimediaKit \ + -lopenmaxal + +# check for PROFILE_RAM_USAGE +contains(DEFINES, PROFILE_RAM_USAGE) { + LIBS += -lhal +} diff --git a/src/plugins/symbian/openmaxal/qxacommon.h b/src/plugins/symbian/openmaxal/qxacommon.h new file mode 100644 index 000000000..f19a75d1c --- /dev/null +++ b/src/plugins/symbian/openmaxal/qxacommon.h @@ -0,0 +1,203 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** +****************************************************************************/ + +#ifndef QXACOMMON_H +#define QXACOMMON_H + +#if defined(PLUGIN_QT_TRACE_ENABLED) \ + || defined(PLUGIN_QT_SIGNAL_EMIT_TRACE_ENABLED) \ + || defined(PROFILE_TIME) \ + || defined(PROFILE_RAM_USAGE) \ + || defined(PROFILE_HEAP_USAGE) +# include <QDebug> +#endif /* PLUGIN_QT_TRACE_ENABLED */ + +#ifdef PROFILE_RAM_USAGE +# include <hal.h> +#endif + + +#ifdef PLUGIN_QT_TRACE_ENABLED +# define QT_TRACE_FUNCTION_ENTRY qDebug() << __PRETTY_FUNCTION__ << ">" +# define QT_TRACE_FUNCTION_EXIT qDebug() << __PRETTY_FUNCTION__ << "<" +# define QT_TRACE_FUNCTION_ENTRY_EXIT qDebug() << __PRETTY_FUNCTION__ << "><" +# define QT_TRACE1(v1) qDebug() << v1 +# define QT_TRACE2(v1, v2) qDebug() << v1 << v2 +#else +# define QT_TRACE_FUNCTION_ENTRY +# define QT_TRACE_FUNCTION_EXIT +# define QT_TRACE_FUNCTION_ENTRY_EXIT +# define QT_TRACE1(v1) +# define QT_TRACE2(v1, v2) +#endif /*PLUGIN_QT_TRACE_ENABLED*/ + +#ifdef PLUGIN_QT_SIGNAL_EMIT_TRACE_ENABLED +# define SIGNAL_EMIT_TRACE1(v1) qDebug() << __PRETTY_FUNCTION__ << v1 +#else +# define SIGNAL_EMIT_TRACE1(v1) +#endif /*PLUGIN_QT_SIGNAL_EMIT_TRACE_ENABLED*/ + +#ifdef PROFILE_TIME_ELAPSED +# define TAG_TIME_PROFILING_BEGIN \ + TTime beginProfilingTime; \ + beginProfilingTime.HomeTime() + +# define TAG_TIME_PROFILING_END \ + TTime endProfilingTime; \ + endProfilingTime.HomeTime(); \ + TTimeIntervalMicroSeconds diffInMicroSecs = endProfilingTime.MicroSecondsFrom(beginProfilingTime) + +# define QT_PRINT_TO_CONSOLE_TIME_DIFF \ + qDebug() << "VPROFILEDAT: " << __PRETTY_FUNCTION__ << ": Time taken " << diffInMicroSecs.Int64() << " microseconds" +#else /* Empty macros */ +# define TAG_TIME_PROFILING_BEGIN +# define TAG_TIME_PROFILING_END +# define QT_PRINT_TO_CONSOLE_TIME_DIFF +#endif /*PROFILE_TIME_ELAPSED*/ + +#ifdef PROFILE_RAM_USAGE +# define TAG_RAM_PROFILING_BEGIN \ + TInt beginProfilingRAM; \ + TInt err1 = HAL::Get(HALData::EMemoryRAMFree, beginProfilingRAM) + +# define TAG_RAM_PROFILING_END \ + TInt endProfilingRAM; \ + TInt err2 = HAL::Get(HALData::EMemoryRAMFree, endProfilingRAM) + +# define QT_PRINT_TO_CONSOLE_RAM_DIFF \ + if ((err1 == KErrNone) && (err2 == KErrNone)) \ + { \ + TInt diffRAM = (beginProfilingRAM - endProfilingRAM); \ + if ( diffRAM > 0 ) \ + { \ + qDebug() << "VPROFILEDAT: " << __PRETTY_FUNCTION__ << ": " << diffRAM << " bytes of RAM used"; \ + } \ + else \ + { \ + qDebug() << "VPROFILEDAT: " << __PRETTY_FUNCTION__ << ": " << -(diffRAM) << " bytes of RAM freed"; \ + } \ + } \ + else \ + { \ + qDebug() << "VPROFILEDAT: " << __PRETTY_FUNCTION__ << "Error1[" << err1 << "] Error2[" << err2; \ + } + +#else /* Empty macros */ +# define TAG_RAM_PROFILING_BEGIN +# define TAG_RAM_PROFILING_END +# define QT_PRINT_TO_CONSOLE_RAM_DIFF +#endif /*PROFILE_RAM_USAGE*/ + +#ifdef PROFILE_HEAP_USAGE +# define TAG_DEFAULT_HEAP_PROFILING_BEGIN \ + TInt beginProfilingHEAPBiggestBlock; \ + TInt beginProfilingHEAP = User::Available(beginProfilingHEAPBiggestBlock) \ + +# define TAG_DEFAULT_HEAP_PROFILING_END \ + TInt endProfilingHEAPBiggestBlock; \ + TInt endProfilingHEAP = User::Available(endProfilingHEAPBiggestBlock) \ + +# define QT_PRINT_TO_CONSOLE_HEAP_DIFF \ + TInt diffHEAP = beginProfilingHEAP - endProfilingHEAP; \ + if ( diffHEAP > 0 ) \ + { \ + qDebug() << "VPROFILEDAT: " << __PRETTY_FUNCTION__ << ": " << diffHEAP << " bytes in default HEAP used"; \ + } \ + else \ + { \ + qDebug() << "VPROFILEDAT: " << __PRETTY_FUNCTION__ << ": " << -(diffHEAP) << " bytes in default HEAP freed"; \ + } +#else /* Empty macros */ +# define TAG_DEFAULT_HEAP_PROFILING_BEGIN +# define TAG_DEFAULT_HEAP_PROFILING_END +# define QT_PRINT_TO_CONSOLE_HEAP_DIFF +#endif /*PROFILE_HEAP_USAGE*/ + +/* This macro checks p pointer for null. If it is, returns value 's' from + * function immediately. + */ +#define RET_s_IF_p_IS_NULL(p, s) \ + if (p == NULL) { \ + return s; \ + } + +/* This macro checks p pointer for null. If it is, returns from function + * immediately. + */ +#define RET_IF_p_IS_NULL(p) \ + if (p == NULL) { \ + return; \ + } + +/* This macro checks p pointer for null. If it is, emits an error signal + * error(QMediaPlayer::ResourceError, tr("Resource Error")); + * and returns value 's' from function immediately. + */ +#define RET_s_IF_p_IS_NULL_EMIT_PLAYER_RESOURCE_ERROR(p, s) \ + if (p == NULL) { \ + emit error(QMediaPlayer::ResourceError, tr("Resource Error")); \ + SIGNAL_EMIT_TRACE1("emit error(QMediaPlayer::ResourceError, tr(\"Resource Error\"))"); \ + return s; \ + } + +/* This macro checks p pointer for null. If it is, emits an error signal + * error(QMediaPlayer::ResourceError, tr("Resource Error")); + * and returns from function immediately. + */ +#define RET_IF_p_IS_NULL_EMIT_PLAYER_RESOURCE_ERROR(p) \ + if (p == NULL) { \ + emit error(QMediaPlayer::ResourceError, tr("Resource Error")); \ + SIGNAL_EMIT_TRACE1("emit error(QMediaPlayer::ResourceError, tr(\"Resource Error\"))"); \ + return; \ + } + +/* This macro checks p pointer for null. If it is, emits an error signal + * error(QMediaPlayer::ResourceError, tr("Resource Error")); + * and returns from function immediately. + */ +#define RET_IF_ERROR(p) \ + if (p != KErrNone) { \ + emit error(QMediaPlayer::ResourceError, tr("Resource Error")); \ + SIGNAL_EMIT_TRACE1("emit error(QMediaPlayer::ResourceError, tr(\"Resource Error\"))"); \ + return; \ + } + +#endif /* QXACOMMON_H */ diff --git a/src/plugins/symbian/openmaxal/qxamediaserviceproviderplugin.cpp b/src/plugins/symbian/openmaxal/qxamediaserviceproviderplugin.cpp new file mode 100644 index 000000000..bfbb4333a --- /dev/null +++ b/src/plugins/symbian/openmaxal/qxamediaserviceproviderplugin.cpp @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** 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 <QString> +#include "qxamediaserviceproviderplugin.h" +#include "qxaplaymediaservice.h" +#include "qxarecordmediaservice.h" +#include "qxaradiomediaservice.h" +#include "qxacommon.h" + +QStringList QXAMediaServiceProviderPlugin::keys() const +{ + return QStringList() + << QLatin1String(Q_MEDIASERVICE_MEDIAPLAYER) + << QLatin1String(Q_MEDIASERVICE_AUDIOSOURCE) + << QLatin1String(Q_MEDIASERVICE_RADIO); +} + +QMediaService* QXAMediaServiceProviderPlugin::create(QString const& key) +{ + QT_TRACE_FUNCTION_ENTRY; + QMediaService* service = NULL; + if (key == QLatin1String(Q_MEDIASERVICE_MEDIAPLAYER) ) { + service = new QXAPlayMediaService; + QT_TRACE1("Created QXAPlayMediaService"); + } + else if (key == QLatin1String(Q_MEDIASERVICE_AUDIOSOURCE)) { + service = new QXARecodMediaService; + QT_TRACE1("Created QXARecodMediaService"); + } + else if (key == QLatin1String(Q_MEDIASERVICE_RADIO) ) { + service = new QXARadioMediaService; + QT_TRACE1("Created QXARadioMediaService"); + } + else { + QT_TRACE2("unsupported key:", key); + } + QT_TRACE_FUNCTION_EXIT; + return service; +} + +void QXAMediaServiceProviderPlugin::release(QMediaService *service) +{ + QT_TRACE_FUNCTION_ENTRY; + delete service; + QT_TRACE_FUNCTION_EXIT; +} + +Q_EXPORT_PLUGIN2(qtmultimediakit_openmaxalengine, QXAMediaServiceProviderPlugin); diff --git a/src/plugins/symbian/openmaxal/qxamediaserviceproviderplugin.h b/src/plugins/symbian/openmaxal/qxamediaserviceproviderplugin.h new file mode 100644 index 000000000..6d3530349 --- /dev/null +++ b/src/plugins/symbian/openmaxal/qxamediaserviceproviderplugin.h @@ -0,0 +1,60 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef QXAMEDIASERVICEPROVIDERPLUGIN_H +#define QXAMEDIASERVICEPROVIDERPLUGIN_H + +#include <QtCore/qobject.h> +#include <qmediaserviceprovider.h> +#include <qmediaserviceproviderplugin.h> + +QT_USE_NAMESPACE + +class QXAMediaServiceProviderPlugin : public QMediaServiceProviderPlugin +{ + Q_OBJECT +public: + QStringList keys() const; + QMediaService* create(QString const& key); + void release(QMediaService *service); +}; + +#endif /* QXAMEDIASERVICEPROVIDERPLUGIN_H */ diff --git a/src/plugins/symbian/openmaxal/radiotuner/qxaradiocontrol.cpp b/src/plugins/symbian/openmaxal/radiotuner/qxaradiocontrol.cpp new file mode 100644 index 000000000..9666b0410 --- /dev/null +++ b/src/plugins/symbian/openmaxal/radiotuner/qxaradiocontrol.cpp @@ -0,0 +1,202 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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 "qxaradiocontrol.h" +#include "qxaradiosession.h" +#include "xaradiosessionimpl.h" + +QXARadioControl::QXARadioControl(QXARadioSession *session, QObject *parent) +:QRadioTunerControl(parent), m_session(session) +{ + + connect(m_session, SIGNAL(stateChanged(QRadioTuner::State)), this, SIGNAL(stateChanged(QRadioTuner::State))); + + connect(m_session, SIGNAL(bandChanged(QRadioTuner::Band)), this, SIGNAL(bandChanged(QRadioTuner::Band))); + + connect(m_session, SIGNAL(frequencyChanged(int)), this, SIGNAL(frequencyChanged(int))); + + connect(m_session, SIGNAL(stereoStatusChanged(bool)), this, SIGNAL(stereoStatusChanged(bool))); + + connect(m_session, SIGNAL(searchingChanged(bool)), this, SIGNAL(searchingChanged(bool))); + + connect(m_session, SIGNAL(signalStrengthChanged(int)), this, SIGNAL(signalStrengthChanged(int))); + + connect(m_session, SIGNAL(volumeChanged(int)), this, SIGNAL(volumeChanged(int))); + + connect(m_session, SIGNAL(mutedChanged(bool)), this, SIGNAL(mutedChanged(bool))); + +// connect(m_session, SIGNAL(error(int,QString)), this,SIGNAL(error(int,QString))); +} + +QXARadioControl::~QXARadioControl() +{ + +} + +QtMultimediaKit::AvailabilityError QXARadioControl::availabilityError() const +{ + return m_session->availabilityError(); +} + +bool QXARadioControl::isAvailable() const +{ + return m_session->isAvailable(); +} + +QRadioTuner::State QXARadioControl::state() const +{ + return m_session->state(); +} + +QRadioTuner::Band QXARadioControl::band() const +{ + return m_session->band(); +} + +void QXARadioControl::setBand(QRadioTuner::Band band) +{ + m_session->setBand(band); +} + +bool QXARadioControl::isBandSupported(QRadioTuner::Band band) const +{ + return m_session->isBandSupported(band); +} + +int QXARadioControl::frequency() const +{ + return m_session->frequency(); +} + +int QXARadioControl::frequencyStep(QRadioTuner::Band band) const +{ + return m_session->frequencyStep(band); +} + +QPair<int,int> QXARadioControl::frequencyRange(QRadioTuner::Band band) const +{ + return m_session->frequencyRange(band); +} + +void QXARadioControl::setFrequency(int freq) +{ + m_session->setFrequency(freq); +} + +bool QXARadioControl::isStereo() const +{ + return m_session->isStereo(); +} + +QRadioTuner::StereoMode QXARadioControl::stereoMode() const +{ + return m_session->stereoMode(); +} + +void QXARadioControl::setStereoMode(QRadioTuner::StereoMode stereoMode) +{ + m_session->setStereoMode(stereoMode); +} + +int QXARadioControl::signalStrength() const +{ + return m_session->signalStrength(); +} + +int QXARadioControl::volume() const +{ + return m_session->volume(); +} + +void QXARadioControl::setVolume(int volume) +{ + m_session->setVolume(volume); +} + +bool QXARadioControl::isMuted() const +{ + return m_session->isMuted(); +} + +void QXARadioControl::setMuted(bool muted) +{ + m_session->setMuted(muted); +} + +bool QXARadioControl::isSearching() const +{ + return m_session->isSearching(); +} + +void QXARadioControl::searchForward() +{ + m_session->searchForward(); +} + +void QXARadioControl::searchBackward() +{ + m_session->searchBackward(); +} + +void QXARadioControl::cancelSearch() +{ + m_session->cancelSearch(); +} + +void QXARadioControl::start() +{ + m_session->start(); +} + +void QXARadioControl::stop() +{ + m_session->stop(); +} + +QRadioTuner::Error QXARadioControl::error() const +{ + return m_session->error(); +} + +QString QXARadioControl::errorString() const +{ + return m_session->errorString(); +} diff --git a/src/plugins/symbian/openmaxal/radiotuner/qxaradiocontrol.h b/src/plugins/symbian/openmaxal/radiotuner/qxaradiocontrol.h new file mode 100644 index 000000000..47d4f827d --- /dev/null +++ b/src/plugins/symbian/openmaxal/radiotuner/qxaradiocontrol.h @@ -0,0 +1,95 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** +****************************************************************************/ + +#ifndef QXARADIOCONTROL_H +#define QXARADIOCONTROL_H + +#include <QObject> +#include <QRadioTunerControl> + +QT_USE_NAMESPACE + +class QXARadioSession; + +class QXARadioControl : public QRadioTunerControl +{ + Q_OBJECT + +public: + QXARadioControl(QXARadioSession *session, QObject *parent = 0); + virtual ~QXARadioControl(); + QRadioTuner::State state() const; + + QRadioTuner::Band band() const; + void setBand(QRadioTuner::Band band); + bool isBandSupported(QRadioTuner::Band band) const; + int frequency() const; + int frequencyStep(QRadioTuner::Band band) const; + QPair<int,int> frequencyRange(QRadioTuner::Band band) const; + void setFrequency(int freq); + bool isStereo() const; + QRadioTuner::StereoMode stereoMode() const; + void setStereoMode(QRadioTuner::StereoMode stereoMode); + int signalStrength() const; + int volume() const; + void setVolume(int volume); + bool isMuted() const; + void setMuted(bool muted); + bool isSearching() const; + void searchForward(); + void searchBackward(); + void cancelSearch(); + bool isValid() const; + bool isAvailable() const; + QtMultimediaKit::AvailabilityError availabilityError() const; + void start(); + void stop(); + QRadioTuner::Error error() const; + QString errorString() const; + +private: + QXARadioSession *m_session; + +protected: + QXARadioControl(QObject* parent = 0); +}; + +#endif /* QXARADIOCONTROL_H */ diff --git a/src/plugins/symbian/openmaxal/radiotuner/qxaradiomediaservice.cpp b/src/plugins/symbian/openmaxal/radiotuner/qxaradiomediaservice.cpp new file mode 100644 index 000000000..f399ef8c5 --- /dev/null +++ b/src/plugins/symbian/openmaxal/radiotuner/qxaradiomediaservice.cpp @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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 <QString> + +#include "qxaradiomediaservice.h" +#include "qxaradiosession.h" +#include "qxaradiocontrol.h" +#include <qradiotunercontrol.h> + +QXARadioMediaService::QXARadioMediaService(QObject *parent) + : QMediaService(parent) +{ + m_session = new QXARadioSession(this); + m_control = new QXARadioControl(m_session, this); +} + +QXARadioMediaService::~QXARadioMediaService() +{ +} + +QMediaControl* QXARadioMediaService::requestControl(const char *name) +{ + + if (qstrcmp(name, QRadioTunerControl_iid) == 0) { + return m_control; + } + return 0; +} + +void QXARadioMediaService::releaseControl(QMediaControl *control) +{ + Q_UNUSED(control) +} diff --git a/src/plugins/symbian/openmaxal/radiotuner/qxaradiomediaservice.h b/src/plugins/symbian/openmaxal/radiotuner/qxaradiomediaservice.h new file mode 100644 index 000000000..7ac014f8f --- /dev/null +++ b/src/plugins/symbian/openmaxal/radiotuner/qxaradiomediaservice.h @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** +****************************************************************************/ + +#ifndef QXARADIOMEDIASERVICE_H +#define QXARADIOMEDIASERVICE_H + +#include <QtCore/qobject.h> +#include <qmediaservice.h> + +QT_USE_NAMESPACE + +class QXARadioSession; +class QXARadioControl; + +class QXARadioMediaService : public QMediaService +{ + Q_OBJECT +public: + QXARadioMediaService(QObject *parent = 0); + ~QXARadioMediaService(); + QMediaControl *requestControl(const char *name); + void releaseControl( QMediaControl *control); +private: + QXARadioSession *m_session; + QXARadioControl *m_control; +}; + +#endif /*QXARADIOMEDIASERVICE_H*/ diff --git a/src/plugins/symbian/openmaxal/radiotuner/qxaradiosession.cpp b/src/plugins/symbian/openmaxal/radiotuner/qxaradiosession.cpp new file mode 100644 index 000000000..6822813c4 --- /dev/null +++ b/src/plugins/symbian/openmaxal/radiotuner/qxaradiosession.cpp @@ -0,0 +1,323 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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 <qradiotuner.h> +#include "qxaradiosession.h" +#include "xaradiosessionimpl.h" +#include "qxacommon.h" + +QXARadioSession::QXARadioSession(QObject *parent) +:QObject(parent) +{ + QT_TRACE_FUNCTION_ENTRY; + m_impl = new XARadioSessionImpl(*this); + if (!m_impl) { + QT_TRACE1("RadioSession::RadioSession(): ERROR creating RadioSessionImpl..."); + return; + } + if (m_impl->PostConstruct() != QRadioTuner::NoError) { + QT_TRACE1("RadioSession::RadioSession(): ERROR from RadioSessionImpl::PostContstruct..."); + delete m_impl; + m_impl = NULL; + } + QT_TRACE_FUNCTION_EXIT; +} + +QXARadioSession::~QXARadioSession() +{ + delete m_impl; +} + +QRadioTuner::State QXARadioSession::state() const +{ + QRadioTuner::State state = QRadioTuner::StoppedState; + if (m_impl) + state = m_impl->State(); + return state; + } +QtMultimediaKit::AvailabilityError QXARadioSession::availabilityError() const +{ + QtMultimediaKit::AvailabilityError error = QtMultimediaKit::NoError; + if (m_impl) + error = m_impl->AvailabilityError(); + return error; +} + +QRadioTuner::Band QXARadioSession::band() const +{ + QRadioTuner::Band band = QRadioTuner::FM; + if (m_impl) + band = m_impl->Band(); + return band; +} + +void QXARadioSession::setBand(QRadioTuner::Band band) +{ + if (m_impl) + m_impl->SetBand(band); +} + +bool QXARadioSession::isBandSupported(QRadioTuner::Band band) const +{ + if (m_impl) + return m_impl->IsBandSupported(band); + return false; +} + +bool QXARadioSession::isAvailable() const +{ + if (m_impl) + return m_impl->IsAvailable(); + return false; +} + +int QXARadioSession::frequency() const +{ + TInt frequency = 0; + if (m_impl) + frequency = m_impl->GetFrequency(); + return (int)frequency; +} + +int QXARadioSession::frequencyStep(QRadioTuner::Band band) const +{ + TInt freqStep = 0; + if (m_impl) + freqStep = m_impl->FrequencyStep(band); + return (int)freqStep; +} + +QPair<int, int> QXARadioSession::frequencyRange(QRadioTuner::Band /*band*/) const +{ + QPair<int, int> freqRange; + freqRange.first = 0; + freqRange.second =0; + + if (m_impl) { + TInt freqRangeType = m_impl->GetFrequencyRange(); + m_impl->GetFrequencyRangeProperties(freqRangeType, freqRange.first, freqRange.second); + } + + return freqRange; +} + +void QXARadioSession::setFrequency(int frequency) +{ + if (m_impl) + m_impl->SetFrequency(frequency); +} + +bool QXARadioSession::isStereo() const +{ + bool isStereo = false; + if (m_impl) + isStereo = m_impl->IsStereo(); + return isStereo; +} + +QRadioTuner::StereoMode QXARadioSession::stereoMode() const +{ + QRadioTuner::StereoMode mode(QRadioTuner::Auto); + if (m_impl) + mode = m_impl->StereoMode(); + return mode; +} + +void QXARadioSession::setStereoMode(QRadioTuner::StereoMode mode) +{ + if (m_impl) + m_impl->SetStereoMode(mode); +} + +int QXARadioSession::signalStrength() const +{ + TInt signalStrength = 0; + if (m_impl) + signalStrength = m_impl->GetSignalStrength(); + return (int)signalStrength; +} + +int QXARadioSession::volume() const +{ + TInt volume = 0; + if (m_impl) + volume = m_impl->GetVolume(); + return volume; +} + +int QXARadioSession::setVolume(int volume) +{ + TInt newVolume = 0; + if (m_impl) { + m_impl->SetVolume(volume); + newVolume = m_impl->GetVolume(); + } + return newVolume; +} + +bool QXARadioSession::isMuted() const +{ + bool isMuted = false; + if (m_impl) + isMuted = m_impl->IsMuted(); + return isMuted; +} + +void QXARadioSession::setMuted(bool muted) +{ + if (m_impl) + m_impl->SetMuted(muted); +} + +bool QXARadioSession::isSearching() const +{ + bool isSearching = false; + if (m_impl) + isSearching = m_impl->IsSearching(); + return isSearching; +} + +void QXARadioSession::searchForward() +{ + if (m_impl) + m_impl->Seek(true); +} + +void QXARadioSession::searchBackward() +{ + if (m_impl) + m_impl->Seek(false); +} + +void QXARadioSession::cancelSearch() +{ + if (m_impl) + m_impl->StopSeeking(); +} + +void QXARadioSession::start() +{ + if (m_impl) + m_impl->Start(); +} + +void QXARadioSession::stop() +{ + if (m_impl) + m_impl->Stop(); +} + +QRadioTuner::Error QXARadioSession::error() const +{ + QRadioTuner::Error err(QRadioTuner::NoError); + if (m_impl) + err = m_impl->Error(); + return err; +} + +QString QXARadioSession::errorString() const +{ + QString str = NULL; + switch (iError) { + case QRadioTuner::ResourceError: + str = "Resource Error"; + break; + case QRadioTuner::OpenError: + str = "Open Error"; + break; + case QRadioTuner::OutOfRangeError: + str = "Out of Range Error"; + break; + default: + break; + } + + return str; +} + +// Callbacks, which will emit signals to client: +void QXARadioSession::CBStateChanged(QRadioTuner::State state) +{ + emit stateChanged(state); +} + +void QXARadioSession::CBBandChanged(QRadioTuner::Band band) +{ + emit bandChanged(band); +} + +void QXARadioSession::CBFrequencyChanged(TInt newFrequency) +{ + emit frequencyChanged(newFrequency); +} + +void QXARadioSession::CBStereoStatusChanged(bool isStereo) +{ + emit stereoStatusChanged(isStereo); +} + +void QXARadioSession::CBSignalStrengthChanged(int signalStrength) +{ + emit signalStrengthChanged(signalStrength); +} + +void QXARadioSession::CBVolumeChanged(int volume) +{ + emit volumeChanged(volume); +} + +void QXARadioSession::CBMutedChanged(bool isMuted) +{ + emit mutedChanged(isMuted); +} + +void QXARadioSession::CBSearchingChanged(bool isSearching) +{ + emit searchingChanged(isSearching); +} + +void QXARadioSession::CBError(QRadioTuner::Error err) +{ + iError = err; + emit error((int)err, errorString()); +} + + diff --git a/src/plugins/symbian/openmaxal/radiotuner/qxaradiosession.h b/src/plugins/symbian/openmaxal/radiotuner/qxaradiosession.h new file mode 100644 index 000000000..72f6a7a01 --- /dev/null +++ b/src/plugins/symbian/openmaxal/radiotuner/qxaradiosession.h @@ -0,0 +1,118 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** +****************************************************************************/ + +#ifndef QXARADIOSESSION_H +#define QXARADIOSESSION_H + +#include <QObject> +#include <QUrl> +#include <qradiotuner.h> +#include "xaradiosessionimplobserver.h" + +QT_USE_NAMESPACE + +class XARadioSessionImpl; + +class QXARadioSession : public QObject, public XARadioSessionImplObserver +{ +Q_OBJECT + +public: + QXARadioSession(QObject *parent); + virtual ~QXARadioSession(); + + QRadioTuner::State state() const; + QRadioTuner::Band band() const; + void setBand(QRadioTuner::Band band); + bool isBandSupported(QRadioTuner::Band band) const; + int frequency() const; + int frequencyStep(QRadioTuner::Band b) const; + QPair<int,int> frequencyRange(QRadioTuner::Band b) const; + void setFrequency(int frequency); + bool isStereo() const; + QRadioTuner::StereoMode stereoMode() const; + void setStereoMode(QRadioTuner::StereoMode mode); + int signalStrength() const; + int volume() const; + int setVolume(int volume); + bool isMuted() const; + void setMuted(bool muted); + bool isSearching() const; + void searchForward(); + void searchBackward(); + void cancelSearch(); + void start(); + void stop(); + bool isAvailable() const; + QtMultimediaKit::AvailabilityError availabilityError() const; + QRadioTuner::Error error() const; + QString errorString() const; + + /* Callbacks from XARadioSessionImplObserver begin */ + void CBBandChanged(QRadioTuner::Band band); + void CBStateChanged(QRadioTuner::State state); + void CBFrequencyChanged(TInt newFrequency); + void CBStereoStatusChanged(bool isStereo); + void CBSignalStrengthChanged(int signalStrength); + void CBVolumeChanged(int volume); + void CBMutedChanged(bool isMuted); + void CBSearchingChanged(bool isSearching); + void CBError(QRadioTuner::Error err); + /* Callbacks from XARadioSessionImplObserver end */ + +signals: + void stateChanged(QRadioTuner::State state); + void bandChanged(QRadioTuner::Band band); + void frequencyChanged(int frequency); + void stereoStatusChanged(bool stereo); + void searchingChanged(bool stereo); + void signalStrengthChanged(int signalStrength); + void volumeChanged(int volume); + void mutedChanged(bool muted); + void error(int err, QString str); + +private: + /* Own */ + QRadioTuner::Error iError; + XARadioSessionImpl* m_impl; +}; + +#endif /*QXARADIOSESSION_H*/ diff --git a/src/plugins/symbian/openmaxal/radiotuner/radiotuner.pri b/src/plugins/symbian/openmaxal/radiotuner/radiotuner.pri new file mode 100644 index 000000000..bf83d05fc --- /dev/null +++ b/src/plugins/symbian/openmaxal/radiotuner/radiotuner.pri @@ -0,0 +1,18 @@ +INCLUDEPATH += $$PWD + +# Input +HEADERS += \ + $$PWD/qxaradiomediaservice.h \ + $$PWD/qxaradiosession.h \ + $$PWD/qxaradiocontrol.h \ + $$PWD/xaradiosessionimpl.h \ + $$PWD/xaradiosessionimplobserver.h + +SOURCES += \ + $$PWD/qxaradiomediaservice.cpp \ + $$PWD/qxaradiosession.cpp \ + $$PWD/qxaradiocontrol.cpp \ + $$PWD/xaradiosessionimpl.cpp + +LIBS += \ + -lbafl diff --git a/src/plugins/symbian/openmaxal/radiotuner/xaradiosessionimpl.cpp b/src/plugins/symbian/openmaxal/radiotuner/xaradiosessionimpl.cpp new file mode 100644 index 000000000..94bebc373 --- /dev/null +++ b/src/plugins/symbian/openmaxal/radiotuner/xaradiosessionimpl.cpp @@ -0,0 +1,715 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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 "xaradiosessionimpl.h" +#include "xaradiosessionimplobserver.h" +#include <xaradioitfext.h> +#include "xacommon.h" + +#define MAX_NUMBER_INTERFACES 20 +#define FM_STEP 100000; // Hz (.1 MHz) + +/* + * function declarations. + * */ +void EngineObjectCallback(XAObjectItf caller, const void */*pContext*/, + XAuint32 event, XAresult result, XAuint32 /*param*/, + void */*pInterface*/); + +void RadioCallback(XARadioItf caller, void* pContext, XAuint32 event, XAuint32 eventIntData, XAboolean eventBooleanData); +void NokiaVolumeExtItfCallback(XANokiaVolumeExtItf caller, void* pContext, XAuint32 event, XAboolean eventBooleanData); +void NokiaLinearVolumeItfCallback(XANokiaLinearVolumeItf caller, void* pContext, XAuint32 event, XAboolean eventBooleanData); +void PlayItfCallbackForRadio(XAPlayItf caller, void* pContext, XAuint32 event); + +XARadioSessionImpl::XARadioSessionImpl(XARadioSessionImplObserver& parent) +:iParent(parent), +iRadio(NULL), +iEngine(NULL), +iPlayer(NULL), +iSearching(EFalse), +iRadioAvailable(EFalse), +iState(QRadioTuner::StoppedState) +{ + iAvailabilityError = QtMultimediaKit::NoError; +} + +XARadioSessionImpl::~XARadioSessionImpl() +{ + if (iRadio) { + TRACE_LOG((_L("XARadioSessionImpl::~XARadioSessionImpl(): Deleting Radio Device..."))); + (*iRadio)->Destroy(iRadio); + iRadio = NULL; + TRACE_LOG((_L("XARadioSessionImpl::~XARadioSessionImpl(): Deleted Radio Device"))); + } + if (iPlayer) { + TRACE_LOG((_L("XARadioSessionImpl::~XARadioSessionImpl(): Deleting player..."))); + (*iPlayer)->Destroy(iPlayer); + iPlayer = NULL; + TRACE_LOG((_L("XARadioSessionImpl::~XARadioSessionImpl(): Deleted iPlayer"))); + } + if ( iEngine ) { + TRACE_LOG((_L("XARadioSessionImpl::~XARadioSessionImpl(): Deleting engine..."))); + (*iEngine)->Destroy(iEngine); + iEngine = NULL; + TRACE_LOG((_L("XARadioSessionImpl::~XARadioSessionImpl(): Deleted engine"))); + } +} + +QRadioTuner::Error XARadioSessionImpl::PostConstruct() +{ + XAresult res = CreateEngine(); + if (res != KErrNone) + return QRadioTuner::ResourceError; + else + return QRadioTuner::NoError; +} + +TInt XARadioSessionImpl::CreateEngine() +{ + TRACE_FUNCTION_ENTRY; + XAboolean required[MAX_NUMBER_INTERFACES]; + XAInterfaceID iidArray[MAX_NUMBER_INTERFACES]; + XAuint32 noOfInterfaces = 0; + int i; + XAresult res; + + XAEngineOption EngineOption[] = + { + { + (XAuint32) XA_ENGINEOPTION_THREADSAFE, + (XAuint32) XA_BOOLEAN_TRUE + } + }; + + /* Create XA engine */ + if (!iEngine) { + TRACE_LOG((_L("XARadioSessionImpl::CreateEngine: Creating Engine..."))); + res = xaCreateEngine(&iEngine, 1, EngineOption, 0, NULL, NULL); + RET_ERR_IF_ERR(CheckErr(res)); + res = (*iEngine)->RegisterCallback(iEngine, EngineObjectCallback, NULL); + RET_ERR_IF_ERR(CheckErr(res)); + + TRACE_LOG((_L("XARadioSessionImpl::CreateEngine: Realizing..."))); + res = (*iEngine)->Realize(iEngine, XA_BOOLEAN_FALSE); + RET_ERR_IF_ERR(CheckErr(res)); + + // Create Engine Interface: + TRACE_LOG((_L("XARadioSessionImpl::CreateEngine: Creating Engine Interface"))); + RET_ERR_IF_ERR(CheckErr((*iEngine)->GetInterface(iEngine, XA_IID_ENGINE, (void*)&iEngineItf))); + + // Create Radio Device and interface(s): + if (!iRadio) { + TRACE_LOG((_L("XARadioSessionImpl::CreateEngine: Creating Radio Device"))); + res = (*iEngineItf)->CreateRadioDevice(iEngineItf,&iRadio, 0, NULL, NULL); + RET_ERR_IF_ERR(CheckErr(res)); + + TRACE_LOG((_L("XARadioSessionImpl::CreateEngine: Realize Radio Device"))); + res = (*iRadio)->Realize(iRadio, XA_BOOLEAN_FALSE); + RET_ERR_IF_ERR(CheckErr(res)); + + // Get Radio interface: + TRACE_LOG((_L("XARadioSessionImpl::CreateEngine: Get Radio Interface"))); + res = (*iRadio)->GetInterface(iRadio, XA_IID_RADIO, (void*)&iRadioItf); + RET_ERR_IF_ERR(CheckErr(res)); + iRadioAvailable = ETrue; + // Register Radio Callback: + TRACE_LOG((_L("XARadioSessionImpl::CreateEngine: Create Radio Callback:"))); + res = (*iRadioItf)->RegisterRadioCallback(iRadioItf, RadioCallback, (void*)this); + RET_ERR_IF_ERR(CheckErr(res)); + } + XADataSource audioSource; + XADataLocator_IODevice locatorIODevice; + XADataSink audioSink; + XADataLocator_OutputMix locator_outputmix; + + /* Init arrays required[] and iidArray[] */ + for (i = 0; i < MAX_NUMBER_INTERFACES; i++) { + required[i] = XA_BOOLEAN_FALSE; + iidArray[i] = XA_IID_NULL; + } + + iidArray[0] = XA_IID_NOKIAVOLUMEEXT; + iidArray[1] = XA_IID_NOKIALINEARVOLUME; + noOfInterfaces = 2; + + locatorIODevice.locatorType = XA_DATALOCATOR_IODEVICE; + locatorIODevice.deviceType = XA_IODEVICE_RADIO; + locatorIODevice.deviceID = 0; /* ignored */ + locatorIODevice.device = iRadio; + audioSource.pLocator = (void*) &locatorIODevice; + audioSource.pFormat = NULL; + + /* Setup the data sink structure */ + locator_outputmix.locatorType = XA_DEFAULTDEVICEID_AUDIOOUTPUT; + locator_outputmix.outputMix = NULL; + audioSink.pLocator = (void*) &locator_outputmix; + audioSink.pFormat = NULL; + + TRACE_LOG((_L("XARadioSessionImpl::CreateEngine: Create Media Player:"))); + res = (*iEngineItf)->CreateMediaPlayer(iEngineItf, &iPlayer, &audioSource, NULL, &audioSink, NULL, NULL, NULL, noOfInterfaces, iidArray, required); + RET_ERR_IF_ERR(CheckErr(res)); + + TRACE_LOG((_L("XARadioSessionImpl::CreateEngine: Realize Media Player:"))); + res = (*iPlayer)->Realize(iPlayer, XA_BOOLEAN_FALSE); + RET_ERR_IF_ERR(CheckErr(res)); + TRACE_LOG((_L("XARadioSessionImpl::CreateEngine: Get Play Interface from player:"))); + res = (*iPlayer)->GetInterface(iPlayer, XA_IID_PLAY, (void*) &iPlayItf); + RET_ERR_IF_ERR(CheckErr(res)); + TRACE_LOG((_L("XARadioSessionImpl::CreateEngine: Create PlayItf Callback:"))); + res = (*iPlayItf)->RegisterCallback(iPlayItf, PlayItfCallbackForRadio, (void*)this); + RET_ERR_IF_ERR(CheckErr(res)); + + // Get Volume Interfaces specific for Nokia impl: + TRACE_LOG((_L("XARadioSessionImpl::CreateEngine: Get NokiaVolumeExt Interface"))); + res = (*iPlayer)->GetInterface(iPlayer, XA_IID_NOKIAVOLUMEEXT, (void*)&iNokiaVolumeExtItf); + RET_ERR_IF_ERR(CheckErr(res)); + + TRACE_LOG((_L("XARadioSessionImpl::CreateEngine: Get NokiaLinearVolume Interface"))); + res = (*iPlayer)->GetInterface(iPlayer, XA_IID_NOKIALINEARVOLUME, (void*)&iNokiaLinearVolumeItf); + RET_ERR_IF_ERR(CheckErr(res)); + + // Register Volume Callbacks: + TRACE_LOG((_L("XARadioSessionImpl::CreateEngine: Create NokiaVolumeExtItf Callback:"))); + res = (*iNokiaVolumeExtItf)->RegisterVolumeCallback(iNokiaVolumeExtItf, NokiaVolumeExtItfCallback, (void*)this); + RET_ERR_IF_ERR(CheckErr(res)); + res = (*iNokiaVolumeExtItf)->SetCallbackEventsMask(iNokiaVolumeExtItf,(XA_NOKIAVOLUMEEXT_EVENT_MUTE_CHANGED)); + RET_ERR_IF_ERR(CheckErr(res)); + TRACE_LOG((_L("XARadioSessionImpl::CreateEngine: Create NokiaLinearVolumeItf Callback:"))); + res = (*iNokiaLinearVolumeItf)->RegisterVolumeCallback(iNokiaLinearVolumeItf, NokiaLinearVolumeItfCallback, (void*)this); + RET_ERR_IF_ERR(CheckErr(res)); + res = (*iNokiaLinearVolumeItf)->SetCallbackEventsMask(iNokiaLinearVolumeItf,(XA_NOKIALINEARVOLUME_EVENT_VOLUME_CHANGED)); + RET_ERR_IF_ERR(CheckErr(res)); + } + + TRACE_FUNCTION_EXIT; + return EFalse; +} + +QRadioTuner::State XARadioSessionImpl::State() const +{ + TRACE_FUNCTION_ENTRY_EXIT; + return iState; +} + +QtMultimediaKit::AvailabilityError XARadioSessionImpl::AvailabilityError() const +{ + TRACE_FUNCTION_ENTRY_EXIT; + return iAvailabilityError; +} + + bool XARadioSessionImpl::IsAvailable() const +{ + TRACE_FUNCTION_ENTRY_EXIT; + return iRadioAvailable; +} + +QRadioTuner::Band XARadioSessionImpl::Band() const +{ + TRACE_FUNCTION_ENTRY_EXIT; + return iBand; +} + +void XARadioSessionImpl::SetBand(QRadioTuner::Band band) +{ + if (band != QRadioTuner::FM) + iParent.CBError(QRadioTuner::OpenError); + else + iBand = band; +} + +bool XARadioSessionImpl::IsBandSupported(QRadioTuner::Band band) const +{ + if (band == QRadioTuner::FM) + return ETrue; + else + return EFalse; +} + +// Returns the number of Hertz to increment the frequency by when stepping through frequencies within a given band. +TInt XARadioSessionImpl::FrequencyStep(QRadioTuner::Band /*band*/) const +{ + TInt freqStep = FM_STEP; + return (int)freqStep; +} + +bool XARadioSessionImpl::IsStereo() //const +{ + bool isStereo = EFalse; + QRadioTuner::StereoMode mode = StereoMode(); + if (mode == QRadioTuner::ForceStereo || mode == QRadioTuner::Auto) + isStereo = ETrue; + return isStereo; +} + +bool XARadioSessionImpl::IsMuted() const +{ + TRACE_FUNCTION_ENTRY; + XAboolean isMuted = EFalse; + (*iNokiaVolumeExtItf)->GetMute(iNokiaVolumeExtItf, &isMuted ); + TRACE_LOG((_L("XARadioSessionImpl::IsMuted: isMuted = %d"), isMuted)); + + TRACE_FUNCTION_EXIT; + return isMuted; +} + +bool XARadioSessionImpl::IsSearching() const +{ + //iSearching is set when seek (QT:searchForward-backward) + // iSearching is cleared when SearchingStatusChanged is called or StopSeeking is called + return iSearching; +} + +TInt XARadioSessionImpl::GetFrequency() +{ + TRACE_FUNCTION_ENTRY; + + XAuint32 freq = 0; + XAresult res = (*iRadioItf)->GetFrequency(iRadioItf, &freq ); + RET_ERR_IF_ERR(CheckErr(res)); + TRACE_LOG((_L("XARadioSessionImpl::GetFrequency: Frequency = %d"), freq)); + + TRACE_FUNCTION_EXIT; + return (int)freq; +} + +TInt XARadioSessionImpl::GetFrequencyRange() +{ + TRACE_FUNCTION_ENTRY; + XAuint8 range = 0; + + XAresult res = (*iRadioItf)->GetFreqRange(iRadioItf, &range); + RET_ERR_IF_ERR(CheckErr(res)); + TRACE_LOG((_L("XARadioSessionImpl::GetFrequencyRange: Frequency Range = %d"), range)); + + TRACE_FUNCTION_EXIT; + return (int)range; +} + +TInt XARadioSessionImpl::GetFrequencyRangeProperties(TInt range, TInt &minFreq, TInt &maxFreq) +{ + TRACE_FUNCTION_ENTRY; + XAuint32 freqInterval = 0; + XAresult res = (*iRadioItf)->GetFreqRangeProperties(iRadioItf, (XAuint8)range, (XAuint32*)&minFreq,(XAuint32*)&maxFreq, (XAuint32*)&freqInterval); + RET_ERR_IF_ERR(CheckErr(res)); + TRACE_LOG((_L("XARadioSessionImpl::GetFrequencyRangeProperties: minFreq = %d, maxFreq = %d"), minFreq, maxFreq)); + + TRACE_FUNCTION_EXIT; + return res; +} + +TInt XARadioSessionImpl::SetFrequency(TInt aFreq) +{ + TRACE_FUNCTION_ENTRY; + + TRACE_LOG((_L("XARadioSessionImpl::SetFrequency: Setting Frequency to: %d"), aFreq)); + XAresult res = (*iRadioItf)->SetFrequency(iRadioItf, aFreq ); + RET_ERR_IF_ERR(CheckErr(res)); + + TRACE_FUNCTION_EXIT; + return res; +} + +QRadioTuner::StereoMode XARadioSessionImpl::StereoMode() +{ + TRACE_FUNCTION_ENTRY; + QRadioTuner::StereoMode qtStereoMode; + XAuint32 symStereoMode; + (*iRadioItf)->GetStereoMode(iRadioItf, &symStereoMode); + + if (symStereoMode == XA_STEREOMODE_MONO) + qtStereoMode = QRadioTuner::ForceMono; + else if (symStereoMode == XA_STEREOMODE_STEREO) + qtStereoMode = QRadioTuner::ForceStereo; + else + qtStereoMode = QRadioTuner::Auto; + + TRACE_FUNCTION_EXIT; + return qtStereoMode; +} + +TInt XARadioSessionImpl::SetStereoMode(QRadioTuner::StereoMode qtStereoMode) +{ + TRACE_FUNCTION_ENTRY; + XAuint32 symStereoMode; + + if (qtStereoMode == QRadioTuner::ForceMono) + symStereoMode = XA_STEREOMODE_MONO; + else if (qtStereoMode == QRadioTuner::ForceStereo) + symStereoMode = XA_STEREOMODE_STEREO; + else + symStereoMode = XA_STEREOMODE_AUTO; + + XAresult res = (*iRadioItf)->SetStereoMode(iRadioItf, (symStereoMode)); + TRACE_FUNCTION_EXIT; + return res; +} + +TInt XARadioSessionImpl::GetSignalStrength() +{ + TRACE_FUNCTION_ENTRY; + XAuint32 signalStrength = 0; + + (*iRadioItf)->GetSignalStrength(iRadioItf, &signalStrength ); + TRACE_LOG((_L("XARadioSessionImpl::GetSignalStrength: Signal Strength = %d"), signalStrength)); + TRACE_FUNCTION_EXIT; + return (int)signalStrength; +} + +TInt XARadioSessionImpl::GetVolume() +{ + TRACE_FUNCTION_ENTRY; + XAuint32 vol; + if (iPlayer && iNokiaLinearVolumeItf) { + (*iNokiaLinearVolumeItf)->GetVolumeLevel(iNokiaLinearVolumeItf, &vol ); + TRACE_LOG((_L("XARadioSessionImpl::GetVolume: Volume = %d"), vol)); + } + TRACE_FUNCTION_EXIT; + return (TInt)vol; +} + +TInt XARadioSessionImpl::SetVolume(TInt aVolume) +{ + TRACE_FUNCTION_ENTRY; + XAuint32 newVolume = 0; + TRACE_LOG((_L("XARadioSessionImpl::SetVolume: Setting volume to: %d"), aVolume)); + if (iPlayer && iNokiaLinearVolumeItf) { + newVolume = aVolume; + XAresult res = (*iNokiaLinearVolumeItf)->SetVolumeLevel(iNokiaLinearVolumeItf, &newVolume); + } + TRACE_FUNCTION_EXIT; + return (TInt)newVolume; +} + +TInt XARadioSessionImpl::SetMuted(TBool aMuted) +{ + TRACE_FUNCTION_ENTRY; + XAresult res = (*iNokiaVolumeExtItf)->SetMute(iNokiaVolumeExtItf, aMuted); + TRACE_FUNCTION_EXIT; + return res; +} + +TInt XARadioSessionImpl::Seek(TBool aDirection) +{ + TRACE_FUNCTION_ENTRY; + iSearching = true; + XAresult res = (*iRadioItf)->Seek(iRadioItf, aDirection ); + TRACE_FUNCTION_EXIT; + return res; +} + +TInt XARadioSessionImpl::StopSeeking() +{ + TRACE_FUNCTION_ENTRY; + XAresult res = (*iRadioItf)->StopSeeking(iRadioItf); + iSearching = EFalse; + TRACE_FUNCTION_EXIT; + return res; +} + +void XARadioSessionImpl::Start() +{ + TRACE_FUNCTION_ENTRY; + if (iPlayItf) { + XAresult res = (*iPlayItf)->SetPlayState(iPlayItf, XA_PLAYSTATE_PLAYING); + // add error handling if res != 0 (call errorCB) + } + TRACE_FUNCTION_EXIT; +} + +void XARadioSessionImpl::Stop() +{ + TRACE_FUNCTION_ENTRY; + if (iPlayItf) { + XAresult res = (*iPlayItf)->SetPlayState(iPlayItf, XA_PLAYSTATE_STOPPED); + // add error handling if res != 0 (call errorCB) + } + TRACE_FUNCTION_EXIT; +} + +QRadioTuner::Error XARadioSessionImpl::Error() +{ + TRACE_FUNCTION_ENTRY_EXIT; + return QRadioTuner::NoError; +} + +//TInt XARadioSessionImpl::ErrorString(); +// { +// TRACE_FUNCTION_ENTRY; + +// TRACE_FUNCTION_EXIT; +// } + +void XARadioSessionImpl::StateChanged(QRadioTuner::State state) +{ + TRACE_FUNCTION_ENTRY; + iState = state; + iParent.CBStateChanged(state); + TRACE_FUNCTION_EXIT; +} + +void XARadioSessionImpl::FrequencyChanged(XAuint32 freq) +{ + TRACE_FUNCTION_ENTRY; + iParent.CBFrequencyChanged(freq); + TRACE_FUNCTION_EXIT; +} + +void XARadioSessionImpl::SearchingChanged(TBool isSearching) +{ + TRACE_FUNCTION_ENTRY; + iSearching = EFalse; + iParent.CBSearchingChanged(isSearching); + TRACE_FUNCTION_EXIT; +} + +void XARadioSessionImpl::StereoStatusChanged(TBool stereoStatus) +{ + TRACE_FUNCTION_ENTRY; + iParent.CBStereoStatusChanged(stereoStatus); + TRACE_FUNCTION_EXIT; +} + +void XARadioSessionImpl::SignalStrengthChanged(TBool stereoStatus) +{ + TRACE_FUNCTION_ENTRY; + iParent.CBSignalStrengthChanged(stereoStatus); + TRACE_FUNCTION_EXIT; +} + +void XARadioSessionImpl::VolumeChanged() +{ + TRACE_FUNCTION_ENTRY; + int vol = 0; + iParent.CBVolumeChanged(vol); + TRACE_FUNCTION_EXIT; +} + +void XARadioSessionImpl::MutedChanged(TBool mute) +{ + TRACE_FUNCTION_ENTRY; + iParent.CBMutedChanged(mute); + TRACE_FUNCTION_EXIT; +} + +void EngineObjectCallback(XAObjectItf /*caller*/, + const void */*pContext*/, +#ifdef PLUGIN_SYMBIAN_TRACE_ENABLED + XAuint32 event, +#else + XAuint32 /*event*/, +#endif /*PLUGIN_SYMBIAN_TRACE_ENABLED*/ + XAresult /*result*/, + XAuint32 /*param*/, + void */*pInterface*/) +{ +#ifdef PLUGIN_SYMBIAN_TRACE_ENABLED + TRACE_LOG((_L("Engine object event: 0x%x\n"), (int)event)); +#endif /*PLUGIN_SYMBIAN_TRACE_ENABLED*/ +} + +void RadioCallback(XARadioItf /*caller*/, + void* pContext, + XAuint32 event, + XAuint32 eventIntData, + XAboolean eventBooleanData) +{ + XAuint32 freq; + XAboolean stereoStatus(XA_BOOLEAN_FALSE); + + switch (event) { + case XA_RADIO_EVENT_ANTENNA_STATUS_CHANGED: + TRACE_LOG((_L("RadioCallback: XA_RADIO_EVENT_ANTENNA_STATUS_CHANGED"))); + // Qt API has no callback defined for this event. + break; + case XA_RADIO_EVENT_FREQUENCY_CHANGED: + freq = eventIntData; + TRACE_LOG((_L("RadioCallback: XA_RADIO_EVENT_FREQUENCY_CHANGED to: %d"), freq)); + if (pContext) + ((XARadioSessionImpl*)pContext)->FrequencyChanged(freq); + break; + case XA_RADIO_EVENT_FREQUENCY_RANGE_CHANGED: + TRACE_LOG((_L("RadioCallback: XA_RADIO_EVENT_FREQUENCY_RANGE_CHANGED"))); + // Qt API has no callback defined for this event. + break; + case XA_RADIO_EVENT_PRESET_CHANGED: + TRACE_LOG((_L("RadioCallback: XA_RADIO_EVENT_PRESET_CHANGED"))); + // Qt API has no callback defined for this event. + break; + case XA_RADIO_EVENT_SEEK_COMPLETED: + TRACE_LOG((_L("RadioCallback: XA_RADIO_EVENT_SEEK_COMPLETED"))); + if (pContext) + ((XARadioSessionImpl*)pContext)->SearchingChanged(false); + break; + case XA_RADIO_EVENT_STEREO_STATUS_CHANGED: + stereoStatus = eventBooleanData; + TRACE_LOG((_L("RadioCallback: XA_RADIO_EVENT_STEREO_STATUS_CHANGED: %d"), stereoStatus)); + if (pContext) + ((XARadioSessionImpl*)pContext)->StereoStatusChanged(stereoStatus); + break; + case XA_RADIO_EVENT_SIGNAL_STRENGTH_CHANGED: + TRACE_LOG((_L("RadioCallback: XA_RADIO_EVENT_SIGNAL_STRENGTH_CHANGED"))); + if (pContext) + ((XARadioSessionImpl*)pContext)->SignalStrengthChanged(stereoStatus); + break; + default: + TRACE_LOG((_L("RadioCallback: default"))); + break; + } +} + +void NokiaVolumeExtItfCallback(XANokiaVolumeExtItf /*caller*/, + void* pContext, + XAuint32 event, + XAboolean eventBooleanData) +{ + XAboolean mute; + switch (event) { + case XA_NOKIAVOLUMEEXT_EVENT_MUTE_CHANGED: + mute = eventBooleanData; + TRACE_LOG((_L("NokiaVolumeExtItfCallback: XA_NOKIAVOLUMEEXT_EVENT_MUTE_CHANGED to: %d"), mute)); + if (pContext) + ((XARadioSessionImpl*)pContext)->MutedChanged(mute); + break; + default: + TRACE_LOG((_L("NokiaVolumeExtItfCallback: default"))); + break; + } +} + +void NokiaLinearVolumeItfCallback(XANokiaLinearVolumeItf /*caller*/, + void* pContext, + XAuint32 event, + XAboolean /*eventBooleanData*/) +{ + switch (event) { + case XA_NOKIALINEARVOLUME_EVENT_VOLUME_CHANGED: + if (pContext) + ((XARadioSessionImpl*)pContext)->VolumeChanged(); + break; + default: + TRACE_LOG((_L("NokiaLinearVolumeItfCallback: default"))); + break; + } +} + +void PlayItfCallbackForRadio(XAPlayItf /*caller*/, + void* pContext, + XAuint32 event) +{ + switch (event) { + case XA_PLAYEVENT_HEADMOVING: + if (pContext) + ((XARadioSessionImpl*)pContext)->StateChanged(QRadioTuner::ActiveState); + break; + case XA_PLAYEVENT_HEADSTALLED: + if (pContext) + ((XARadioSessionImpl*)pContext)->StateChanged(QRadioTuner::StoppedState); + break; + default: + TRACE_LOG((_L("NokiaLinearVolumeItfCallback: default"))); + break; + } +} + +TInt XARadioSessionImpl::CheckErr(XAresult res) +{ + TInt status(KErrGeneral); + switch(res) { + case XA_RESULT_SUCCESS: + //TRACE_LOG((_L("XA_RESULT_SUCCESS"))); + status = KErrNone; + break; + case XA_RESULT_PRECONDITIONS_VIOLATED: + TRACE_LOG((_L("XA_RESULT_PRECONDITIONS_VIOLATED"))); + break; + case XA_RESULT_PARAMETER_INVALID: + TRACE_LOG((_L("XA_RESULT_PARAMETER_INVALID"))); + break; + case XA_RESULT_MEMORY_FAILURE: + TRACE_LOG((_L("XA_RESULT_MEMORY_FAILURE"))); + iAvailabilityError = QtMultimediaKit::ResourceError; + break; + case XA_RESULT_RESOURCE_ERROR: + TRACE_LOG((_L("XA_RESULT_RESOURCE_ERROR"))); + iAvailabilityError = QtMultimediaKit::ResourceError; + break; + case XA_RESULT_RESOURCE_LOST: + TRACE_LOG((_L("XA_RESULT_RESOURCE_LOST"))); + iAvailabilityError = QtMultimediaKit::ResourceError; + break; + case XA_RESULT_IO_ERROR: + TRACE_LOG((_L("XA_RESULT_IO_ERROR"))); + break; + case XA_RESULT_BUFFER_INSUFFICIENT: + TRACE_LOG((_L("XA_RESULT_BUFFER_INSUFFICIENT"))); + break; + case XA_RESULT_CONTENT_CORRUPTED: + TRACE_LOG((_L("XA_RESULT_CONTENT_CORRUPTED"))); + break; + case XA_RESULT_CONTENT_UNSUPPORTED: + TRACE_LOG((_L("XA_RESULT_CONTENT_UNSUPPORTED"))); + break; + case XA_RESULT_CONTENT_NOT_FOUND: + TRACE_LOG((_L("XA_RESULT_CONTENT_NOT_FOUND"))); + break; + case XA_RESULT_PERMISSION_DENIED: + TRACE_LOG((_L("XA_RESULT_PERMISSION_DENIED"))); + break; + case XA_RESULT_FEATURE_UNSUPPORTED: + TRACE_LOG((_L("XA_RESULT_FEATURE_UNSUPPORTED"))); + break; + case XA_RESULT_INTERNAL_ERROR: + TRACE_LOG((_L("XA_RESULT_INTERNAL_ERROR"))); + break; + case XA_RESULT_UNKNOWN_ERROR: + TRACE_LOG((_L("XA_RESULT_UNKNOWN_ERROR"))); + break; + case XA_RESULT_OPERATION_ABORTED: + TRACE_LOG((_L("XA_RESULT_OPERATION_ABORTED"))); + break; + case XA_RESULT_CONTROL_LOST: + TRACE_LOG((_L("XA_RESULT_CONTROL_LOST"))); + break; + default: + TRACE_LOG((_L("Unknown Error!!!"))); + } + return status; +} diff --git a/src/plugins/symbian/openmaxal/radiotuner/xaradiosessionimpl.h b/src/plugins/symbian/openmaxal/radiotuner/xaradiosessionimpl.h new file mode 100644 index 000000000..ee5f53a2f --- /dev/null +++ b/src/plugins/symbian/openmaxal/radiotuner/xaradiosessionimpl.h @@ -0,0 +1,128 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** +****************************************************************************/ + +#ifndef XARADIOSESSIONIMPL_H +#define XARADIOSESSIONIMPL_H + +#include <OpenMAXAL.h> +#include <xanokialinearvolumeitf.h> +#include <xanokiavolumeextitf.h> +#include <qradiotuner.h> +#include <qtmedianamespace.h> + +QT_USE_NAMESPACE + +class XARadioSessionImplObserver; + +class XARadioSessionImpl +{ +public: + XARadioSessionImpl(XARadioSessionImplObserver& parent); + ~XARadioSessionImpl(); + QRadioTuner::Error PostConstruct(); + QRadioTuner::Band Band() const; + QRadioTuner::State State() const; + QtMultimediaKit::AvailabilityError AvailabilityError() const; + bool IsAvailable() const; + void SetBand(QRadioTuner::Band band); + bool IsBandSupported(QRadioTuner::Band band) const; + TInt FrequencyStep(QRadioTuner::Band band) const; + bool IsStereo(); //const; + bool IsMuted() const; + bool IsSearching() const; + TInt GetFrequency(); + TInt GetFrequencyRange(); + TInt GetFrequencyRangeProperties(TInt range, TInt &minFreq, TInt &maxFreq); + TInt SetFrequency(TInt aFreq); + QRadioTuner::StereoMode StereoMode(); + TInt SetStereoMode(QRadioTuner::StereoMode stereoMode); + TInt GetSignalStrength(); + TInt GetVolume(); + TInt SetVolume(TInt aVolume); + TInt SetMuted(TBool aMuted); + TInt Seek(TBool aDirection); + TInt StopSeeking(); + void Start(); + void Stop(); + QRadioTuner::Error Error(); +//TInt ErrorString(); + void StateChanged(QRadioTuner::State state); + void FrequencyChanged(XAuint32 freq); + void SearchingChanged(TBool isSearching); + void StereoStatusChanged(TBool stereoStatus); + void SignalStrengthChanged(TBool stereoStatus); + void VolumeChanged(); + void MutedChanged(TBool mute); + +private: + TInt CreateEngine(); + TInt CheckErr(XAresult res); + + +private: + XARadioSessionImplObserver& iParent; + XAObjectItf iRadio; + XAObjectItf iEngine; + XAObjectItf iPlayer; + XAEngineItf iEngineItf; + XARecordItf iRecordItf; + XAPlayItf iPlayItf; + XARadioItf iRadioItf; + XARDSItf iRdsItf; + XANokiaVolumeExtItf iNokiaVolumeExtItf; // used for mute functionality + XANokiaLinearVolumeItf iNokiaLinearVolumeItf; // used for volume functionality + + /* Audio Source */ + XADataSource iDataSource; + + /*Audio Sink*/ + XADataSink iAudioSink; + XADataLocator_OutputMix iLocator_outputmix; + + TBool iAutoFlag; + TBool iSearching; + TBool iRadioAvailable; + QtMultimediaKit::AvailabilityError iAvailabilityError; + QRadioTuner::Band iBand; + QRadioTuner::State iState; +}; + +#endif /* XARADIOSESSIONIMPL_H */ diff --git a/src/plugins/symbian/openmaxal/radiotuner/xaradiosessionimplobserver.h b/src/plugins/symbian/openmaxal/radiotuner/xaradiosessionimplobserver.h new file mode 100644 index 000000000..73c734fd3 --- /dev/null +++ b/src/plugins/symbian/openmaxal/radiotuner/xaradiosessionimplobserver.h @@ -0,0 +1,64 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** +****************************************************************************/ + +#ifndef XARADIOSESSIONIMPLOBSERVER_H +#define XARADIOSESSIONIMPLOBSERVER_H + +#include <e32base.h> +#include <qradiotuner.h> + +QT_USE_NAMESPACE + +class XARadioSessionImplObserver +{ +public: + virtual void CBStateChanged(QRadioTuner::State state) = 0; + virtual void CBBandChanged(QRadioTuner::Band band) = 0; + virtual void CBFrequencyChanged(TInt newFrequency) = 0; + virtual void CBStereoStatusChanged(bool isStereo) = 0; + virtual void CBSignalStrengthChanged(int signalStrength) = 0; + virtual void CBVolumeChanged(int volume) = 0; + virtual void CBMutedChanged(bool isMuted) = 0; + virtual void CBSearchingChanged(bool isSearching) = 0; + virtual void CBError(QRadioTuner::Error err) = 0; +}; + +#endif /*XARADIOSESSIONIMPLOBSERVER_H*/ diff --git a/src/plugins/symbian/openmaxal/xacommon.h b/src/plugins/symbian/openmaxal/xacommon.h new file mode 100644 index 000000000..9aecbc8f5 --- /dev/null +++ b/src/plugins/symbian/openmaxal/xacommon.h @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** +****************************************************************************/ + +#ifndef XACOMMON_H +#define XACOMMON_H + +#ifdef PLUGIN_SYMBIAN_TRACE_ENABLED +# include <e32debug.h> +#endif /* PLUGIN_SYMBIAN_TRACE_ENABLED */ + +#ifdef PLUGIN_SYMBIAN_TRACE_ENABLED +# define TRACE_FUNCTION_ENTRY RDebug::Printf( "%s >", __PRETTY_FUNCTION__) +# define TRACE_FUNCTION_EXIT RDebug::Printf( "%s <", __PRETTY_FUNCTION__) +# define TRACE_FUNCTION_ENTRY_EXIT RDebug::Printf( "%s ><", __PRETTY_FUNCTION__) +# define TRACE_LOG(s) RDebug::Print s +#else +# define TRACE_FUNCTION_ENTRY +# define TRACE_FUNCTION_EXIT +# define TRACE_FUNCTION_ENTRY_EXIT +# define TRACE_LOG +#endif /* PLUGIN_SYMBIAN_TRACE_ENABLED */ + +#define RET_IF_FALSE(e) \ + if (e == false) \ + { \ + return; \ + } + +#define RET_BOOL_IF_FALSE(e) \ + if (e == false) \ + { \ + return e; \ + } + +#define RET_ERR_IF_ERR(e) \ + if (e != 0) \ + { \ + return e; \ + } + +#endif /* XACOMMON_H */ diff --git a/src/plugins/symbian/symbian.pro b/src/plugins/symbian/symbian.pro new file mode 100644 index 000000000..7fc2c8690 --- /dev/null +++ b/src/plugins/symbian/symbian.pro @@ -0,0 +1,23 @@ +###################################################################### +# +# Mobility API project - Symbian backends +# +###################################################################### + +TEMPLATE = subdirs + +include (../../../config.pri) + +# The openmax-al backend is currently not supported +# we include mmf only if we are not building openmaxal based backend +#contains(openmaxal_symbian_enabled, no) { +# message("Enabling mmf mediarecording, playback and radio backend") +# symbian:SUBDIRS += mmf +# +#else { +# message("Enabling OpenMAX AL audio record, playback and radio backend") +# symbian:SUBDIRS += openmaxal +# + +symbian:SUBDIRS += ecam mmf + diff --git a/src/plugins/symbian/videooutput/s60videodisplay.cpp b/src/plugins/symbian/videooutput/s60videodisplay.cpp new file mode 100644 index 000000000..35e234e98 --- /dev/null +++ b/src/plugins/symbian/videooutput/s60videodisplay.cpp @@ -0,0 +1,179 @@ +/**************************************************************************** +** +** Copyright (C) 2011 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 "s60videodisplay.h" +#include <QtGui/QApplication> +#include <QtGui/QDesktopWidget> +#include <coecntrl.h> +#include <w32std.h> + +S60VideoDisplay::S60VideoDisplay(QObject *parent) +: QObject(parent) +, m_fullScreen(false) +, m_visible(true) +, m_aspectRatioMode(Qt::KeepAspectRatio) +, m_paintingEnabled(false) +, m_rotation(0.0f) +{ + connect(this, SIGNAL(displayRectChanged(QRect, QRect)), + this, SLOT(updateContentRect())); + connect(this, SIGNAL(nativeSizeChanged(QSize)), + this, SLOT(updateContentRect())); +} + +S60VideoDisplay::~S60VideoDisplay() +{ + +} + +RWindow *S60VideoDisplay::windowHandle() const +{ + return winId() ? static_cast<RWindow *>(winId()->DrawableWindow()) : 0; +} + +QRect S60VideoDisplay::clipRect() const +{ + QRect displayableRect; +#ifdef VIDEOOUTPUT_GRAPHICS_SURFACES + if (RWindow *window = windowHandle()) + displayableRect = QRect(0, 0, window->Size().iWidth, window->Size().iHeight); +#else + displayableRect = QApplication::desktop()->screenGeometry(); +#endif + return extentRect().intersected(displayableRect); +} + +QRect S60VideoDisplay::contentRect() const +{ + return m_contentRect; +} + +void S60VideoDisplay::setFullScreen(bool enabled) +{ + if (m_fullScreen != enabled) { + m_fullScreen = enabled; + emit fullScreenChanged(m_fullScreen); + } +} + +bool S60VideoDisplay::isFullScreen() const +{ + return m_fullScreen; +} + +void S60VideoDisplay::setVisible(bool enabled) +{ + if (m_visible != enabled) { + m_visible = enabled; + emit visibilityChanged(m_visible); + } +} + +bool S60VideoDisplay::isVisible() const +{ + return m_visible; +} + +void S60VideoDisplay::setAspectRatioMode(Qt::AspectRatioMode mode) +{ + if (m_aspectRatioMode != mode) { + m_aspectRatioMode = mode; + emit aspectRatioModeChanged(m_aspectRatioMode); + } +} + +Qt::AspectRatioMode S60VideoDisplay::aspectRatioMode() const +{ + return m_aspectRatioMode; +} + +void S60VideoDisplay::setNativeSize(const QSize &size) +{ + if (m_nativeSize != size) { + m_nativeSize = size; + emit nativeSizeChanged(m_nativeSize); + } +} + +const QSize& S60VideoDisplay::nativeSize() const +{ + return m_nativeSize; +} + +void S60VideoDisplay::setPaintingEnabled(bool enabled) +{ + if (m_paintingEnabled != enabled) { + m_paintingEnabled = enabled; + emit paintingEnabledChanged(m_paintingEnabled); + } +} + +bool S60VideoDisplay::isPaintingEnabled() const +{ + return m_paintingEnabled; +} + +void S60VideoDisplay::setRotation(qreal value) +{ + if (value != m_rotation) { + m_rotation = value; + emit rotationChanged(m_rotation); + } +} + +qreal S60VideoDisplay::rotation() const +{ + return m_rotation; +} + +void S60VideoDisplay::updateContentRect() +{ + if (isPaintingEnabled()) { + const int dx = qMax(0, extentRect().width() - nativeSize().width()); + const int dy = qMax(0, extentRect().height() - nativeSize().height()); + QRect contentRect(QPoint(dx/2, dy/2), nativeSize()); + if (m_contentRect != contentRect) { + m_contentRect = contentRect; + emit contentRectChanged(m_contentRect); + } + } +} + diff --git a/src/plugins/symbian/videooutput/s60videodisplay.h b/src/plugins/symbian/videooutput/s60videodisplay.h new file mode 100644 index 000000000..e16e7bb71 --- /dev/null +++ b/src/plugins/symbian/videooutput/s60videodisplay.h @@ -0,0 +1,188 @@ +/** +** Copyright (C) 2011 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$ +** +****************************************************************************/ + +#ifndef S60VIDEODISPLAY_H +#define S60VIDEODISPLAY_H + +#include <QtCore/QMetaType> +#include <QtCore/QObject> +#include <QtCore/QRect> +#include <QtCore/QSize> +#include <QtGui/qwindowdefs.h> + +class CFbsBitmap; +class RWindow; + +QT_USE_NAMESPACE + +/* + * This class defines a common API used by Symbian camera and mediaplayer + * backends to render to on-screen video outputs, i.e. implementations of + * QVideoWidgetControl and QVideoWindowControl. + */ +class S60VideoDisplay : public QObject +{ + Q_OBJECT +public: + S60VideoDisplay(QObject *parent); + virtual ~S60VideoDisplay(); + + /* + * Returns native Symbian handle of the window to be used for rendering + */ + RWindow *windowHandle() const; + + /* + * Returns Qt WId (CCoeControl* on Symbian) + */ + virtual WId winId() const = 0; + + /* + * Returns video display rectangle + * + * This is the rectangle which includes both the video content itself, plus + * any border bars which added around the video. The aspect ratio of this + * rectangle therefore may differ from that of the nativeSize(). + * + * If running on a platform supporting video rendering to graphics + * surfaces (i.e. if VIDEOOUTPUT_GRAPHICS_SURFACES is defined), the return + * value is the relative to the origin of the video window. Otherwise, the + * return value is an absolute screen rectangle. + * + * Note that this rectangle can extend beyond the bounds of the screen or of + * the video window. + * + * When using QVideoWindowControl, the size of the extentRect matches the + * displayRect; if running on a platform which supports only DSA rendering, + * the origin differs as described above. + * + * See also clipRect, contentRect + */ + virtual QRect extentRect() const = 0; + + /* + * Returns video clipping rectangle + * + * This rectangle is the intersection of displayRect() with either the window + * rectangle (on platforms supporting video rendering to graphics surfaces), + * or the screen rectangle (on platforms supporting only DSA video rendering). + * + * If running on a platform supporting video rendering to graphics + * surfaces (i.e. if VIDEOOUTPUT_GRAPHICS_SURFACES is defined), the return + * value is the relative to the origin of the video window. Otherwise, the + * return value is an absolute screen rectangle. + * + * See also extentRect, contentRect + */ + QRect clipRect() const; + + /* + * Returns video content rectangle + * + * This is the rectangle in which the video content is rendered, i.e. its + * size is that of extentRect() minus border bars. The aspect ratio of this + * rectangle is therefore equal to that of the nativeSize(). + * + * This rectangle is always relative to the window in which video is rendered. + * + * See also extentRect, clipRect + */ + QRect contentRect() const; + + void setFullScreen(bool enabled); + bool isFullScreen() const; + + void setVisible(bool visible); + bool isVisible() const; + + void setAspectRatioMode(Qt::AspectRatioMode mode); + Qt::AspectRatioMode aspectRatioMode() const; + + const QSize& nativeSize() const; + + void setPaintingEnabled(bool enabled); + bool isPaintingEnabled() const; + + void setRotation(qreal value); + qreal rotation() const; + +public slots: + void setNativeSize(const QSize &size); + + /* + * Provide new video frame + * + * If setPaintingEnabled(true) has been called, the frame is rendered to + * the display. + * + * If a QWidget is available to the control (i.e. the control is a + * QVideoWidgetControl), the frame is rendered via QPainter. Otherwise, the + * frame is blitted to the window using native Symbian drawing APIs. + */ + virtual void setFrame(const CFbsBitmap &bitmap) = 0; + +signals: + void windowHandleChanged(RWindow *); + void displayRectChanged(QRect extentRect, QRect clipRect); + void fullScreenChanged(bool); + void visibilityChanged(bool); + void aspectRatioModeChanged(Qt::AspectRatioMode); + void nativeSizeChanged(QSize); + void contentRectChanged(QRect); + void paintingEnabledChanged(bool); + void rotationChanged(qreal); + void beginVideoWindowNativePaint(); + void endVideoWindowNativePaint(); + +private slots: + void updateContentRect(); + +private: + QRect m_contentRect; + bool m_fullScreen; + bool m_visible; + Qt::AspectRatioMode m_aspectRatioMode; + QSize m_nativeSize; + bool m_paintingEnabled; + qreal m_rotation; +}; + +#endif // S60VIDEODISPLAY_H + diff --git a/src/plugins/symbian/videooutput/s60videooutpututils.cpp b/src/plugins/symbian/videooutput/s60videooutpututils.cpp new file mode 100644 index 000000000..feac346d1 --- /dev/null +++ b/src/plugins/symbian/videooutput/s60videooutpututils.cpp @@ -0,0 +1,119 @@ +/**************************************************************************** +** +** Copyright (C) 2011 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 "s60videooutpututils.h" + +#ifdef PRIVATE_QTGUI_HEADERS_AVAILABLE +#if QT_VERSION >= 0x040601 && !defined(__WINSCW__) +#include <QtGui/private/qt_s60_p.h> +#include <QtGui/private/qwidget_p.h> +#define USE_PRIVATE_QTGUI_APIS +#endif // QT_VERSION >= 0x040601 && !defined(__WINSCW__) +#endif // PRIVATE_QTGUI_HEADERS_AVAILABLE + +namespace S60VideoOutputUtils +{ + +void setIgnoreFocusChanged(QWidget *widget) +{ +#ifdef USE_PRIVATE_QTGUI_APIS + // Warning: if this flag is not set, the application may crash due to + // CGraphicsContext being called from within the context of + // QGraphicsVideoItem::paint(), when the video widget is shown. + static_cast<QSymbianControl *>(widget->winId())->setIgnoreFocusChanged(true); +#else + Q_UNUSED(widget) +#endif +} + +void setNativePaintMode(QWidget *widget, NativePaintMode mode) +{ +#ifdef USE_PRIVATE_QTGUI_APIS + QWidgetPrivate *widgetPrivate = qt_widget_private(widget->window()); + widgetPrivate->createExtra(); + QWExtra::NativePaintMode widgetMode = QWExtra::Default; + switch (mode) { + case Default: + break; + case ZeroFill: + widgetMode = QWExtra::ZeroFill; + break; + case BlitWriteAlpha: +#if QT_VERSION >= 0x040704 + widgetMode = QWExtra::BlitWriteAlpha; +#endif + break; + case Disable: + widgetMode = QWExtra::Disable; + break; + } + widgetPrivate->extraData()->nativePaintMode = widgetMode; +#else + Q_UNUSED(widget) + Q_UNUSED(mode) +#endif +} + +void setNativePaintMode(WId wid, NativePaintMode mode) +{ +#ifdef USE_PRIVATE_QTGUI_APIS + QWidget *window = static_cast<QSymbianControl *>(wid)->widget()->window(); + setNativePaintMode(window, mode); +#else + Q_UNUSED(wid) + Q_UNUSED(mode) +#endif +} + +void setReceiveNativePaintEvents(QWidget *widget, bool enabled) +{ +#ifdef USE_PRIVATE_QTGUI_APIS + QWidgetPrivate *widgetPrivate = qt_widget_private(widget); + widgetPrivate->createExtra(); + widgetPrivate->extraData()->receiveNativePaintEvents = enabled; +#else + Q_UNUSED(widget) + Q_UNUSED(enabled) +#endif +} + +} // namespace S60VideoOutputUtils + diff --git a/src/plugins/symbian/videooutput/s60videooutpututils.h b/src/plugins/symbian/videooutput/s60videooutpututils.h new file mode 100644 index 000000000..6d83062c3 --- /dev/null +++ b/src/plugins/symbian/videooutput/s60videooutpututils.h @@ -0,0 +1,71 @@ +/** +** Copyright (C) 2011 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$ +** +****************************************************************************/ + +#ifndef S60VIDEOOUTPUTUTILS_H +#define S60VIDEOOUTPUTUTILS_H + +#include <QtCore/qglobal.h> +#include <QtGui/qwindowdefs.h> + +QT_FORWARD_DECLARE_CLASS(QWidget) + +/* + * Helper functions used by video output. + */ +namespace S60VideoOutputUtils +{ + +enum NativePaintMode +{ + Default, + ZeroFill, + BlitWriteAlpha, + Disable +}; + +void setIgnoreFocusChanged(QWidget *widget); +void setNativePaintMode(QWidget *widget, NativePaintMode mode); +void setNativePaintMode(WId wid, NativePaintMode mode); +void setReceiveNativePaintEvents(QWidget *widget, bool enabled); + +} // namespace S60VideoOutputUtils + +#endif // S60VIDEOOUTPUTUTILS_H + diff --git a/src/plugins/symbian/videooutput/s60videowidget.cpp b/src/plugins/symbian/videooutput/s60videowidget.cpp new file mode 100644 index 000000000..44c0919ba --- /dev/null +++ b/src/plugins/symbian/videooutput/s60videowidget.cpp @@ -0,0 +1,237 @@ +/**************************************************************************** +** +** Copyright (C) 2011 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 "s60videowidget.h" +#include "s60videooutpututils.h" + +#include <QtCore/QVariant> +#include <QtCore/QEvent> +#include <QtGui/QApplication> +#include <QtGui/QPainter> + +#include <coemain.h> // CCoeEnv +#include <coecntrl.h> // CCoeControl +#include <w32std.h> + +using namespace S60VideoOutputUtils; + +const int NullOrdinalPosition = -1; + +S60VideoWidget::S60VideoWidget(QWidget *parent) +: QWidget(parent) +, m_pixmap(NULL) +, m_paintingEnabled(false) +, m_topWinId(0) +, m_ordinalPosition(NullOrdinalPosition) +{ + setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + setPalette(QPalette(Qt::black)); + setAutoFillBackground(false); + if (!parent) + setProperty("_q_DummyWindowSurface", true); + S60VideoOutputUtils::setIgnoreFocusChanged(this); +} + +S60VideoWidget::~S60VideoWidget() +{ + +} + +bool S60VideoWidget::event(QEvent *event) +{ + if (event->type() == QEvent::WinIdChange) + updateOrdinalPosition(); + return QWidget::event(event); +} + +void S60VideoWidget::paintEvent(QPaintEvent *event) +{ + if (m_paintingEnabled && m_pixmap) { + QPainter painter(this); + if (m_pixmap->size() != m_contentRect.size()) + qWarning("pixmap size does not match expected value"); + painter.drawPixmap(m_contentRect.topLeft(), *m_pixmap); + } +} + +void S60VideoWidget::setVisible(bool visible) +{ + queueReactivateWindow(); + QWidget::setVisible(visible); +} + + +WId S60VideoWidget::videoWinId() const +{ + WId wid = 0; + if (internalWinId()) + wid = internalWinId(); + else if (parentWidget() && effectiveWinId()) + wid = effectiveWinId(); + return wid; +} + +void S60VideoWidget::setPixmap(const QPixmap *pixmap) +{ + m_pixmap = pixmap; + update(); +} + +void S60VideoWidget::setContentRect(const QRect &rect) +{ + if (m_contentRect != rect) { + m_contentRect = rect; + update(); + } +} + +void S60VideoWidget::setWindowBackgroundColor() +{ + if (WId wid = internalWinId()) + static_cast<RWindow *>(wid->DrawableWindow())->SetBackgroundColor(TRgb(0, 0, 0, 255)); +} + +WId S60VideoWidget::topWinId() const +{ + return m_topWinId; +} + +void S60VideoWidget::setTopWinId(WId id) +{ + m_topWinId = id; + updateOrdinalPosition(); +#ifdef VIDEOOUTPUT_GRAPHICS_SURFACES + // This function may be called from a paint event, so defer any window + // manipulation until painting is complete. + QMetaObject::invokeMethod(this, "setWindowsNonFading", Qt::QueuedConnection); +#endif +} + +void S60VideoWidget::setOrdinalPosition(int ordinalPosition) +{ + m_ordinalPosition = ordinalPosition; + updateOrdinalPosition(); +} + +int S60VideoWidget::ordinalPosition() const +{ + return m_ordinalPosition; +} + +void S60VideoWidget::updateOrdinalPosition() +{ + if ((m_ordinalPosition != NullOrdinalPosition) && m_topWinId) { + if (WId wid = videoWinId()) { + int topOrdinalPosition = m_topWinId->DrawableWindow()->OrdinalPosition(); + queueReactivateWindow(); + wid->DrawableWindow()->SetOrdinalPosition(m_ordinalPosition + topOrdinalPosition); + } + } +} + +void S60VideoWidget::queueReactivateWindow() +{ + if (!parent()) { + if (QWidget *activeWindow = QApplication::activeWindow()) + QMetaObject::invokeMethod(this, "reactivateWindow", Qt::QueuedConnection, + Q_ARG(QWidget *, activeWindow)); + } +} + +void S60VideoWidget::reactivateWindow(QWidget *widget) +{ + widget->activateWindow(); +} + +void S60VideoWidget::setWindowsNonFading() +{ + winId()->DrawableWindow()->SetNonFading(ETrue); + if (m_topWinId) + m_topWinId->DrawableWindow()->SetNonFading(ETrue); +} + +void S60VideoWidget::beginNativePaintEvent(const QRect &rect) +{ + Q_UNUSED(rect) + emit beginVideoWidgetNativePaint(); +} + +void S60VideoWidget::endNativePaintEvent(const QRect &rect) +{ + Q_UNUSED(rect) + CCoeEnv::Static()->WsSession().Flush(); + emit endVideoWidgetNativePaint(); +} + +void S60VideoWidget::setPaintingEnabled(bool enabled) +{ + if (enabled) { +#ifndef VIDEOOUTPUT_GRAPHICS_SURFACES + setAttribute(Qt::WA_OpaquePaintEvent, false); + setAttribute(Qt::WA_NoSystemBackground, false); + S60VideoOutputUtils::setReceiveNativePaintEvents(this, false); + S60VideoOutputUtils::setNativePaintMode(this, Default); +#else + S60VideoOutputUtils::setNativePaintMode(this, Default); +#endif // !VIDEOOUTPUT_GRAPHICS_SURFACES + } else { +#ifndef VIDEOOUTPUT_GRAPHICS_SURFACES + setAttribute(Qt::WA_OpaquePaintEvent, true); + setAttribute(Qt::WA_NoSystemBackground, true); + S60VideoOutputUtils::setReceiveNativePaintEvents(this, true); + S60VideoOutputUtils::setNativePaintMode(this, ZeroFill); +#else + S60VideoOutputUtils::setNativePaintMode(this, Disable); +#endif // !VIDEOOUTPUT_GRAPHICS_SURFACES + winId(); // Create native window handle + } + m_paintingEnabled = enabled; + setWindowBackgroundColor(); +} + +void S60VideoWidget::setFullScreen(bool enabled) +{ + if (enabled) + showFullScreen(); + else + showMaximized(); +} + diff --git a/src/plugins/symbian/videooutput/s60videowidget.h b/src/plugins/symbian/videooutput/s60videowidget.h new file mode 100644 index 000000000..30e7a3bd0 --- /dev/null +++ b/src/plugins/symbian/videooutput/s60videowidget.h @@ -0,0 +1,97 @@ +/**************************************************************************** +** +** Copyright (C) 2011 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$ +** +****************************************************************************/ + +#ifndef S60VIDEOWIDGET_H +#define S60VIDEOWIDGET_H + +#include <QtGui/QWidget> + +QT_USE_NAMESPACE + +class S60VideoWidget : public QWidget +{ + Q_OBJECT +public: + S60VideoWidget(QWidget *parent = 0); + ~S60VideoWidget(); + + // QWidget + bool event(QEvent *event); + void paintEvent(QPaintEvent *event); + void setVisible(bool visible); + + WId videoWinId() const; + void setPixmap(const QPixmap *pixmap); + void setWindowBackgroundColor(); + void setTopWinId(WId id); + WId topWinId() const; + void setOrdinalPosition(int ordinalPosition); + int ordinalPosition() const; + +public slots: + void beginNativePaintEvent(const QRect &rect); + void endNativePaintEvent(const QRect &rect); + void setPaintingEnabled(bool enabled); + void setFullScreen(bool enabled); + void setContentRect(const QRect &rect); + +signals: + void beginVideoWidgetNativePaint(); + void endVideoWidgetNativePaint(); + +private: + void updateOrdinalPosition(); + void queueReactivateWindow(); + +private slots: + void reactivateWindow(QWidget *window); + void setWindowsNonFading(); + +private: + const QPixmap *m_pixmap; + QRect m_contentRect; + bool m_paintingEnabled; + WId m_topWinId; + int m_ordinalPosition; +}; + +#endif // S60VIDEOWIDGET_H + diff --git a/src/plugins/symbian/videooutput/s60videowidgetcontrol.cpp b/src/plugins/symbian/videooutput/s60videowidgetcontrol.cpp new file mode 100644 index 000000000..46cb2963e --- /dev/null +++ b/src/plugins/symbian/videooutput/s60videowidgetcontrol.cpp @@ -0,0 +1,171 @@ +/**************************************************************************** +** +** Copyright (C) 2011 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 "s60videowidgetcontrol.h" +#include "s60videowidgetdisplay.h" + +S60VideoWidgetControl::S60VideoWidgetControl(QObject *parent) +: QVideoWidgetControl(parent) +, m_display(new S60VideoWidgetDisplay(this)) +{ + connect(m_display, SIGNAL(nativeSizeChanged(QSize)), + this, SIGNAL(nativeSizeChanged())); +} + +S60VideoWidgetControl::~S60VideoWidgetControl() +{ + +} + +QWidget *S60VideoWidgetControl::videoWidget() +{ + return m_display->widget(); +} + +Qt::AspectRatioMode S60VideoWidgetControl::aspectRatioMode() const +{ + return m_display->aspectRatioMode(); +} + +void S60VideoWidgetControl::setAspectRatioMode(Qt::AspectRatioMode ratio) +{ + m_display->setAspectRatioMode(ratio); +} + +bool S60VideoWidgetControl::isFullScreen() const +{ + return m_display->isFullScreen(); +} + +void S60VideoWidgetControl::setFullScreen(bool fullScreen) +{ + m_display->setFullScreen(fullScreen); +} + +int S60VideoWidgetControl::brightness() const +{ + return 0; +} + +void S60VideoWidgetControl::setBrightness(int brightness) +{ + Q_UNUSED(brightness); +} + +int S60VideoWidgetControl::contrast() const +{ + return 0; +} + +void S60VideoWidgetControl::setContrast(int contrast) +{ + Q_UNUSED(contrast); +} + +int S60VideoWidgetControl::hue() const +{ + return 0; +} + +void S60VideoWidgetControl::setHue(int hue) +{ + Q_UNUSED(hue); +} + +int S60VideoWidgetControl::saturation() const +{ + return 0; +} + +void S60VideoWidgetControl::setSaturation(int saturation) +{ + Q_UNUSED(saturation); +} + +S60VideoWidgetDisplay *S60VideoWidgetControl::display() const +{ + return m_display; +} + +void S60VideoWidgetControl::setTopWinId(WId id) +{ + m_display->setTopWinId(id); +} + +WId S60VideoWidgetControl::topWinId() const +{ + return m_display->topWinId(); +} + +int S60VideoWidgetControl::ordinalPosition() const +{ + return m_display->ordinalPosition(); +} + +void S60VideoWidgetControl::setOrdinalPosition(int ordinalPosition) +{ + m_display->setOrdinalPosition(ordinalPosition); +} + +const QRect &S60VideoWidgetControl::extentRect() const +{ + return m_display->explicitExtentRect(); +} + +void S60VideoWidgetControl::setExtentRect(const QRect &rect) +{ + m_display->setExplicitExtentRect(rect); +} + +QSize S60VideoWidgetControl::nativeSize() const +{ + return m_display->nativeSize(); +} + +qreal S60VideoWidgetControl::rotation() const +{ + return m_display->rotation(); +} + +void S60VideoWidgetControl::setRotation(qreal value) +{ + m_display->setRotation(value); +} diff --git a/src/plugins/symbian/videooutput/s60videowidgetcontrol.h b/src/plugins/symbian/videooutput/s60videowidgetcontrol.h new file mode 100644 index 000000000..eb103b6b8 --- /dev/null +++ b/src/plugins/symbian/videooutput/s60videowidgetcontrol.h @@ -0,0 +1,131 @@ +/**************************************************************************** +** +** Copyright (C) 2011 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$ +** +****************************************************************************/ + +#ifndef S60VIDEOWIDGETCONTROL_H +#define S60VIDEOWIDGETCONTROL_H + +#include <qvideowidgetcontrol.h> + +QT_USE_NAMESPACE + +class S60VideoWidgetDisplay; + +class S60VideoWidgetControl : public QVideoWidgetControl +{ + Q_OBJECT + + /** + * WId of the topmost window in the application, used to calculate the + * absolute ordinal position of the video widget. + * This is used by the "window" implementation of QGraphicsVideoItem. + */ + Q_PROPERTY(WId topWinId READ topWinId WRITE setTopWinId) + + /** + * Ordinal position of the video widget, relative to the topmost window + * in the application. If both the topWinId property and the ordinalPosition + * property are set, the absolute ordinal position of the video widget is + * the sum of the topWinId ordinal position and the value of the + * ordinalPosition property. + * This is used by the "window" implementation of QGraphicsVideoItem. + */ + Q_PROPERTY(int ordinalPosition READ ordinalPosition WRITE setOrdinalPosition) + + /** + * Extent of the video, relative to this video widget. + * This is used by the "window" implementation of QGraphicsVideoItem. + */ + Q_PROPERTY(QRect extentRect READ extentRect WRITE setExtentRect) + + /** + * Native size of video. + * This is used by the "window" implementation of QGraphicsVideoItem. + */ + Q_PROPERTY(QSize nativeSize READ nativeSize) + + /** + * Rotation to be applied to video. + * Angle is measured in degrees, with positive values counter-clockwise. + * Zero is at 12 o'clock. + */ + Q_PROPERTY(qreal rotation READ rotation WRITE setRotation) + +public: + S60VideoWidgetControl(QObject *parent); + ~S60VideoWidgetControl(); + +public: + // QVideoWidgetControl + QWidget *videoWidget(); + Qt::AspectRatioMode aspectRatioMode() const; + void setAspectRatioMode(Qt::AspectRatioMode ratio); + bool isFullScreen() const; + void setFullScreen(bool fullScreen); + int brightness() const; + void setBrightness(int brightness); + int contrast() const; + void setContrast(int contrast); + int hue() const; + void setHue(int hue); + int saturation() const; + void setSaturation(int saturation); + + S60VideoWidgetDisplay *display() const; + + WId topWinId() const; + void setTopWinId(WId id); + int ordinalPosition() const; + void setOrdinalPosition(int ordinalPosition); + const QRect &extentRect() const; + void setExtentRect(const QRect &rect); + QSize nativeSize() const; + qreal rotation() const; + void setRotation(qreal value); + +signals: + void nativeSizeChanged(); + +private: + S60VideoWidgetDisplay *m_display; +}; + +#endif // S60VIDEOWIDGETCONTROL_H + diff --git a/src/plugins/symbian/videooutput/s60videowidgetdisplay.cpp b/src/plugins/symbian/videooutput/s60videowidgetdisplay.cpp new file mode 100644 index 000000000..de7440dbf --- /dev/null +++ b/src/plugins/symbian/videooutput/s60videowidgetdisplay.cpp @@ -0,0 +1,174 @@ +/**************************************************************************** +** +** Copyright (C) 2011 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 "s60videowidget.h" +#include "s60videowidgetdisplay.h" +#include <QtCore/QEvent> +#include <QtCore/QVariant> +#include <fbs.h> +#include <w32std.h> + +S60VideoWidgetDisplay::S60VideoWidgetDisplay(QObject *parent) +: S60VideoDisplay(parent) +, m_widget(new S60VideoWidget) +{ + connect(this, SIGNAL(paintingEnabledChanged(bool)), m_widget, SLOT(setPaintingEnabled(bool))); + connect(this, SIGNAL(fullScreenChanged(bool)), m_widget, SLOT(setFullScreen(bool))); + connect(this, SIGNAL(contentRectChanged(const QRect&)), m_widget, SLOT(setContentRect(const QRect &))); +#ifndef VIDEOOUTPUT_GRAPHICS_SURFACES + connect(m_widget, SIGNAL(beginVideoWidgetNativePaint()), this, SIGNAL(beginVideoWindowNativePaint())); + connect(m_widget, SIGNAL(endVideoWidgetNativePaint()), this, SIGNAL(endVideoWindowNativePaint())); +#endif + m_widget->installEventFilter(this); + m_widget->setPaintingEnabled(false); +} + +S60VideoWidgetDisplay::~S60VideoWidgetDisplay() +{ + // Notify observers that window is about to be destroyed + QScopedPointer<QWidget> widget(m_widget); + m_widget = 0; + emit windowHandleChanged(windowHandle()); + // Widget will be deleted by QScopedPointer +} + +bool S60VideoWidgetDisplay::eventFilter(QObject *object, QEvent *e) +{ + if (object == m_widget) { + switch (e->type()) { + case QEvent::ParentChange: + if (QWidget *parent = m_widget->parentWidget()) + parent->setProperty("_q_DummyWindowSurface", true); + break; + case QEvent::WinIdChange: + m_widget->setWindowBackgroundColor(); + emit windowHandleChanged(windowHandle()); + break; + case QEvent::Resize: + emit displayRectChanged(extentRect(), clipRect()); + break; +#ifndef VIDEOOUTPUT_GRAPHICS_SURFACES + case QEvent::Move: + // TODO: this is insufficient - we also need to respond to changes in + // the position of ancestor widgets + emit displayRectChanged(extentRect(), clipRect()); + break; +#endif + case QEvent::Show: + emit windowHandleChanged(windowHandle()); + emit visibilityChanged(true); + break; + case QEvent::Hide: + emit visibilityChanged(false); + break; + default: + // Do nothing + break; + } + } + return false; +} + +WId S60VideoWidgetDisplay::winId() const +{ + return m_widget ? m_widget->videoWinId() : 0; +} + +QRect S60VideoWidgetDisplay::extentRect() const +{ + QRect rect; + if (const RWindow *window = windowHandle()) { + const TSize size = window ? window->Size() : TSize(); + if (m_explicitExtentRect.isValid()) + rect = m_explicitExtentRect; + else + rect = QRect(0, 0, size.iWidth, size.iHeight); +#ifndef VIDEOOUTPUT_GRAPHICS_SURFACES + const TPoint pos = window ? window->AbsPosition() : TPoint(); + rect.moveTopLeft(QPoint(pos.iX, pos.iY)); +#endif + } + return rect; +} + +void S60VideoWidgetDisplay::setFrame(const CFbsBitmap &bitmap) +{ + m_pixmap = QPixmap::fromSymbianCFbsBitmap(const_cast<CFbsBitmap*>(&bitmap)); + m_widget->setPixmap(&m_pixmap); +} + +QWidget *S60VideoWidgetDisplay::widget() const +{ + return m_widget; +} + +void S60VideoWidgetDisplay::setTopWinId(WId id) +{ + m_widget->setTopWinId(id); +} + +WId S60VideoWidgetDisplay::topWinId() const +{ + return m_widget->topWinId(); +} + +void S60VideoWidgetDisplay::setOrdinalPosition(int ordinalPosition) +{ + m_widget->setOrdinalPosition(ordinalPosition); +} + +int S60VideoWidgetDisplay::ordinalPosition() const +{ + return m_widget->ordinalPosition(); +} + +const QRect &S60VideoWidgetDisplay::explicitExtentRect() const +{ + return m_explicitExtentRect; +} + +void S60VideoWidgetDisplay::setExplicitExtentRect(const QRect &rect) +{ + if (rect != m_explicitExtentRect) { + m_explicitExtentRect = rect; + emit displayRectChanged(extentRect(), clipRect()); + } +} diff --git a/src/plugins/symbian/videooutput/s60videowidgetdisplay.h b/src/plugins/symbian/videooutput/s60videowidgetdisplay.h new file mode 100644 index 000000000..d3d92d953 --- /dev/null +++ b/src/plugins/symbian/videooutput/s60videowidgetdisplay.h @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** Copyright (C) 2011 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$ +** +****************************************************************************/ + +#ifndef S60VIDEOWIDGETDISPLAY_H +#define S60VIDEOWIDGETDISPLAY_H + +#include "s60videodisplay.h" +#include <QtGui/qwindowdefs.h> +#include <QtGui/QPixmap> + +class CFbsBitmap; +class S60VideoWidget; +class QWidget; + +QT_USE_NAMESPACE + +class S60VideoWidgetDisplay : public S60VideoDisplay +{ + Q_OBJECT +public: + S60VideoWidgetDisplay(QObject *parent); + ~S60VideoWidgetDisplay(); + + // QObject + bool eventFilter(QObject *object, QEvent *e); + + // S60VideoDisplay + WId winId() const; + QRect extentRect() const; + void setFrame(const CFbsBitmap &bitmap); + + QWidget *widget() const; + WId topWinId() const; + void setTopWinId(WId id); + void setOrdinalPosition(int ordinalPosition); + int ordinalPosition() const; + const QRect &explicitExtentRect() const; + void setExplicitExtentRect(const QRect &rect); + +private: + S60VideoWidget *m_widget; + QPixmap m_pixmap; + QRect m_explicitExtentRect; +}; + +#endif // S60VIDEOWIDGETDISPLAY_H + diff --git a/src/plugins/symbian/videooutput/s60videowindowcontrol.cpp b/src/plugins/symbian/videooutput/s60videowindowcontrol.cpp new file mode 100644 index 000000000..db33a5f32 --- /dev/null +++ b/src/plugins/symbian/videooutput/s60videowindowcontrol.cpp @@ -0,0 +1,178 @@ +/**************************************************************************** +** +** Copyright (C) 2011 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 "s60videowindowcontrol.h" +#include "s60videowindowdisplay.h" + +S60VideoWindowControl::S60VideoWindowControl(QObject *parent) +: QVideoWindowControl(parent) +, m_display(new S60VideoWindowDisplay(this)) +{ + connect(m_display, SIGNAL(nativeSizeChanged(QSize)), + this, SIGNAL(nativeSizeChanged())); + connect(m_display, SIGNAL(fullScreenChanged(bool)), + this, SIGNAL(fullScreenChanged(bool))); +} + +S60VideoWindowControl::~S60VideoWindowControl() +{ + +} + +WId S60VideoWindowControl::winId() const +{ + return m_display->winId(); +} + +void S60VideoWindowControl::setWinId(WId id) +{ + m_display->setWinId(id); +} + +QRect S60VideoWindowControl::displayRect() const +{ + return m_display->displayRect(); +} + +void S60VideoWindowControl::setDisplayRect(const QRect &rect) +{ + m_display->setDisplayRect(rect); +} + +Qt::AspectRatioMode S60VideoWindowControl::aspectRatioMode() const +{ + return m_display->aspectRatioMode(); +} + +void S60VideoWindowControl::setAspectRatioMode(Qt::AspectRatioMode ratio) +{ + m_display->setAspectRatioMode(ratio); +} + +QSize S60VideoWindowControl::customAspectRatio() const +{ + return QSize(); +} + +void S60VideoWindowControl::setCustomAspectRatio(const QSize &customRatio) +{ + Q_UNUSED(customRatio); +} + +void S60VideoWindowControl::repaint() +{ + m_display->repaint(); +} + +int S60VideoWindowControl::brightness() const +{ + return 0; +} + +void S60VideoWindowControl::setBrightness(int brightness) +{ + Q_UNUSED(brightness) +} + +int S60VideoWindowControl::contrast() const +{ + return 0; +} + +void S60VideoWindowControl::setContrast(int contrast) +{ + Q_UNUSED(contrast) +} + +int S60VideoWindowControl::hue() const +{ + return 0; +} + +void S60VideoWindowControl::setHue(int hue) +{ + Q_UNUSED(hue) +} + +int S60VideoWindowControl::saturation() const +{ + return 0; +} + +void S60VideoWindowControl::setSaturation(int saturation) +{ + Q_UNUSED(saturation) +} + +bool S60VideoWindowControl::isFullScreen() const +{ + return m_display->isFullScreen(); +} + +void S60VideoWindowControl::setFullScreen(bool fullScreen) +{ + m_display->setFullScreen(fullScreen); +} + +QSize S60VideoWindowControl::nativeSize() const +{ + return m_display->nativeSize(); +} + +void S60VideoWindowControl::refreshDisplay() +{ + m_display->refreshDisplay(); +} + +S60VideoWindowDisplay *S60VideoWindowControl::display() const +{ + return m_display; +} + +qreal S60VideoWindowControl::rotation() const +{ + return m_display->rotation(); +} + +void S60VideoWindowControl::setRotation(qreal value) +{ + m_display->setRotation(value); +} diff --git a/src/plugins/symbian/videooutput/s60videowindowcontrol.h b/src/plugins/symbian/videooutput/s60videowindowcontrol.h new file mode 100644 index 000000000..a62d29a13 --- /dev/null +++ b/src/plugins/symbian/videooutput/s60videowindowcontrol.h @@ -0,0 +1,102 @@ +/**************************************************************************** +** +** Copyright (C) 2011 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$ +** +****************************************************************************/ + +#ifndef S60VIDEOWINDOWCONTROL_H +#define S60VIDEOWINDOWCONTROL_H + +#include <qvideowindowcontrol.h> + +class S60VideoWindowDisplay; + +QT_USE_NAMESPACE + +class S60VideoWindowControl : public QVideoWindowControl +{ + Q_OBJECT + + /** + * Rotation to be applied to video. + * Angle is measured in degrees, with positive values counter-clockwise. + * Zero is at 12 o'clock. + */ + Q_PROPERTY(qreal rotation READ rotation WRITE setRotation) + +public: + S60VideoWindowControl(QObject *parent); + ~S60VideoWindowControl(); + +public: + // QVideoWindowControl + WId winId() const; + void setWinId(WId id); + QRect displayRect() const; + void setDisplayRect(const QRect &rect); + bool isFullScreen() const; + void setFullScreen(bool fullScreen); + void repaint(); + QSize nativeSize() const; + Qt::AspectRatioMode aspectRatioMode() const; + void setAspectRatioMode(Qt::AspectRatioMode mode); + QSize customAspectRatio() const; + void setCustomAspectRatio(const QSize &customRatio); + int brightness() const; + void setBrightness(int brightness); + int contrast() const; + void setContrast(int contrast); + int hue() const; + void setHue(int hue); + int saturation() const; + void setSaturation(int saturation); + + S60VideoWindowDisplay *display() const; + + qreal rotation() const; + void setRotation(qreal value); + +public slots: + void refreshDisplay(); + +private: + S60VideoWindowDisplay *m_display; +}; + +#endif // S60VIDEOWINDOWCONTROL_H + diff --git a/src/plugins/symbian/videooutput/s60videowindowdisplay.cpp b/src/plugins/symbian/videooutput/s60videowindowdisplay.cpp new file mode 100644 index 000000000..a8bdb8b4a --- /dev/null +++ b/src/plugins/symbian/videooutput/s60videowindowdisplay.cpp @@ -0,0 +1,140 @@ +/**************************************************************************** +** +** Copyright (C) 2011 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 "s60videowindowdisplay.h" +#include "s60videooutpututils.h" +#include <QtCore/QVariant> +#include <coecntrl.h> +#include <w32std.h> + +using namespace S60VideoOutputUtils; + +S60VideoWindowDisplay::S60VideoWindowDisplay(QObject *parent) +: S60VideoDisplay(parent) +, m_winId(0) +, m_bitmap(0) +{ + parent->setProperty("colorKey", Qt::transparent); +} + +S60VideoWindowDisplay::~S60VideoWindowDisplay() +{ + +} + +WId S60VideoWindowDisplay::winId() const +{ + return m_winId; +} + +QRect S60VideoWindowDisplay::extentRect() const +{ + QRect rect = displayRect(); +#ifndef VIDEOOUTPUT_GRAPHICS_SURFACES + if (RWindow *window = windowHandle()) { + const TPoint windowPos = window->AbsPosition(); + rect.translate(windowPos.iX, windowPos.iY); + } +#endif // VIDEOOUTPUT_GRAPHICS_SURFACES + return rect; +} + +void S60VideoWindowDisplay::setFrame(const CFbsBitmap &bitmap) +{ + m_bitmap = const_cast<CFbsBitmap*>(&bitmap); + if (m_winId) { + // Blit the bitmap into the native window owned by m_winId + CWindowGc &gc = m_winId->SystemGc(); + RWindow *window = windowHandle(); + gc.Activate(*window); + const QPoint offsetQ = displayRect().topLeft() + contentRect().topLeft(); + const TPoint offsetT(offsetQ.x(), offsetQ.y()); + const TRect winRect(offsetT, m_bitmap->SizeInPixels()); + window->BeginRedraw(winRect); + gc.BitBlt(offsetT, m_bitmap); + window->EndRedraw(); + gc.Deactivate(); + } +} + +void S60VideoWindowDisplay::setWinId(WId id) +{ + if (m_winId != id) { + m_winId = id; + if (m_winId) { + static_cast<RWindow *>(m_winId->DrawableWindow())->SetBackgroundColor(TRgb(0, 0, 0, 0)); +#ifndef VIDEOOUTPUT_GRAPHICS_SURFACES + if (QSysInfo::s60Version() >= QSysInfo::SV_S60_5_0) + S60VideoOutputUtils::setNativePaintMode(m_winId, BlitWriteAlpha); +#endif // !VIDEOOUTPUT_GRAPHICS_SURFACES + } + emit windowHandleChanged(windowHandle()); + } +} + +void S60VideoWindowDisplay::setDisplayRect(const QRect &rect) +{ + if (m_displayRect != rect) { + // If QGraphicsVideoItem moves out of screen, display rect is invalidated + if (rect == QRect(QPoint(-1,-1), QSize(1,1))) + emit visibilityChanged(false); + else + emit visibilityChanged(true); + m_displayRect = rect; + emit displayRectChanged(extentRect(), clipRect()); + } +} + +QRect S60VideoWindowDisplay::displayRect() const +{ + return m_displayRect; +} + +void S60VideoWindowDisplay::repaint() +{ + // TODO +} + +void S60VideoWindowDisplay::refreshDisplay() +{ + emit displayRectChanged(extentRect(), clipRect()); +} + diff --git a/src/plugins/symbian/videooutput/s60videowindowdisplay.h b/src/plugins/symbian/videooutput/s60videowindowdisplay.h new file mode 100644 index 000000000..8e749dcf3 --- /dev/null +++ b/src/plugins/symbian/videooutput/s60videowindowdisplay.h @@ -0,0 +1,73 @@ +/**************************************************************************** +** +** Copyright (C) 2011 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$ +** +****************************************************************************/ + +#ifndef S60VIDEOWINDOWDISPLAY_H +#define S60VIDEOWINDOWDISPLAY_H + +#include "s60videodisplay.h" + +QT_USE_NAMESPACE + +class S60VideoWindowDisplay : public S60VideoDisplay +{ +public: + S60VideoWindowDisplay(QObject *parent); + ~S60VideoWindowDisplay(); + + // S60VideoDisplay + WId winId() const; + QRect extentRect() const; + void setFrame(const CFbsBitmap &bitmap); + + void setWinId(WId id); + void setDisplayRect(const QRect &rect); + QRect displayRect() const; + void repaint(); + void refreshDisplay(); + +private: + WId m_winId; + QRect m_displayRect; + CFbsBitmap *m_bitmap; +}; + +#endif // S60VIDEOWINDOWDISPLAY_H + diff --git a/src/plugins/symbian/videooutput/videooutput.pri b/src/plugins/symbian/videooutput/videooutput.pri new file mode 100644 index 000000000..13aa7a0fc --- /dev/null +++ b/src/plugins/symbian/videooutput/videooutput.pri @@ -0,0 +1,37 @@ +INCLUDEPATH += $$PWD + +message("VideoOutput: using common implementation") + +contains(surfaces_s60_enabled, yes) { + message("VideoOutput: graphics surface rendering supported") + DEFINES += VIDEOOUTPUT_GRAPHICS_SURFACES +} else { + message("VideoOutput: no graphics surface rendering support - DSA only") +} + +exists($$[QT_INSTALL_HEADERS]/QtGui/private/qwidget_p.h) { + DEFINES += PRIVATE_QTGUI_HEADERS_AVAILABLE + message("VideoOutput: private QtGui headers are available") +} else { + message("VideoOutput: private QtGui headers not available - video and viewfinder may not be rendered correctly") +} + +HEADERS += $$PWD/s60videodisplay.h \ + $$PWD/s60videooutpututils.h \ + $$PWD/s60videowidget.h \ + $$PWD/s60videowidgetcontrol.h \ + $$PWD/s60videowidgetdisplay.h \ + $$PWD/s60videowindowcontrol.h \ + $$PWD/s60videowindowdisplay.h + +SOURCES += $$PWD/s60videodisplay.cpp \ + $$PWD/s60videooutpututils.cpp \ + $$PWD/s60videowidget.cpp \ + $$PWD/s60videowidgetcontrol.cpp \ + $$PWD/s60videowidgetdisplay.cpp \ + $$PWD/s60videowindowcontrol.cpp \ + $$PWD/s60videowindowdisplay.cpp + +LIBS *= -lcone +LIBS *= -lws32 + |