diff options
Diffstat (limited to 'src/multimedia')
184 files changed, 44005 insertions, 0 deletions
diff --git a/src/multimedia/audio/audio.pri b/src/multimedia/audio/audio.pri new file mode 100644 index 000000000..4bedbd4d5 --- /dev/null +++ b/src/multimedia/audio/audio.pri @@ -0,0 +1,60 @@ +INCLUDEPATH += audio + +PUBLIC_HEADERS += audio/qaudio.h \ + audio/qaudioformat.h \ + audio/qaudioinput.h \ + audio/qaudiooutput.h \ + audio/qaudiodeviceinfo.h \ + audio/qaudiosystemplugin.h \ + audio/qaudiosystem.h + +PRIVATE_HEADERS += audio/qaudiodevicefactory_p.h audio/qaudiopluginloader_p.h + + +SOURCES += audio/qaudio.cpp \ + audio/qaudioformat.cpp \ + audio/qaudiodeviceinfo.cpp \ + audio/qaudiooutput.cpp \ + audio/qaudioinput.cpp \ + audio/qaudiosystemplugin.cpp \ + audio/qaudiosystem.cpp \ + audio/qaudiodevicefactory.cpp \ + audio/qaudiopluginloader.cpp + +mac { + PRIVATE_HEADERS += audio/qaudioinput_mac_p.h \ + audio/qaudiooutput_mac_p.h \ + audio/qaudiodeviceinfo_mac_p.h \ + audio/qaudio_mac_p.h + + SOURCES += audio/qaudiodeviceinfo_mac_p.cpp \ + audio/qaudiooutput_mac_p.cpp \ + audio/qaudioinput_mac_p.cpp \ + audio/qaudio_mac.cpp + + LIBS += -framework ApplicationServices -framework CoreAudio -framework AudioUnit -framework AudioToolbox +} + +win32 { + PRIVATE_HEADERS += audio/qaudioinput_win32_p.h audio/qaudiooutput_win32_p.h audio/qaudiodeviceinfo_win32_p.h + SOURCES += audio/qaudiodeviceinfo_win32_p.cpp \ + audio/qaudiooutput_win32_p.cpp \ + audio/qaudioinput_win32_p.cpp + LIBS += -lwinmm -lstrmiids -lole32 -loleaut32 +} + +unix:!mac { + contains(config_test_pulseaudio, yes) { + DEFINES += QT_NO_AUDIO_BACKEND + } + else:contains(QT_CONFIG, alsa) { + linux-*|freebsd-*|openbsd-* { + DEFINES += HAS_ALSA + PRIVATE_HEADERS += audio/qaudiooutput_alsa_p.h audio/qaudioinput_alsa_p.h audio/qaudiodeviceinfo_alsa_p.h + SOURCES += audio/qaudiodeviceinfo_alsa_p.cpp \ + audio/qaudiooutput_alsa_p.cpp \ + audio/qaudioinput_alsa_p.cpp + LIBS_PRIVATE += -lasound + } + } +} diff --git a/src/multimedia/audio/qaudio.cpp b/src/multimedia/audio/qaudio.cpp new file mode 100644 index 000000000..bb18f8448 --- /dev/null +++ b/src/multimedia/audio/qaudio.cpp @@ -0,0 +1,103 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <qaudio.h> + + +QT_BEGIN_NAMESPACE + +namespace QAudio +{ + +class RegisterMetaTypes +{ +public: + RegisterMetaTypes() + { + qRegisterMetaType<QAudio::Error>(); + qRegisterMetaType<QAudio::State>(); + qRegisterMetaType<QAudio::Mode>(); + } + +} _register; + +} + +/* + \namespace QAudio + \brief The QAudio namespace contains enums used by the audio classes. + \inmodule QtMultimedia + \ingroup multimedia +*/ + +/* + \enum QAudio::Error + + \value NoError No errors have occurred + \value OpenError An error occurred opening the audio device + \value IOError An error occurred during read/write of audio device + \value UnderrunError Audio data is not being fed to the audio device at a fast enough rate + \value FatalError A non-recoverable error has occurred, the audio device is not usable at this time. +*/ + +/* + \enum QAudio::State + + \value ActiveState Audio data is being processed, this state is set after start() is called + and while audio data is available to be processed. + \value SuspendedState The audio device is in a suspended state, this state will only be entered + after suspend() is called. + \value StoppedState The audio device is closed, and is not processing any audio data + \value IdleState The QIODevice passed in has no data and audio system's buffer is empty, this state + is set after start() is called and while no audio data is available to be processed. +*/ + +/* + \enum QAudio::Mode + + \value AudioOutput audio output device + \value AudioInput audio input device +*/ + + +QT_END_NAMESPACE + diff --git a/src/multimedia/audio/qaudio.h b/src/multimedia/audio/qaudio.h new file mode 100644 index 000000000..fff1094c0 --- /dev/null +++ b/src/multimedia/audio/qaudio.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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#ifndef QAUDIO_H +#define QAUDIO_H + +#include <qtmultimediadefs.h> +#include <qtmedianamespace.h> + +#include <QtCore/qmetatype.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + +//QTM_SYNC_HEADER_EXPORT QAudio + +namespace QAudio +{ + enum Error { NoError, OpenError, IOError, UnderrunError, FatalError }; + enum State { ActiveState, SuspendedState, StoppedState, IdleState }; + enum Mode { AudioInput, AudioOutput }; +} + +QT_END_NAMESPACE + +QT_END_HEADER + +Q_DECLARE_METATYPE(QAudio::Error) +Q_DECLARE_METATYPE(QAudio::State) +Q_DECLARE_METATYPE(QAudio::Mode) + +#endif // QAUDIO_H diff --git a/src/multimedia/audio/qaudio_mac.cpp b/src/multimedia/audio/qaudio_mac.cpp new file mode 100644 index 000000000..461508304 --- /dev/null +++ b/src/multimedia/audio/qaudio_mac.cpp @@ -0,0 +1,145 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include "qaudio_mac_p.h" + +QT_BEGIN_NAMESPACE + +// Debugging +QDebug operator<<(QDebug dbg, const QAudioFormat& audioFormat) +{ + dbg.nospace() << "QAudioFormat(" << + audioFormat.frequency() << "," << + audioFormat.channels() << "," << + audioFormat.sampleSize()<< "," << + audioFormat.codec() << "," << + audioFormat.byteOrder() << "," << + audioFormat.sampleType() << ")"; + + return dbg.space(); +} + + +// Conversion +QAudioFormat toQAudioFormat(AudioStreamBasicDescription const& sf) +{ + QAudioFormat audioFormat; + + audioFormat.setFrequency(sf.mSampleRate); + audioFormat.setChannels(sf.mChannelsPerFrame); + audioFormat.setSampleSize(sf.mBitsPerChannel); + audioFormat.setCodec(QString::fromLatin1("audio/pcm")); + audioFormat.setByteOrder((sf.mFormatFlags & kAudioFormatFlagIsBigEndian) != 0 ? QAudioFormat::BigEndian : QAudioFormat::LittleEndian); + QAudioFormat::SampleType type = QAudioFormat::UnSignedInt; + if ((sf.mFormatFlags & kAudioFormatFlagIsSignedInteger) != 0) + type = QAudioFormat::SignedInt; + else if ((sf.mFormatFlags & kAudioFormatFlagIsFloat) != 0) + type = QAudioFormat::Float; + audioFormat.setSampleType(type); + + return audioFormat; +} + +AudioStreamBasicDescription toAudioStreamBasicDescription(QAudioFormat const& audioFormat) +{ + AudioStreamBasicDescription sf; + + sf.mFormatFlags = kAudioFormatFlagIsPacked; + sf.mSampleRate = audioFormat.frequency(); + sf.mFramesPerPacket = 1; + sf.mChannelsPerFrame = audioFormat.channels(); + sf.mBitsPerChannel = audioFormat.sampleSize(); + sf.mBytesPerFrame = sf.mChannelsPerFrame * (sf.mBitsPerChannel / 8); + sf.mBytesPerPacket = sf.mFramesPerPacket * sf.mBytesPerFrame; + sf.mFormatID = kAudioFormatLinearPCM; + + switch (audioFormat.sampleType()) { + case QAudioFormat::SignedInt: sf.mFormatFlags |= kAudioFormatFlagIsSignedInteger; break; + case QAudioFormat::UnSignedInt: /* default */ break; + case QAudioFormat::Float: sf.mFormatFlags |= kAudioFormatFlagIsFloat; break; + case QAudioFormat::Unknown: default: break; + } + + if (audioFormat.byteOrder() == QAudioFormat::BigEndian) + sf.mFormatFlags |= kAudioFormatFlagIsBigEndian; + + return sf; +} + +// QAudioRingBuffer +QAudioRingBuffer::QAudioRingBuffer(int bufferSize): + m_bufferSize(bufferSize) +{ + m_buffer = new char[m_bufferSize]; + reset(); +} + +QAudioRingBuffer::~QAudioRingBuffer() +{ + delete m_buffer; +} + +int QAudioRingBuffer::used() const +{ + return m_bufferUsed; +} + +int QAudioRingBuffer::free() const +{ + return m_bufferSize - m_bufferUsed; +} + +int QAudioRingBuffer::size() const +{ + return m_bufferSize; +} + +void QAudioRingBuffer::reset() +{ + m_readPos = 0; + m_writePos = 0; + m_bufferUsed = 0; +} + +QT_END_NAMESPACE + + diff --git a/src/multimedia/audio/qaudio_mac_p.h b/src/multimedia/audio/qaudio_mac_p.h new file mode 100644 index 000000000..06ce43010 --- /dev/null +++ b/src/multimedia/audio/qaudio_mac_p.h @@ -0,0 +1,145 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + + +#ifndef QAUDIO_MAC_P_H +#define QAUDIO_MAC_P_H + +#include <CoreAudio/CoreAudio.h> + +#include <QtCore/qdebug.h> +#include <QtCore/qatomic.h> + +#include <qaudioformat.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + + +extern QDebug operator<<(QDebug dbg, const QAudioFormat& audioFormat); + +extern QAudioFormat toQAudioFormat(const AudioStreamBasicDescription& streamFormat); +extern AudioStreamBasicDescription toAudioStreamBasicDescription(QAudioFormat const& audioFormat); + +class QAudioRingBuffer +{ +public: + typedef QPair<char*, int> Region; + + QAudioRingBuffer(int bufferSize); + ~QAudioRingBuffer(); + + Region acquireReadRegion(int size) + { + const int used = m_bufferUsed.fetchAndAddAcquire(0); + + if (used > 0) { + const int readSize = qMin(size, qMin(m_bufferSize - m_readPos, used)); + + return readSize > 0 ? Region(m_buffer + m_readPos, readSize) : Region(0, 0); + } + + return Region(0, 0); + } + + void releaseReadRegion(Region const& region) + { + m_readPos = (m_readPos + region.second) % m_bufferSize; + + m_bufferUsed.fetchAndAddRelease(-region.second); + } + + Region acquireWriteRegion(int size) + { + const int free = m_bufferSize - m_bufferUsed.fetchAndAddAcquire(0); + + if (free > 0) { + const int writeSize = qMin(size, qMin(m_bufferSize - m_writePos, free)); + + return writeSize > 0 ? Region(m_buffer + m_writePos, writeSize) : Region(0, 0); + } + + return Region(0, 0); + } + + void releaseWriteRegion(Region const& region) + { + m_writePos = (m_writePos + region.second) % m_bufferSize; + + m_bufferUsed.fetchAndAddRelease(region.second); + } + + int used() const; + int free() const; + int size() const; + + void reset(); + +private: + int m_bufferSize; + int m_readPos; + int m_writePos; + char* m_buffer; + QAtomicInt m_bufferUsed; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QAUDIO_MAC_P_H + + diff --git a/src/multimedia/audio/qaudiodevicefactory.cpp b/src/multimedia/audio/qaudiodevicefactory.cpp new file mode 100644 index 000000000..19071e78f --- /dev/null +++ b/src/multimedia/audio/qaudiodevicefactory.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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtCore/qdebug.h> + +#include "qaudiosystem.h" +#include "qaudiosystemplugin.h" + +#include "qaudiopluginloader_p.h" +#include "qaudiodevicefactory_p.h" + +#ifndef QT_NO_AUDIO_BACKEND +#if defined(Q_OS_WIN) +#include "qaudiodeviceinfo_win32_p.h" +#include "qaudiooutput_win32_p.h" +#include "qaudioinput_win32_p.h" +#elif defined(Q_OS_MAC) +#include "qaudiodeviceinfo_mac_p.h" +#include "qaudiooutput_mac_p.h" +#include "qaudioinput_mac_p.h" +#elif defined(HAS_ALSA) +#include "qaudiodeviceinfo_alsa_p.h" +#include "qaudiooutput_alsa_p.h" +#include "qaudioinput_alsa_p.h" +#endif +#endif + +QT_BEGIN_NAMESPACE + +#if !defined (QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS) +Q_GLOBAL_STATIC_WITH_ARGS(QAudioPluginLoader, audioLoader, + (QAudioSystemFactoryInterface_iid, QLatin1String("/audio"), Qt::CaseInsensitive)) +#endif + +class QNullDeviceInfo : public QAbstractAudioDeviceInfo +{ +public: + QAudioFormat preferredFormat() const { qWarning()<<"using null deviceinfo, none available"; return QAudioFormat(); } + bool isFormatSupported(const QAudioFormat& ) const { return false; } + QAudioFormat nearestFormat(const QAudioFormat& ) const { return QAudioFormat(); } + QString deviceName() const { return QString(); } + QStringList supportedCodecs() { return QStringList(); } + QList<int> supportedSampleRates() { return QList<int>(); } + QList<int> supportedChannelCounts() { return QList<int>(); } + QList<int> supportedSampleSizes() { return QList<int>(); } + QList<QAudioFormat::Endian> supportedByteOrders() { return QList<QAudioFormat::Endian>(); } + QList<QAudioFormat::SampleType> supportedSampleTypes() { return QList<QAudioFormat::SampleType>(); } +}; + +class QNullInputDevice : public QAbstractAudioInput +{ +public: + void start(QIODevice*) { qWarning()<<"using null input device, none available";} + QIODevice* start() { qWarning()<<"using null input device, none available"; return 0; } + void stop() {} + void reset() {} + void suspend() {} + void resume() {} + int bytesReady() const { return 0; } + int periodSize() const { return 0; } + void setBufferSize(int ) {} + int bufferSize() const { return 0; } + void setNotifyInterval(int ) {} + int notifyInterval() const { return 0; } + qint64 processedUSecs() const { return 0; } + qint64 elapsedUSecs() const { return 0; } + QAudio::Error error() const { return QAudio::OpenError; } + QAudio::State state() const { return QAudio::StoppedState; } + void setFormat(const QAudioFormat&) {} + QAudioFormat format() const { return QAudioFormat(); } +}; + +class QNullOutputDevice : public QAbstractAudioOutput +{ +public: + void start(QIODevice*) {qWarning()<<"using null output device, none available";} + QIODevice* start() { qWarning()<<"using null output device, none available"; return 0; } + void stop() {} + void reset() {} + void suspend() {} + void resume() {} + int bytesFree() const { return 0; } + int periodSize() const { return 0; } + void setBufferSize(int ) {} + int bufferSize() const { return 0; } + void setNotifyInterval(int ) {} + int notifyInterval() const { return 0; } + qint64 processedUSecs() const { return 0; } + qint64 elapsedUSecs() const { return 0; } + QAudio::Error error() const { return QAudio::OpenError; } + QAudio::State state() const { return QAudio::StoppedState; } + void setFormat(const QAudioFormat&) {} + QAudioFormat format() const { return QAudioFormat(); } +}; + +QList<QAudioDeviceInfo> QAudioDeviceFactory::availableDevices(QAudio::Mode mode) +{ + QList<QAudioDeviceInfo> devices; +#ifndef QT_NO_AUDIO_BACKEND +#if (defined(Q_OS_WIN) || defined(Q_OS_MAC) || defined(HAS_ALSA)) + foreach (const QByteArray &handle, QAudioDeviceInfoInternal::availableDevices(mode)) + devices << QAudioDeviceInfo(QLatin1String("builtin"), handle, mode); +#endif +#endif + +#if !defined (QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS) + QAudioPluginLoader* l = audioLoader(); + foreach (const QString& key, l->keys()) { + QAudioSystemFactoryInterface* plugin = qobject_cast<QAudioSystemFactoryInterface*>(l->instance(key)); + if (plugin) { + foreach (QByteArray const& handle, plugin->availableDevices(mode)) + devices << QAudioDeviceInfo(key, handle, mode); + } + + delete plugin; + } +#endif + + return devices; +} + +QAudioDeviceInfo QAudioDeviceFactory::defaultInputDevice() +{ +#if !defined (QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS) + QAudioSystemFactoryInterface* plugin = qobject_cast<QAudioSystemFactoryInterface*>(audioLoader()->instance(QLatin1String("default"))); + + if (plugin) { + QList<QByteArray> list = plugin->availableDevices(QAudio::AudioInput); + if (list.size() > 0) + return QAudioDeviceInfo(QLatin1String("default"), list.at(0), QAudio::AudioInput); + } +#endif + +#ifndef QT_NO_AUDIO_BACKEND +#if (defined(Q_OS_WIN) || defined(Q_OS_MAC) || defined(HAS_ALSA)) + return QAudioDeviceInfo(QLatin1String("builtin"), QAudioDeviceInfoInternal::defaultInputDevice(), QAudio::AudioInput); +#endif +#endif + return QAudioDeviceInfo(); +} + +QAudioDeviceInfo QAudioDeviceFactory::defaultOutputDevice() +{ +#if !defined (QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS) + QAudioSystemFactoryInterface* plugin = qobject_cast<QAudioSystemFactoryInterface*>(audioLoader()->instance(QLatin1String("default"))); + + if (plugin) { + QList<QByteArray> list = plugin->availableDevices(QAudio::AudioOutput); + if (list.size() > 0) + return QAudioDeviceInfo(QLatin1String("default"), list.at(0), QAudio::AudioOutput); + } +#endif + +#ifndef QT_NO_AUDIO_BACKEND +#if (defined(Q_OS_WIN) || defined(Q_OS_MAC) || defined(HAS_ALSA)) + return QAudioDeviceInfo(QLatin1String("builtin"), QAudioDeviceInfoInternal::defaultOutputDevice(), QAudio::AudioOutput); +#endif +#endif + return QAudioDeviceInfo(); +} + +QAbstractAudioDeviceInfo* QAudioDeviceFactory::audioDeviceInfo(const QString &realm, const QByteArray &handle, QAudio::Mode mode) +{ + QAbstractAudioDeviceInfo *rc = 0; + +#ifndef QT_NO_AUDIO_BACKEND +#if (defined(Q_OS_WIN) || defined(Q_OS_MAC) || defined(HAS_ALSA)) + if (realm == QLatin1String("builtin")) + return new QAudioDeviceInfoInternal(handle, mode); +#endif +#endif + +#if !defined (QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS) + QAudioSystemFactoryInterface* plugin = + qobject_cast<QAudioSystemFactoryInterface*>(audioLoader()->instance(realm)); + + if (plugin) + rc = plugin->createDeviceInfo(handle, mode); +#endif + + return rc == 0 ? new QNullDeviceInfo() : rc; +} + +QAbstractAudioInput* QAudioDeviceFactory::createDefaultInputDevice(QAudioFormat const &format) +{ + return createInputDevice(defaultInputDevice(), format); +} + +QAbstractAudioOutput* QAudioDeviceFactory::createDefaultOutputDevice(QAudioFormat const &format) +{ + return createOutputDevice(defaultOutputDevice(), format); +} + +QAbstractAudioInput* QAudioDeviceFactory::createInputDevice(QAudioDeviceInfo const& deviceInfo, QAudioFormat const &format) +{ + if (deviceInfo.isNull()) + return new QNullInputDevice(); +#ifndef QT_NO_AUDIO_BACKEND +#if (defined(Q_OS_WIN) || defined(Q_OS_MAC) || defined(HAS_ALSA)) + if (deviceInfo.realm() == QLatin1String("builtin")) { + QAbstractAudioInput* p = new QAudioInputPrivate(deviceInfo.handle()); + if (p) p->setFormat(format); + return p; + } +#endif +#endif +#if !defined (QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS) + QAudioSystemFactoryInterface* plugin = + qobject_cast<QAudioSystemFactoryInterface*>(audioLoader()->instance(deviceInfo.realm())); + + if (plugin) { + QAbstractAudioInput* p = plugin->createInput(deviceInfo.handle()); + if (p) p->setFormat(format); + return p; + } +#endif + + return new QNullInputDevice(); +} + +QAbstractAudioOutput* QAudioDeviceFactory::createOutputDevice(QAudioDeviceInfo const& deviceInfo, QAudioFormat const &format) +{ + if (deviceInfo.isNull()) + return new QNullOutputDevice(); +#ifndef QT_NO_AUDIO_BACKEND +#if (defined(Q_OS_WIN) || defined(Q_OS_MAC) || defined(HAS_ALSA)) + if (deviceInfo.realm() == QLatin1String("builtin")) { + QAbstractAudioOutput* p = new QAudioOutputPrivate(deviceInfo.handle()); + if (p) p->setFormat(format); + return p; + } +#endif +#endif + +#if !defined (QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS) + QAudioSystemFactoryInterface* plugin = + qobject_cast<QAudioSystemFactoryInterface*>(audioLoader()->instance(deviceInfo.realm())); + + if (plugin) { + QAbstractAudioOutput* p = plugin->createOutput(deviceInfo.handle()); + if (p) p->setFormat(format); + return p; + } +#endif + + return new QNullOutputDevice(); +} + +QT_END_NAMESPACE + diff --git a/src/multimedia/audio/qaudiodevicefactory_p.h b/src/multimedia/audio/qaudiodevicefactory_p.h new file mode 100644 index 000000000..26b3a48e5 --- /dev/null +++ b/src/multimedia/audio/qaudiodevicefactory_p.h @@ -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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#ifndef QAUDIODEVICEFACTORY_P_H +#define QAUDIODEVICEFACTORY_P_H + +#include <QtCore/qbytearray.h> +#include <QtCore/qlist.h> + +#include <qtmultimediadefs.h> +#include <qtmedianamespace.h> + +#include "qaudiodeviceinfo.h" + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + +class QAbstractAudioInput; +class QAbstractAudioOutput; +class QAbstractAudioDeviceInfo; + +class QAudioDeviceFactory +{ +public: + static QList<QAudioDeviceInfo> availableDevices(QAudio::Mode mode); + + static QAudioDeviceInfo defaultInputDevice(); + static QAudioDeviceInfo defaultOutputDevice(); + + static QAbstractAudioDeviceInfo* audioDeviceInfo(const QString &realm, const QByteArray &handle, QAudio::Mode mode); + + static QAbstractAudioInput* createDefaultInputDevice(QAudioFormat const &format); + static QAbstractAudioOutput* createDefaultOutputDevice(QAudioFormat const &format); + + static QAbstractAudioInput* createInputDevice(QAudioDeviceInfo const &device, QAudioFormat const &format); + static QAbstractAudioOutput* createOutputDevice(QAudioDeviceInfo const &device, QAudioFormat const &format); + + static QAbstractAudioInput* createNullInput(); + static QAbstractAudioOutput* createNullOutput(); +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QAUDIODEVICEFACTORY_P_H + diff --git a/src/multimedia/audio/qaudiodeviceinfo.cpp b/src/multimedia/audio/qaudiodeviceinfo.cpp new file mode 100644 index 000000000..f45805dbc --- /dev/null +++ b/src/multimedia/audio/qaudiodeviceinfo.cpp @@ -0,0 +1,483 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qaudiodevicefactory_p.h" +#include "qaudiosystem.h" +#include "qaudiodeviceinfo.h" + +#include <QtCore/qmap.h> + +QT_BEGIN_NAMESPACE + +class QAudioDeviceInfoPrivate : public QSharedData +{ +public: + QAudioDeviceInfoPrivate():info(0) {} + QAudioDeviceInfoPrivate(const QString &r, const QByteArray &h, QAudio::Mode m): + realm(r), handle(h), mode(m) + { + if (!handle.isEmpty()) + info = QAudioDeviceFactory::audioDeviceInfo(realm, handle, mode); + else + info = NULL; + } + + QAudioDeviceInfoPrivate(const QAudioDeviceInfoPrivate &other): + QSharedData(other), + realm(other.realm), handle(other.handle), mode(other.mode) + { + info = QAudioDeviceFactory::audioDeviceInfo(realm, handle, mode); + } + + QAudioDeviceInfoPrivate& operator=(const QAudioDeviceInfoPrivate &other) + { + delete info; + + realm = other.realm; + handle = other.handle; + mode = other.mode; + info = QAudioDeviceFactory::audioDeviceInfo(realm, handle, mode); + return *this; + } + + ~QAudioDeviceInfoPrivate() + { + delete info; + } + + QString realm; + QByteArray handle; + QAudio::Mode mode; + QAbstractAudioDeviceInfo* info; +}; + + +/*! + \class QAudioDeviceInfo + \brief The QAudioDeviceInfo class provides an interface to query audio devices and their functionality. + \inmodule QtMultimedia + \ingroup multimedia + + QAudioDeviceInfo lets you query for audio devices--such as sound + cards and USB headsets--that are currently available on the system. + The audio devices available are dependent on the platform or audio plugins installed. + + A QAudioDeviceInfo is used by Qt to construct + classes that communicate with the device--such as + QAudioInput, and QAudioOutput. + + You can also query each device for the formats it supports. A + format in this context is a set consisting of a specific byte + order, channel, codec, frequency, sample rate, and sample type. A + format is represented by the QAudioFormat class. + + The values supported by the the device for each of these + parameters can be fetched with + supportedByteOrders(), supportedChannelCounts(), supportedCodecs(), + supportedSampleRates(), supportedSampleSizes(), and + supportedSampleTypes(). The combinations supported are dependent on the platform, + audio plugins installed and the audio device capabilities. If you need a + specific format, you can check if + the device supports it with isFormatSupported(), or fetch a + supported format that is as close as possible to the format with + nearestFormat(). For instance: + + \snippet doc/src/snippets/multimedia-snippets/audio.cpp Setting audio format + + The static + functions defaultInputDevice(), defaultOutputDevice(), and + availableDevices() let you get a list of all available + devices. Devices are fetched according to the value of mode + this is specified by the \l {QAudio}::Mode enum. + The QAudioDeviceInfo returned are only valid for the \l {QAudio}::Mode. + + For instance: + + \snippet doc/src/snippets/multimedia-snippets/audio.cpp Dumping audio formats + + In this code sample, we loop through all devices that are able to output + sound, i.e., play an audio stream in a supported format. For each device we + find, we simply print the deviceName(). + + \sa QAudioOutput, QAudioInput +*/ + +/*! + Constructs an empty QAudioDeviceInfo object. +*/ +QAudioDeviceInfo::QAudioDeviceInfo(): + d(new QAudioDeviceInfoPrivate) +{ +} + +/*! + Constructs a copy of \a other. + \since 1.0 +*/ +QAudioDeviceInfo::QAudioDeviceInfo(const QAudioDeviceInfo& other): + d(other.d) +{ +} + +/*! + Destroy this audio device info. +*/ +QAudioDeviceInfo::~QAudioDeviceInfo() +{ +} + +/*! + Sets the QAudioDeviceInfo object to be equal to \a other. + \since 1.0 +*/ +QAudioDeviceInfo& QAudioDeviceInfo::operator=(const QAudioDeviceInfo &other) +{ + d = other.d; + return *this; +} + +/*! + Returns whether this QAudioDeviceInfo object holds a device definition. + \since 1.0 +*/ +bool QAudioDeviceInfo::isNull() const +{ + return d->info == 0; +} + +/*! + Returns the human readable name of the audio device. + + Device names vary depending on the platform/audio plugin being used. + + They are a unique string identifier for the audio device. + + eg. default, Intel, U0x46d0x9a4 + \since 1.0 +*/ +QString QAudioDeviceInfo::deviceName() const +{ + return isNull() ? QString() : d->info->deviceName(); +} + +/*! + Returns true if the supplied \a settings are supported by the audio + device described by this QAudioDeviceInfo. + \since 1.0 +*/ +bool QAudioDeviceInfo::isFormatSupported(const QAudioFormat &settings) const +{ + return isNull() ? false : d->info->isFormatSupported(settings); +} + +/*! + Returns the default audio format settings for this device. + + These settings are provided by the platform/audio plugin being used. + + They are also dependent on the \l {QAudio}::Mode being used. + + A typical audio system would provide something like: + \list + \o Input settings: 8000Hz mono 8 bit. + \o Output settings: 44100Hz stereo 16 bit little endian. + \endlist + \since 1.0 +*/ +QAudioFormat QAudioDeviceInfo::preferredFormat() const +{ + return isNull() ? QAudioFormat() : d->info->preferredFormat(); +} + +/*! + Returns the closest QAudioFormat to the supplied \a settings that the system supports. + + These settings are provided by the platform/audio plugin being used. + + They are also dependent on the \l {QAudio}::Mode being used. + \since 1.0 +*/ +QAudioFormat QAudioDeviceInfo::nearestFormat(const QAudioFormat &settings) const +{ + if (isFormatSupported(settings)) + return settings; + + QAudioFormat nearest = settings; + + QList<QString> testCodecs = supportedCodecs(); + QList<int> testChannels = supportedChannels(); + QList<QAudioFormat::Endian> testByteOrders = supportedByteOrders(); + QList<QAudioFormat::SampleType> testSampleTypes; + QList<QAudioFormat::SampleType> sampleTypesAvailable = supportedSampleTypes(); + QMap<int,int> testFrequencies; + QList<int> frequenciesAvailable = supportedFrequencies(); + QMap<int,int> testSampleSizes; + QList<int> sampleSizesAvailable = supportedSampleSizes(); + + // Get sorted lists for checking + if (testCodecs.contains(settings.codec())) { + testCodecs.removeAll(settings.codec()); + testCodecs.insert(0, settings.codec()); + } + testChannels.removeAll(settings.channels()); + testChannels.insert(0, settings.channels()); + testByteOrders.removeAll(settings.byteOrder()); + testByteOrders.insert(0, settings.byteOrder()); + + if (sampleTypesAvailable.contains(settings.sampleType())) + testSampleTypes.append(settings.sampleType()); + if (sampleTypesAvailable.contains(QAudioFormat::SignedInt)) + testSampleTypes.append(QAudioFormat::SignedInt); + if (sampleTypesAvailable.contains(QAudioFormat::UnSignedInt)) + testSampleTypes.append(QAudioFormat::UnSignedInt); + if (sampleTypesAvailable.contains(QAudioFormat::Float)) + testSampleTypes.append(QAudioFormat::Float); + + if (sampleSizesAvailable.contains(settings.sampleSize())) + testSampleSizes.insert(0,settings.sampleSize()); + sampleSizesAvailable.removeAll(settings.sampleSize()); + foreach (int size, sampleSizesAvailable) { + int larger = (size > settings.sampleSize()) ? size : settings.sampleSize(); + int smaller = (size > settings.sampleSize()) ? settings.sampleSize() : size; + bool isMultiple = ( 0 == (larger % smaller)); + int diff = larger - smaller; + testSampleSizes.insert((isMultiple ? diff : diff+100000), size); + } + if (frequenciesAvailable.contains(settings.frequency())) + testFrequencies.insert(0,settings.frequency()); + frequenciesAvailable.removeAll(settings.frequency()); + foreach (int frequency, frequenciesAvailable) { + int larger = (frequency > settings.frequency()) ? frequency : settings.frequency(); + int smaller = (frequency > settings.frequency()) ? settings.frequency() : frequency; + bool isMultiple = ( 0 == (larger % smaller)); + int diff = larger - smaller; + testFrequencies.insert((isMultiple ? diff : diff+100000), frequency); + } + + // Try to find nearest + foreach (QString codec, testCodecs) { + nearest.setCodec(codec); + foreach (QAudioFormat::Endian order, testByteOrders) { + nearest.setByteOrder(order); + foreach (QAudioFormat::SampleType sample, testSampleTypes) { + nearest.setSampleType(sample); + QMapIterator<int, int> sz(testSampleSizes); + while (sz.hasNext()) { + sz.next(); + nearest.setSampleSize(sz.value()); + foreach (int channel, testChannels) { + nearest.setChannels(channel); + QMapIterator<int, int> i(testFrequencies); + while (i.hasNext()) { + i.next(); + nearest.setFrequency(i.value()); + if (isFormatSupported(nearest)) + return nearest; + } + } + } + } + } + } + //Fallback + return preferredFormat(); +} + +/*! + Returns a list of supported codecs. + + All platform and plugin implementations should provide support for: + + "audio/pcm" - Linear PCM + + For writing plugins to support additional codecs refer to: + + http://www.iana.org/assignments/media-types/audio/ + \since 1.0 +*/ +QStringList QAudioDeviceInfo::supportedCodecs() const +{ + return isNull() ? QStringList() : d->info->supportedCodecs(); +} + +/*! + Returns a list of supported sample rates (in Hertz). + + \since 1.0 +*/ +QList<int> QAudioDeviceInfo::supportedSampleRates() const +{ + return supportedFrequencies(); +} + +/*! + \obsolete + + Use supportedSampleRates() instead. + \since 1.0 +*/ +QList<int> QAudioDeviceInfo::supportedFrequencies() const +{ + return isNull() ? QList<int>() : d->info->supportedSampleRates(); +} + +/*! + Returns a list of supported channel counts. + + This is typically 1 for mono sound, or 2 for stereo sound. + + \since 1.0 +*/ +QList<int> QAudioDeviceInfo::supportedChannelCounts() const +{ + return supportedChannels(); +} + +/*! + \obsolete + + Use supportedChannelCount() instead. + \since 1.0 +*/ +QList<int> QAudioDeviceInfo::supportedChannels() const +{ + return isNull() ? QList<int>() : d->info->supportedChannelCounts(); +} + +/*! + Returns a list of supported sample sizes (in bits). + + Typically this will include 8 and 16 bit sample sizes. + + \since 1.0 +*/ +QList<int> QAudioDeviceInfo::supportedSampleSizes() const +{ + return isNull() ? QList<int>() : d->info->supportedSampleSizes(); +} + +/*! + Returns a list of supported byte orders. + \since 1.0 +*/ +QList<QAudioFormat::Endian> QAudioDeviceInfo::supportedByteOrders() const +{ + return isNull() ? QList<QAudioFormat::Endian>() : d->info->supportedByteOrders(); +} + +/*! + Returns a list of supported sample types. + \since 1.0 +*/ +QList<QAudioFormat::SampleType> QAudioDeviceInfo::supportedSampleTypes() const +{ + return isNull() ? QList<QAudioFormat::SampleType>() : d->info->supportedSampleTypes(); +} + +/*! + Returns the information for the default input audio device. + All platform and audio plugin implementations provide a default audio device to use. + \since 1.0 +*/ +QAudioDeviceInfo QAudioDeviceInfo::defaultInputDevice() +{ + return QAudioDeviceFactory::defaultInputDevice(); +} + +/*! + Returns the information for the default output audio device. + All platform and audio plugin implementations provide a default audio device to use. + \since 1.0 +*/ +QAudioDeviceInfo QAudioDeviceInfo::defaultOutputDevice() +{ + return QAudioDeviceFactory::defaultOutputDevice(); +} + +/*! + Returns a list of audio devices that support \a mode. + \since 1.0 +*/ +QList<QAudioDeviceInfo> QAudioDeviceInfo::availableDevices(QAudio::Mode mode) +{ + return QAudioDeviceFactory::availableDevices(mode); +} + + +/*! + \internal + \since 1.0 +*/ +QAudioDeviceInfo::QAudioDeviceInfo(const QString &realm, const QByteArray &handle, QAudio::Mode mode): + d(new QAudioDeviceInfoPrivate(realm, handle, mode)) +{ +} + +/*! + \internal + \since 1.0 +*/ +QString QAudioDeviceInfo::realm() const +{ + return d->realm; +} + +/*! + \internal + \since 1.0 +*/ +QByteArray QAudioDeviceInfo::handle() const +{ + return d->handle; +} + + +/*! + \internal + \since 1.0 +*/ +QAudio::Mode QAudioDeviceInfo::mode() const +{ + return d->mode; +} + +QT_END_NAMESPACE + diff --git a/src/multimedia/audio/qaudiodeviceinfo.h b/src/multimedia/audio/qaudiodeviceinfo.h new file mode 100644 index 000000000..f16122b4d --- /dev/null +++ b/src/multimedia/audio/qaudiodeviceinfo.h @@ -0,0 +1,116 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#ifndef QAUDIODEVICEINFO_H +#define QAUDIODEVICEINFO_H + +#include <QtCore/qobject.h> +#include <QtCore/qbytearray.h> +#include <QtCore/qstring.h> +#include <QtCore/qstringlist.h> +#include <QtCore/qlist.h> + +#include <qtmultimediadefs.h> +#include <qtmedianamespace.h> + +#include <qaudio.h> +#include <qaudioformat.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + +class QAudioDeviceFactory; + +class QAudioDeviceInfoPrivate; +class Q_MULTIMEDIA_EXPORT QAudioDeviceInfo +{ + friend class QAudioDeviceFactory; + +public: + QAudioDeviceInfo(); + QAudioDeviceInfo(const QAudioDeviceInfo& other); + ~QAudioDeviceInfo(); + + QAudioDeviceInfo& operator=(const QAudioDeviceInfo& other); + + bool isNull() const; + + QString deviceName() const; + + bool isFormatSupported(const QAudioFormat &format) const; + QAudioFormat preferredFormat() const; + QAudioFormat nearestFormat(const QAudioFormat &format) const; + + QStringList supportedCodecs() const; + QList<int> supportedFrequencies() const; + QList<int> supportedSampleRates() const; + QList<int> supportedChannels() const; + QList<int> supportedChannelCounts() const; + QList<int> supportedSampleSizes() const; + QList<QAudioFormat::Endian> supportedByteOrders() const; + QList<QAudioFormat::SampleType> supportedSampleTypes() const; + + static QAudioDeviceInfo defaultInputDevice(); + static QAudioDeviceInfo defaultOutputDevice(); + + static QList<QAudioDeviceInfo> availableDevices(QAudio::Mode mode); + +private: + QAudioDeviceInfo(const QString &realm, const QByteArray &handle, QAudio::Mode mode); + QString realm() const; + QByteArray handle() const; + QAudio::Mode mode() const; + + QSharedDataPointer<QAudioDeviceInfoPrivate> d; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +Q_DECLARE_METATYPE(QAudioDeviceInfo) + +#endif // QAUDIODEVICEINFO_H diff --git a/src/multimedia/audio/qaudiodeviceinfo_alsa_p.cpp b/src/multimedia/audio/qaudiodeviceinfo_alsa_p.cpp new file mode 100644 index 000000000..113b330d4 --- /dev/null +++ b/src/multimedia/audio/qaudiodeviceinfo_alsa_p.cpp @@ -0,0 +1,535 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// INTERNAL USE ONLY: Do NOT use for any other purpose. +// + +#include "qaudiodeviceinfo_alsa_p.h" + +#include <alsa/version.h> + +QT_BEGIN_NAMESPACE + +QAudioDeviceInfoInternal::QAudioDeviceInfoInternal(QByteArray dev, QAudio::Mode mode) +{ + handle = 0; + + device = QLatin1String(dev); + this->mode = mode; + + checkSurround(); +} + +QAudioDeviceInfoInternal::~QAudioDeviceInfoInternal() +{ + close(); +} + +bool QAudioDeviceInfoInternal::isFormatSupported(const QAudioFormat& format) const +{ + return testSettings(format); +} + +QAudioFormat QAudioDeviceInfoInternal::preferredFormat() const +{ + QAudioFormat nearest; + if(mode == QAudio::AudioOutput) { + nearest.setFrequency(44100); + nearest.setChannels(2); + nearest.setByteOrder(QAudioFormat::LittleEndian); + nearest.setSampleType(QAudioFormat::SignedInt); + nearest.setSampleSize(16); + nearest.setCodec(QLatin1String("audio/pcm")); + } else { + nearest.setFrequency(8000); + nearest.setChannels(1); + nearest.setSampleType(QAudioFormat::UnSignedInt); + nearest.setSampleSize(8); + nearest.setCodec(QLatin1String("audio/pcm")); + if(!testSettings(nearest)) { + nearest.setChannels(2); + nearest.setSampleSize(16); + nearest.setSampleType(QAudioFormat::SignedInt); + } + } + return nearest; +} + +QString QAudioDeviceInfoInternal::deviceName() const +{ + return device; +} + +QStringList QAudioDeviceInfoInternal::supportedCodecs() +{ + updateLists(); + return codecz; +} + +QList<int> QAudioDeviceInfoInternal::supportedSampleRates() +{ + updateLists(); + return freqz; +} + +QList<int> QAudioDeviceInfoInternal::supportedChannelCounts() +{ + updateLists(); + return channelz; +} + +QList<int> QAudioDeviceInfoInternal::supportedSampleSizes() +{ + updateLists(); + return sizez; +} + +QList<QAudioFormat::Endian> QAudioDeviceInfoInternal::supportedByteOrders() +{ + updateLists(); + return byteOrderz; +} + +QList<QAudioFormat::SampleType> QAudioDeviceInfoInternal::supportedSampleTypes() +{ + updateLists(); + return typez; +} + +bool QAudioDeviceInfoInternal::open() +{ + int err = 0; + QString dev = device; + QList<QByteArray> devices = availableDevices(mode); + + if(dev.compare(QLatin1String("default")) == 0) { +#if(SND_LIB_MAJOR == 1 && SND_LIB_MINOR == 0 && SND_LIB_SUBMINOR >= 14) + if (devices.size() > 0) + dev = QLatin1String(devices.first().constData()); + else + return false; +#else + dev = QLatin1String("hw:0,0"); +#endif + } else { +#if(SND_LIB_MAJOR == 1 && SND_LIB_MINOR == 0 && SND_LIB_SUBMINOR >= 14) + dev = device; +#else + int idx = 0; + char *name; + + QString shortName = device.mid(device.indexOf(QLatin1String("="),0)+1); + + while(snd_card_get_name(idx,&name) == 0) { + if(dev.contains(QLatin1String(name))) + break; + idx++; + } + dev = QString(QLatin1String("hw:%1,0")).arg(idx); +#endif + } + if(mode == QAudio::AudioOutput) { + err=snd_pcm_open( &handle,dev.toLocal8Bit().constData(),SND_PCM_STREAM_PLAYBACK,0); + } else { + err=snd_pcm_open( &handle,dev.toLocal8Bit().constData(),SND_PCM_STREAM_CAPTURE,0); + } + if(err < 0) { + handle = 0; + return false; + } + return true; +} + +void QAudioDeviceInfoInternal::close() +{ + if(handle) + snd_pcm_close(handle); + handle = 0; +} + +bool QAudioDeviceInfoInternal::testSettings(const QAudioFormat& format) const +{ + // Set nearest to closest settings that do work. + // See if what is in settings will work (return value). + int err = 0; + snd_pcm_t* handle; + snd_pcm_hw_params_t *params; + QString dev = device; + + QList<QByteArray> devices = QAudioDeviceInfoInternal::availableDevices(QAudio::AudioOutput); + + if(dev.compare(QLatin1String("default")) == 0) { +#if(SND_LIB_MAJOR == 1 && SND_LIB_MINOR == 0 && SND_LIB_SUBMINOR >= 14) + dev = QLatin1String(devices.first().constData()); +#else + dev = QLatin1String("hw:0,0"); +#endif + } else { +#if(SND_LIB_MAJOR == 1 && SND_LIB_MINOR == 0 && SND_LIB_SUBMINOR >= 14) + dev = device; +#else + int idx = 0; + char *name; + + QString shortName = device.mid(device.indexOf(QLatin1String("="),0)+1); + + while(snd_card_get_name(idx,&name) == 0) { + if(shortName.compare(QLatin1String(name)) == 0) + break; + idx++; + } + dev = QString(QLatin1String("hw:%1,0")).arg(idx); +#endif + } + if(mode == QAudio::AudioOutput) { + err=snd_pcm_open( &handle,dev.toLocal8Bit().constData(),SND_PCM_STREAM_PLAYBACK,0); + } else { + err=snd_pcm_open( &handle,dev.toLocal8Bit().constData(),SND_PCM_STREAM_CAPTURE,0); + } + if(err < 0) { + handle = 0; + return false; + } + + bool testChannel = false; + bool testCodec = false; + bool testFreq = false; + bool testType = false; + bool testSize = false; + + int dir = 0; + + snd_pcm_nonblock( handle, 0 ); + snd_pcm_hw_params_alloca( ¶ms ); + snd_pcm_hw_params_any( handle, params ); + + // set the values! + snd_pcm_hw_params_set_channels(handle,params,format.channels()); + snd_pcm_hw_params_set_rate(handle,params,format.frequency(),dir); + + err = -1; + + switch(format.sampleSize()) { + case 8: + if(format.sampleType() == QAudioFormat::SignedInt) + err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S8); + else if(format.sampleType() == QAudioFormat::UnSignedInt) + err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U8); + break; + case 16: + if(format.sampleType() == QAudioFormat::SignedInt) { + if(format.byteOrder() == QAudioFormat::LittleEndian) + err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S16_LE); + else if(format.byteOrder() == QAudioFormat::BigEndian) + err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S16_BE); + } else if(format.sampleType() == QAudioFormat::UnSignedInt) { + if(format.byteOrder() == QAudioFormat::LittleEndian) + err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U16_LE); + else if(format.byteOrder() == QAudioFormat::BigEndian) + err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U16_BE); + } + break; + case 32: + if(format.sampleType() == QAudioFormat::SignedInt) { + if(format.byteOrder() == QAudioFormat::LittleEndian) + err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S32_LE); + else if(format.byteOrder() == QAudioFormat::BigEndian) + err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S32_BE); + } else if(format.sampleType() == QAudioFormat::UnSignedInt) { + if(format.byteOrder() == QAudioFormat::LittleEndian) + err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U32_LE); + else if(format.byteOrder() == QAudioFormat::BigEndian) + err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U32_BE); + } + } + + // For now, just accept only audio/pcm codec + if(!format.codec().startsWith(QLatin1String("audio/pcm"))) { + err=-1; + } else + testCodec = true; + + if(err>=0 && format.channels() != -1) { + err = snd_pcm_hw_params_test_channels(handle,params,format.channels()); + if(err>=0) + err = snd_pcm_hw_params_set_channels(handle,params,format.channels()); + if(err>=0) + testChannel = true; + } + + if(err>=0 && format.frequency() != -1) { + err = snd_pcm_hw_params_test_rate(handle,params,format.frequency(),0); + if(err>=0) + err = snd_pcm_hw_params_set_rate(handle,params,format.frequency(),dir); + if(err>=0) + testFreq = true; + } + + if((err>=0 && format.sampleSize() != -1) && + (format.sampleType() != QAudioFormat::Unknown)) { + switch(format.sampleSize()) { + case 8: + if(format.sampleType() == QAudioFormat::SignedInt) + err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S8); + else if(format.sampleType() == QAudioFormat::UnSignedInt) + err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U8); + break; + case 16: + if(format.sampleType() == QAudioFormat::SignedInt) { + if(format.byteOrder() == QAudioFormat::LittleEndian) + err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S16_LE); + else if(format.byteOrder() == QAudioFormat::BigEndian) + err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S16_BE); + } else if(format.sampleType() == QAudioFormat::UnSignedInt) { + if(format.byteOrder() == QAudioFormat::LittleEndian) + err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U16_LE); + else if(format.byteOrder() == QAudioFormat::BigEndian) + err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U16_BE); + } + break; + case 32: + if(format.sampleType() == QAudioFormat::SignedInt) { + if(format.byteOrder() == QAudioFormat::LittleEndian) + err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S32_LE); + else if(format.byteOrder() == QAudioFormat::BigEndian) + err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S32_BE); + } else if(format.sampleType() == QAudioFormat::UnSignedInt) { + if(format.byteOrder() == QAudioFormat::LittleEndian) + err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U32_LE); + else if(format.byteOrder() == QAudioFormat::BigEndian) + err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U32_BE); + } + } + if(err>=0) { + testSize = true; + testType = true; + } + } + if(err>=0) + err = snd_pcm_hw_params(handle, params); + + if(err == 0) { + // settings work + // close() + if(handle) + snd_pcm_close(handle); + return true; + } + if(handle) + snd_pcm_close(handle); + + return false; +} + +void QAudioDeviceInfoInternal::updateLists() +{ + // redo all lists based on current settings + freqz.clear(); + channelz.clear(); + sizez.clear(); + byteOrderz.clear(); + typez.clear(); + codecz.clear(); + + if(!handle) + open(); + + if(!handle) + return; + + for(int i=0; i<(int)MAX_SAMPLE_RATES; i++) { + //if(snd_pcm_hw_params_test_rate(handle, params, SAMPLE_RATES[i], dir) == 0) + freqz.append(SAMPLE_RATES[i]); + } + channelz.append(1); + channelz.append(2); + if (surround40) channelz.append(4); + if (surround51) channelz.append(6); + if (surround71) channelz.append(8); + sizez.append(8); + sizez.append(16); + sizez.append(32); + byteOrderz.append(QAudioFormat::LittleEndian); + byteOrderz.append(QAudioFormat::BigEndian); + typez.append(QAudioFormat::SignedInt); + typez.append(QAudioFormat::UnSignedInt); + typez.append(QAudioFormat::Float); + codecz.append(QLatin1String("audio/pcm")); + close(); +} + +QList<QByteArray> QAudioDeviceInfoInternal::availableDevices(QAudio::Mode mode) +{ + QList<QByteArray> allDevices; + QList<QByteArray> devices; + QByteArray filter; + +#if(SND_LIB_MAJOR == 1 && SND_LIB_MINOR == 0 && SND_LIB_SUBMINOR >= 14) + // Create a list of all current audio devices that support mode + void **hints, **n; + char *name, *descr, *io; + + if(snd_device_name_hint(-1, "pcm", &hints) < 0) { + qWarning() << "no alsa devices available"; + return devices; + } + n = hints; + + if(mode == QAudio::AudioInput) { + filter = "Input"; + } else { + filter = "Output"; + } + + while (*n != NULL) { + name = snd_device_name_get_hint(*n, "NAME"); + if (name != 0 && qstrcmp(name, "null") != 0) { + descr = snd_device_name_get_hint(*n, "DESC"); + io = snd_device_name_get_hint(*n, "IOID"); + + if ((descr != NULL) && ((io == NULL) || (io == filter))) { + QString deviceName = QLatin1String(name); + QString deviceDescription = QLatin1String(descr); + allDevices.append(deviceName.toLocal8Bit().constData()); + if (deviceDescription.contains(QLatin1String("Default Audio Device"))) + devices.append(deviceName.toLocal8Bit().constData()); + } + + free(name); + if (descr != NULL) + free(descr); + if (io != NULL) + free(io); + } + ++n; + } + snd_device_name_free_hint(hints); + + if(devices.size() > 0) { + devices.append("default"); + } +#else + int idx = 0; + char* name; + + while(snd_card_get_name(idx,&name) == 0) { + devices.append(name); + idx++; + } + if (idx > 0) + devices.append("default"); +#endif +#if !defined(Q_WS_MAEMO_6) + if (devices.size() == 0 && allDevices.size() > 0) + return allDevices; +#endif + + return devices; +} + +QByteArray QAudioDeviceInfoInternal::defaultInputDevice() +{ + QList<QByteArray> devices = availableDevices(QAudio::AudioInput); + if(devices.size() == 0) + return QByteArray(); + + return devices.first(); +} + +QByteArray QAudioDeviceInfoInternal::defaultOutputDevice() +{ + QList<QByteArray> devices = availableDevices(QAudio::AudioOutput); + if(devices.size() == 0) + return QByteArray(); + + return devices.first(); +} + +void QAudioDeviceInfoInternal::checkSurround() +{ + QList<QByteArray> devices; + surround40 = false; + surround51 = false; + surround71 = false; + + void **hints, **n; + char *name, *descr, *io; + + if(snd_device_name_hint(-1, "pcm", &hints) < 0) + return; + + n = hints; + + while (*n != NULL) { + name = snd_device_name_get_hint(*n, "NAME"); + descr = snd_device_name_get_hint(*n, "DESC"); + io = snd_device_name_get_hint(*n, "IOID"); + if((name != NULL) && (descr != NULL)) { + QString deviceName = QLatin1String(name); + if (mode == QAudio::AudioOutput) { + if(deviceName.contains(QLatin1String("surround40"))) + surround40 = true; + if(deviceName.contains(QLatin1String("surround51"))) + surround51 = true; + if(deviceName.contains(QLatin1String("surround71"))) + surround71 = true; + } + } + if(name != NULL) + free(name); + if(descr != NULL) + free(descr); + if(io != NULL) + free(io); + ++n; + } + snd_device_name_free_hint(hints); +} + +QT_END_NAMESPACE diff --git a/src/multimedia/audio/qaudiodeviceinfo_alsa_p.h b/src/multimedia/audio/qaudiodeviceinfo_alsa_p.h new file mode 100644 index 000000000..cf19d2554 --- /dev/null +++ b/src/multimedia/audio/qaudiodeviceinfo_alsa_p.h @@ -0,0 +1,129 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + + +#ifndef QAUDIODEVICEINFOALSA_H +#define QAUDIODEVICEINFOALSA_H + +#include <alsa/asoundlib.h> + +#include <QtCore/qbytearray.h> +#include <QtCore/qstringlist.h> +#include <QtCore/qlist.h> +#include <QtCore/qdebug.h> + +#include "qaudio.h" +#include "qaudiodeviceinfo.h" +#include "qaudiosystem.h" + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + +const unsigned int MAX_SAMPLE_RATES = 5; +const unsigned int SAMPLE_RATES[] = + { 8000, 11025, 22050, 44100, 48000 }; + +class QAudioDeviceInfoInternal : public QAbstractAudioDeviceInfo +{ + Q_OBJECT +public: + QAudioDeviceInfoInternal(QByteArray dev,QAudio::Mode mode); + ~QAudioDeviceInfoInternal(); + + bool testSettings(const QAudioFormat& format) const; + void updateLists(); + QAudioFormat preferredFormat() const; + bool isFormatSupported(const QAudioFormat& format) const; + QString deviceName() const; + QStringList supportedCodecs(); + QList<int> supportedSampleRates(); + QList<int> supportedChannelCounts(); + QList<int> supportedSampleSizes(); + QList<QAudioFormat::Endian> supportedByteOrders(); + QList<QAudioFormat::SampleType> supportedSampleTypes(); + static QByteArray defaultInputDevice(); + static QByteArray defaultOutputDevice(); + static QList<QByteArray> availableDevices(QAudio::Mode); + +private: + bool open(); + void close(); + + void checkSurround(); + bool surround40; + bool surround51; + bool surround71; + + QString device; + QAudio::Mode mode; + QAudioFormat nearest; + QList<int> freqz; + QList<int> channelz; + QList<int> sizez; + QList<QAudioFormat::Endian> byteOrderz; + QStringList codecz; + QList<QAudioFormat::SampleType> typez; + snd_pcm_t* handle; + snd_pcm_hw_params_t *params; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + + +#endif + diff --git a/src/multimedia/audio/qaudiodeviceinfo_mac_p.cpp b/src/multimedia/audio/qaudiodeviceinfo_mac_p.cpp new file mode 100644 index 000000000..4c7779f91 --- /dev/null +++ b/src/multimedia/audio/qaudiodeviceinfo_mac_p.cpp @@ -0,0 +1,351 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// INTERNAL USE ONLY: Do NOT use for any other purpose. +// + +#include <QtCore/qstringlist.h> +#include <QtCore/qlist.h> +#include <QtCore/qbytearray.h> +#include <QtCore/qdatastream.h> +#include <QtCore/qdebug.h> + +#include <qaudiodeviceinfo.h> +#include "qaudio_mac_p.h" +#include "qaudiodeviceinfo_mac_p.h" + + + +QT_BEGIN_NAMESPACE + +// XXX: remove at some future date +static inline QString cfStringToQString(CFStringRef str) +{ + CFIndex length = CFStringGetLength(str); + const UniChar *chars = CFStringGetCharactersPtr(str); + if (chars) + return QString(reinterpret_cast<const QChar *>(chars), length); + + UniChar buffer[length]; + CFStringGetCharacters(str, CFRangeMake(0, length), buffer); + return QString(reinterpret_cast<const QChar *>(buffer), length); +} + +QAudioDeviceInfoInternal::QAudioDeviceInfoInternal(QByteArray const& handle, QAudio::Mode) +{ + QDataStream ds(handle); + quint32 did, tm; + + ds >> did >> tm >> name; + deviceId = AudioDeviceID(did); + mode = QAudio::Mode(tm); +} + +bool QAudioDeviceInfoInternal::isFormatSupported(const QAudioFormat& format) const +{ + QAudioDeviceInfoInternal *self = const_cast<QAudioDeviceInfoInternal*>(this); + + return format.isValid() + && format.codec() == QString::fromLatin1("audio/pcm") + && self->supportedSampleRates().contains(format.sampleRate()) + && self->supportedChannelCounts().contains(format.channelCount()) + && self->supportedSampleSizes().contains(format.sampleSize()); +} + +QAudioFormat QAudioDeviceInfoInternal::preferredFormat() const +{ + QAudioFormat rc; + + UInt32 propSize = 0; + + if (AudioDeviceGetPropertyInfo(deviceId, + 0, + mode == QAudio::AudioInput, + kAudioDevicePropertyStreams, + &propSize, + 0) == noErr) { + + const int sc = propSize / sizeof(AudioStreamID); + + if (sc > 0) { + AudioStreamID* streams = new AudioStreamID[sc]; + + if (AudioDeviceGetProperty(deviceId, + 0, + mode == QAudio::AudioInput, + kAudioDevicePropertyStreams, + &propSize, + streams) == noErr) { + + for (int i = 0; i < sc; ++i) { + if (AudioStreamGetPropertyInfo(streams[i], + 0, + kAudioStreamPropertyPhysicalFormat, + &propSize, + 0) == noErr) { + + AudioStreamBasicDescription sf; + + if (AudioStreamGetProperty(streams[i], + 0, + kAudioStreamPropertyPhysicalFormat, + &propSize, + &sf) == noErr) { + rc = toQAudioFormat(sf); + break; + } + } + } + } + + delete streams; + } + } + + return rc; +} + +QString QAudioDeviceInfoInternal::deviceName() const +{ + return name; +} + +QStringList QAudioDeviceInfoInternal::supportedCodecs() +{ + return QStringList() << QString::fromLatin1("audio/pcm"); +} + +QList<int> QAudioDeviceInfoInternal::supportedSampleRates() +{ + QSet<int> rc; + + // Add some common frequencies + rc << 8000 << 11025 << 22050 << 44100; + + // + UInt32 propSize = 0; + + if (AudioDeviceGetPropertyInfo(deviceId, + 0, + mode == QAudio::AudioInput, + kAudioDevicePropertyAvailableNominalSampleRates, + &propSize, + 0) == noErr) { + + const int pc = propSize / sizeof(AudioValueRange); + + if (pc > 0) { + AudioValueRange* vr = new AudioValueRange[pc]; + + if (AudioDeviceGetProperty(deviceId, + 0, + mode == QAudio::AudioInput, + kAudioDevicePropertyAvailableNominalSampleRates, + &propSize, + vr) == noErr) { + + for (int i = 0; i < pc; ++i) + rc << vr[i].mMaximum; + } + + delete vr; + } + } + + return rc.toList(); +} + +QList<int> QAudioDeviceInfoInternal::supportedChannelCounts() +{ + QList<int> rc; + + // Can mix down to 1 channel + rc << 1; + + UInt32 propSize = 0; + int channels = 0; + + if (AudioDeviceGetPropertyInfo(deviceId, + 0, + mode == QAudio::AudioInput, + kAudioDevicePropertyStreamConfiguration, + &propSize, + 0) == noErr) { + + AudioBufferList* audioBufferList = static_cast<AudioBufferList*>(qMalloc(propSize)); + + if (audioBufferList != 0) { + if (AudioDeviceGetProperty(deviceId, + 0, + mode == QAudio::AudioInput, + kAudioDevicePropertyStreamConfiguration, + &propSize, + audioBufferList) == noErr) { + + for (int i = 0; i < int(audioBufferList->mNumberBuffers); ++i) { + channels += audioBufferList->mBuffers[i].mNumberChannels; + rc << channels; + } + } + + qFree(audioBufferList); + } + } + + return rc; +} + +QList<int> QAudioDeviceInfoInternal::supportedSampleSizes() +{ + return QList<int>() << 8 << 16 << 24 << 32 << 64; +} + +QList<QAudioFormat::Endian> QAudioDeviceInfoInternal::supportedByteOrders() +{ + return QList<QAudioFormat::Endian>() << QAudioFormat::LittleEndian << QAudioFormat::BigEndian; +} + +QList<QAudioFormat::SampleType> QAudioDeviceInfoInternal::supportedSampleTypes() +{ + return QList<QAudioFormat::SampleType>() << QAudioFormat::SignedInt << QAudioFormat::UnSignedInt << QAudioFormat::Float; +} + +static QByteArray get_device_info(AudioDeviceID audioDevice, QAudio::Mode mode) +{ + UInt32 size; + QByteArray device; + QDataStream ds(&device, QIODevice::WriteOnly); + AudioStreamBasicDescription sf; + CFStringRef name; + Boolean isInput = mode == QAudio::AudioInput; + + // Id + ds << quint32(audioDevice); + + // Mode + size = sizeof(AudioStreamBasicDescription); + if (AudioDeviceGetProperty(audioDevice, 0, isInput, kAudioDevicePropertyStreamFormat, + &size, &sf) != noErr) { + return QByteArray(); + } + ds << quint32(mode); + + // Name + size = sizeof(CFStringRef); + if (AudioDeviceGetProperty(audioDevice, 0, isInput, kAudioObjectPropertyName, + &size, &name) != noErr) { + qWarning() << "QAudioDeviceInfo: Unable to find device name"; + return QByteArray(); + } + ds << cfStringToQString(name); + + CFRelease(name); + + return device; +} + +QByteArray QAudioDeviceInfoInternal::defaultInputDevice() +{ + AudioDeviceID audioDevice; + UInt32 size = sizeof(audioDevice); + + if (AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, &size, + &audioDevice) != noErr) { + qWarning() << "QAudioDeviceInfo: Unable to find default input device"; + return QByteArray(); + } + + return get_device_info(audioDevice, QAudio::AudioInput); +} + +QByteArray QAudioDeviceInfoInternal::defaultOutputDevice() +{ + AudioDeviceID audioDevice; + UInt32 size = sizeof(audioDevice); + + if (AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, &size, + &audioDevice) != noErr) { + qWarning() << "QAudioDeviceInfo: Unable to find default output device"; + return QByteArray(); + } + + return get_device_info(audioDevice, QAudio::AudioOutput); +} + +QList<QByteArray> QAudioDeviceInfoInternal::availableDevices(QAudio::Mode mode) +{ + QList<QByteArray> devices; + + UInt32 propSize = 0; + + if (AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, &propSize, 0) == noErr) { + + const int dc = propSize / sizeof(AudioDeviceID); + + if (dc > 0) { + AudioDeviceID* audioDevices = new AudioDeviceID[dc]; + + if (AudioHardwareGetProperty(kAudioHardwarePropertyDevices, &propSize, audioDevices) == noErr) { + for (int i = 0; i < dc; ++i) { + QByteArray info = get_device_info(audioDevices[i], mode); + if (!info.isNull()) + devices << info; + } + } + + delete audioDevices; + } + } + + return devices; +} + + +QT_END_NAMESPACE + diff --git a/src/multimedia/audio/qaudiodeviceinfo_mac_p.h b/src/multimedia/audio/qaudiodeviceinfo_mac_p.h new file mode 100644 index 000000000..3b9ca4676 --- /dev/null +++ b/src/multimedia/audio/qaudiodeviceinfo_mac_p.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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + + +#ifndef QDEVICEINFO_MAC_P_H +#define QDEVICEINFO_MAC_P_H + +#include <CoreAudio/CoreAudio.h> + +#include <qaudiosystem.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + +class QAudioDeviceInfoInternal : public QAbstractAudioDeviceInfo +{ +public: + AudioDeviceID deviceId; + QString name; + QAudio::Mode mode; + + QAudioDeviceInfoInternal(QByteArray const& handle, QAudio::Mode mode); + + bool isFormatSupported(const QAudioFormat& format) const; + QAudioFormat preferredFormat() const; + + QString deviceName() const; + + QStringList supportedCodecs(); + QList<int> supportedSampleRates(); + QList<int> supportedChannelCounts(); + QList<int> supportedSampleSizes(); + QList<QAudioFormat::Endian> supportedByteOrders(); + QList<QAudioFormat::SampleType> supportedSampleTypes(); + + static QByteArray defaultInputDevice(); + static QByteArray defaultOutputDevice(); + + static QList<QByteArray> availableDevices(QAudio::Mode mode); +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QDEVICEINFO_MAC_P_H diff --git a/src/multimedia/audio/qaudiodeviceinfo_win32_p.cpp b/src/multimedia/audio/qaudiodeviceinfo_win32_p.cpp new file mode 100644 index 000000000..10b9b777d --- /dev/null +++ b/src/multimedia/audio/qaudiodeviceinfo_win32_p.cpp @@ -0,0 +1,465 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// INTERNAL USE ONLY: Do NOT use for any other purpose. +// + + +#include <windows.h> +#include <mmsystem.h> +#include "qaudiodeviceinfo_win32_p.h" +#include <dshow.h> + +#if defined(Q_CC_MINGW) + +extern GUID CLSID_AudioInputDeviceCategory; + +#ifndef __IErrorLog_INTERFACE_DEFINED__ +#define __IErrorLog_INTERFACE_DEFINED__ + +DECLARE_INTERFACE_(IErrorLog, IUnknown) +{ + STDMETHOD(AddError)(THIS_ LPCOLESTR, EXCEPINFO *) PURE; +}; + +#endif /* __IErrorLog_INTERFACE_DEFINED__ */ + +#ifndef __IPropertyBag_INTERFACE_DEFINED__ +#define __IPropertyBag_INTERFACE_DEFINED__ + +const GUID IID_IPropertyBag = {0x55272A00, 0x42CB, 0x11CE, {0x81, 0x35, 0x00, 0xAA, 0x00, 0x4B, 0xB8, 0x51}}; + +DECLARE_INTERFACE_(IPropertyBag, IUnknown) +{ + STDMETHOD(Read)(THIS_ LPCOLESTR, VARIANT *, IErrorLog *) PURE; + STDMETHOD(Write)(THIS_ LPCOLESTR, VARIANT *) PURE; +}; + +#endif /* __IPropertyBag_INTERFACE_DEFINED__ */ + +#endif//Q_CC_MINGW + +QT_BEGIN_NAMESPACE + +// For mingw toolchain mmsystem.h only defines half the defines, so add if needed. +#ifndef WAVE_FORMAT_44M08 +#define WAVE_FORMAT_44M08 0x00000100 +#define WAVE_FORMAT_44S08 0x00000200 +#define WAVE_FORMAT_44M16 0x00000400 +#define WAVE_FORMAT_44S16 0x00000800 +#define WAVE_FORMAT_48M08 0x00001000 +#define WAVE_FORMAT_48S08 0x00002000 +#define WAVE_FORMAT_48M16 0x00004000 +#define WAVE_FORMAT_48S16 0x00008000 +#define WAVE_FORMAT_96M08 0x00010000 +#define WAVE_FORMAT_96S08 0x00020000 +#define WAVE_FORMAT_96M16 0x00040000 +#define WAVE_FORMAT_96S16 0x00080000 +#endif + + +QAudioDeviceInfoInternal::QAudioDeviceInfoInternal(QByteArray dev, QAudio::Mode mode) +{ + QDataStream ds(&dev, QIODevice::ReadOnly); + ds >> devId >> device; + this->mode = mode; + + updateLists(); +} + +QAudioDeviceInfoInternal::~QAudioDeviceInfoInternal() +{ + close(); +} + +bool QAudioDeviceInfoInternal::isFormatSupported(const QAudioFormat& format) const +{ + return testSettings(format); +} + +QAudioFormat QAudioDeviceInfoInternal::preferredFormat() const +{ + QAudioFormat nearest; + if(mode == QAudio::AudioOutput) { + nearest.setFrequency(44100); + nearest.setChannelCount(2); + nearest.setByteOrder(QAudioFormat::LittleEndian); + nearest.setSampleType(QAudioFormat::SignedInt); + nearest.setSampleSize(16); + nearest.setCodec(QLatin1String("audio/pcm")); + } else { + nearest.setFrequency(11025); + nearest.setChannelCount(1); + nearest.setByteOrder(QAudioFormat::LittleEndian); + nearest.setSampleType(QAudioFormat::SignedInt); + nearest.setSampleSize(8); + nearest.setCodec(QLatin1String("audio/pcm")); + } + return nearest; +} + +QString QAudioDeviceInfoInternal::deviceName() const +{ + return device; +} + +QStringList QAudioDeviceInfoInternal::supportedCodecs() +{ + updateLists(); + return codecz; +} + +QList<int> QAudioDeviceInfoInternal::supportedSampleRates() +{ + updateLists(); + return freqz; +} + +QList<int> QAudioDeviceInfoInternal::supportedChannelCounts() +{ + updateLists(); + return channelz; +} + +QList<int> QAudioDeviceInfoInternal::supportedSampleSizes() +{ + updateLists(); + return sizez; +} + +QList<QAudioFormat::Endian> QAudioDeviceInfoInternal::supportedByteOrders() +{ + updateLists(); + return byteOrderz; +} + +QList<QAudioFormat::SampleType> QAudioDeviceInfoInternal::supportedSampleTypes() +{ + updateLists(); + return typez; +} + + +bool QAudioDeviceInfoInternal::open() +{ + return true; +} + +void QAudioDeviceInfoInternal::close() +{ +} + +bool QAudioDeviceInfoInternal::testSettings(const QAudioFormat& format) const +{ + // Set nearest to closest settings that do work. + // See if what is in settings will work (return value). + + bool failed = false; + bool match = false; + + // check codec + for( int i = 0; i < codecz.count(); i++) { + if (format.codec() == codecz.at(i)) + match = true; + } + if (!match) failed = true; + + // check channel + match = false; + if (!failed) { + for( int i = 0; i < channelz.count(); i++) { + if (format.channels() == channelz.at(i)) { + match = true; + break; + } + } + if (!match) + failed = true; + } + + // check frequency + match = false; + if (!failed) { + for( int i = 0; i < freqz.count(); i++) { + if (format.frequency() == freqz.at(i)) { + match = true; + break; + } + } + if (!match) + failed = true; + } + + // check sample size + match = false; + if (!failed) { + for( int i = 0; i < sizez.count(); i++) { + if (format.sampleSize() == sizez.at(i)) { + match = true; + break; + } + } + if (!match) + failed = true; + } + + // check byte order + match = false; + if (!failed) { + for( int i = 0; i < byteOrderz.count(); i++) { + if (format.byteOrder() == byteOrderz.at(i)) { + match = true; + break; + } + } + if (!match) + failed = true; + } + + // check sample type + match = false; + if (!failed) { + for( int i = 0; i < typez.count(); i++) { + if (format.sampleType() == typez.at(i)) { + match = true; + break; + } + } + if (!match) + failed = true; + } + + if(!failed) { + // settings work + return true; + } + return false; +} + +void QAudioDeviceInfoInternal::updateLists() +{ + // redo all lists based on current settings + bool match = false; + DWORD fmt = NULL; + + if(mode == QAudio::AudioOutput) { + WAVEOUTCAPS woc; + if (waveOutGetDevCaps(devId, &woc, sizeof(WAVEOUTCAPS)) == MMSYSERR_NOERROR) { + match = true; + fmt = woc.dwFormats; + } + } else { + WAVEINCAPS woc; + if (waveInGetDevCaps(devId, &woc, sizeof(WAVEINCAPS)) == MMSYSERR_NOERROR) { + match = true; + fmt = woc.dwFormats; + } + } + sizez.clear(); + freqz.clear(); + channelz.clear(); + byteOrderz.clear(); + typez.clear(); + codecz.clear(); + + if(match) { + if((fmt && WAVE_FORMAT_1M08) + || (fmt && WAVE_FORMAT_1S08) + || (fmt && WAVE_FORMAT_2M08) + || (fmt && WAVE_FORMAT_2S08) + || (fmt && WAVE_FORMAT_4M08) + || (fmt && WAVE_FORMAT_4S08) + || (fmt && WAVE_FORMAT_48M08) + || (fmt && WAVE_FORMAT_48S08) + || (fmt && WAVE_FORMAT_96M08) + || (fmt && WAVE_FORMAT_96S08) + ) { + sizez.append(8); + } + if((fmt && WAVE_FORMAT_1M16) + || (fmt && WAVE_FORMAT_1S16) + || (fmt && WAVE_FORMAT_2M16) + || (fmt && WAVE_FORMAT_2S16) + || (fmt && WAVE_FORMAT_4M16) + || (fmt && WAVE_FORMAT_4S16) + || (fmt && WAVE_FORMAT_48M16) + || (fmt && WAVE_FORMAT_48S16) + || (fmt && WAVE_FORMAT_96M16) + || (fmt && WAVE_FORMAT_96S16) + ) { + sizez.append(16); + } + if((fmt && WAVE_FORMAT_1M08) + || (fmt && WAVE_FORMAT_1S08) + || (fmt && WAVE_FORMAT_1M16) + || (fmt && WAVE_FORMAT_1S16)) { + freqz.append(11025); + } + if((fmt && WAVE_FORMAT_2M08) + || (fmt && WAVE_FORMAT_2S08) + || (fmt && WAVE_FORMAT_2M16) + || (fmt && WAVE_FORMAT_2S16)) { + freqz.append(22050); + } + if((fmt && WAVE_FORMAT_4M08) + || (fmt && WAVE_FORMAT_4S08) + || (fmt && WAVE_FORMAT_4M16) + || (fmt && WAVE_FORMAT_4S16)) { + freqz.append(44100); + } + if((fmt && WAVE_FORMAT_48M08) + || (fmt && WAVE_FORMAT_48S08) + || (fmt && WAVE_FORMAT_48M16) + || (fmt && WAVE_FORMAT_48S16)) { + freqz.append(48000); + } + if((fmt && WAVE_FORMAT_96M08) + || (fmt && WAVE_FORMAT_96S08) + || (fmt && WAVE_FORMAT_96M16) + || (fmt && WAVE_FORMAT_96S16)) { + freqz.append(96000); + } + channelz.append(1); + channelz.append(2); + if (mode == QAudio::AudioOutput) { + channelz.append(4); + channelz.append(6); + channelz.append(8); + } + + byteOrderz.append(QAudioFormat::LittleEndian); + + typez.append(QAudioFormat::SignedInt); + typez.append(QAudioFormat::UnSignedInt); + + codecz.append(QLatin1String("audio/pcm")); + } + if (freqz.count() > 0) + freqz.prepend(8000); +} + +QList<QByteArray> QAudioDeviceInfoInternal::availableDevices(QAudio::Mode mode) +{ + Q_UNUSED(mode) + + QList<QByteArray> devices; + //enumerate device fullnames through directshow api + CoInitialize(NULL); + ICreateDevEnum *pDevEnum = NULL; + IEnumMoniker *pEnum = NULL; + // Create the System device enumerator + HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, + CLSCTX_INPROC_SERVER, IID_ICreateDevEnum, + reinterpret_cast<void **>(&pDevEnum)); + + unsigned long iNumDevs = mode == QAudio::AudioOutput ? waveOutGetNumDevs() : waveInGetNumDevs(); + if (SUCCEEDED(hr)) { + // Create the enumerator for the audio input/output category + if (pDevEnum->CreateClassEnumerator( + mode == QAudio::AudioOutput ? CLSID_AudioRendererCategory : CLSID_AudioInputDeviceCategory, + &pEnum, 0) == S_OK) { + pEnum->Reset(); + // go through and find all audio devices + IMoniker *pMoniker = NULL; + while (pEnum->Next(1, &pMoniker, NULL) == S_OK) { + IPropertyBag *pPropBag; + hr = pMoniker->BindToStorage(0,0,IID_IPropertyBag, + reinterpret_cast<void **>(&pPropBag)); + if (FAILED(hr)) { + pMoniker->Release(); + continue; // skip this one + } + // Find if it is a wave device + VARIANT var; + VariantInit(&var); + hr = pPropBag->Read(mode == QAudio::AudioOutput ? L"WaveOutID" : L"WaveInID", &var, 0); + if (SUCCEEDED(hr)) { + LONG waveID = var.lVal; + if (waveID >= 0 && waveID < LONG(iNumDevs)) { + VariantClear(&var); + // Find the description + hr = pPropBag->Read(L"FriendlyName", &var, 0); + if (SUCCEEDED(hr)) { + QByteArray device; + QDataStream ds(&device, QIODevice::WriteOnly); + ds << quint32(waveID) << QString::fromWCharArray(var.bstrVal); + devices.append(device); + } + } + } + + pPropBag->Release(); + pMoniker->Release(); + } + } + } + CoUninitialize(); + + return devices; +} + +QByteArray QAudioDeviceInfoInternal::defaultOutputDevice() +{ + QList<QByteArray> list = availableDevices(QAudio::AudioOutput); + if (list.size() > 0) + return list.at(0); + else + return QByteArray(); +} + +QByteArray QAudioDeviceInfoInternal::defaultInputDevice() +{ + QList<QByteArray> list = availableDevices(QAudio::AudioInput); + if (list.size() > 0) + return list.at(0); + else + return QByteArray(); +} + +QT_END_NAMESPACE diff --git a/src/multimedia/audio/qaudiodeviceinfo_win32_p.h b/src/multimedia/audio/qaudiodeviceinfo_win32_p.h new file mode 100644 index 000000000..2d4e27106 --- /dev/null +++ b/src/multimedia/audio/qaudiodeviceinfo_win32_p.h @@ -0,0 +1,120 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + + +#ifndef QAUDIODEVICEINFOWIN_H +#define QAUDIODEVICEINFOWIN_H + +#include <QtCore/qbytearray.h> +#include <QtCore/qstringlist.h> +#include <QtCore/qlist.h> +#include <QtCore/qdebug.h> + +#include <qaudiodeviceinfo.h> +#include <qaudiosystem.h> + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + +const unsigned int MAX_SAMPLE_RATES = 5; +const unsigned int SAMPLE_RATES[] = { 8000, 11025, 22050, 44100, 48000 }; + +class QAudioDeviceInfoInternal : public QAbstractAudioDeviceInfo +{ + Q_OBJECT + +public: + QAudioDeviceInfoInternal(QByteArray dev,QAudio::Mode mode); + ~QAudioDeviceInfoInternal(); + + bool open(); + void close(); + + bool testSettings(const QAudioFormat& format) const; + void updateLists(); + QAudioFormat preferredFormat() const; + bool isFormatSupported(const QAudioFormat& format) const; + QString deviceName() const; + QStringList supportedCodecs(); + QList<int> supportedSampleRates(); + QList<int> supportedChannelCounts(); + QList<int> supportedSampleSizes(); + QList<QAudioFormat::Endian> supportedByteOrders(); + QList<QAudioFormat::SampleType> supportedSampleTypes(); + static QByteArray defaultInputDevice(); + static QByteArray defaultOutputDevice(); + static QList<QByteArray> availableDevices(QAudio::Mode); + +private: + QAudio::Mode mode; + QString device; + quint32 devId; + QAudioFormat nearest; + QList<int> freqz; + QList<int> channelz; + QList<int> sizez; + QList<QAudioFormat::Endian> byteOrderz; + QStringList codecz; + QList<QAudioFormat::SampleType> typez; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + + +#endif diff --git a/src/multimedia/audio/qaudioformat.cpp b/src/multimedia/audio/qaudioformat.cpp new file mode 100644 index 000000000..6ed72516c --- /dev/null +++ b/src/multimedia/audio/qaudioformat.cpp @@ -0,0 +1,407 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include <QDebug> +#include <qaudioformat.h> + + +QT_BEGIN_NAMESPACE + + +class QAudioFormatPrivate : public QSharedData +{ +public: + QAudioFormatPrivate() + { + frequency = -1; + channels = -1; + sampleSize = -1; + byteOrder = QAudioFormat::Endian(QSysInfo::ByteOrder); + sampleType = QAudioFormat::Unknown; + } + + QAudioFormatPrivate(const QAudioFormatPrivate &other): + QSharedData(other), + codec(other.codec), + byteOrder(other.byteOrder), + sampleType(other.sampleType), + frequency(other.frequency), + channels(other.channels), + sampleSize(other.sampleSize) + { + } + + QAudioFormatPrivate& operator=(const QAudioFormatPrivate &other) + { + codec = other.codec; + byteOrder = other.byteOrder; + sampleType = other.sampleType; + frequency = other.frequency; + channels = other.channels; + sampleSize = other.sampleSize; + + return *this; + } + + QString codec; + QAudioFormat::Endian byteOrder; + QAudioFormat::SampleType sampleType; + int frequency; + int channels; + int sampleSize; +}; + +/*! + \class QAudioFormat + \brief The QAudioFormat class stores audio stream parameter information. + + \inmodule QtMultimedia + \ingroup multimedia + \since 1.0 + + An audio format specifies how data in an audio stream is arranged, + i.e, how the stream is to be interpreted. The encoding itself is + specified by the codec() used for the stream. + + In addition to the encoding, QAudioFormat contains other + parameters that further specify how the audio sample data is arranged. + These are the frequency, the number of channels, the sample size, + the sample type, and the byte order. The following table describes + these in more detail. + + \table + \header + \o Parameter + \o Description + \row + \o Sample Rate + \o Samples per second of audio data in Hertz. + \row + \o Number of channels + \o The number of audio channels (typically one for mono + or two for stereo) + \row + \o Sample size + \o How much data is stored in each sample (typically 8 + or 16 bits) + \row + \o Sample type + \o Numerical representation of sample (typically signed integer, + unsigned integer or float) + \row + \o Byte order + \o Byte ordering of sample (typically little endian, big endian) + \endtable + + This class is typically used in conjunction with QAudioInput or + QAudioOutput to allow you to specify the parameters of the audio + stream being read or written. + + You can obtain audio formats compatible with the audio device used + through functions in QAudioDeviceInfo. This class also lets you + query available parameter values for a device, so that you can set + the parameters yourself. See the \l QAudioDeviceInfo class + description for details. You need to know the format of the audio + streams you wish to play or record. +*/ + +/*! + Construct a new audio format. + + Values are initialized as follows: + \list + \o sampleRate() = -1 + \o channelCount() = -1 + \o sampleSize() = -1 + \o byteOrder() = QAudioFormat::Endian(QSysInfo::ByteOrder) + \o sampleType() = QAudioFormat::Unknown + \c codec() = "" + \endlist +*/ +QAudioFormat::QAudioFormat(): + d(new QAudioFormatPrivate) +{ +} + +/*! + Construct a new audio format using \a other. + \since 1.0 +*/ +QAudioFormat::QAudioFormat(const QAudioFormat &other): + d(other.d) +{ +} + +/*! + Destroy this audio format. +*/ +QAudioFormat::~QAudioFormat() +{ +} + +/*! + Assigns \a other to this QAudioFormat implementation. + \since 1.0 +*/ +QAudioFormat& QAudioFormat::operator=(const QAudioFormat &other) +{ + d = other.d; + return *this; +} + +/*! + Returns true if this QAudioFormat is equal to the \a other + QAudioFormat; otherwise returns false. + + All elements of QAudioFormat are used for the comparison. + \since 1.0 +*/ +bool QAudioFormat::operator==(const QAudioFormat &other) const +{ + return d->frequency == other.d->frequency && + d->channels == other.d->channels && + d->sampleSize == other.d->sampleSize && + d->byteOrder == other.d->byteOrder && + d->codec == other.d->codec && + d->sampleType == other.d->sampleType; +} + +/*! + Returns true if this QAudioFormat is not equal to the \a other + QAudioFormat; otherwise returns false. + + All elements of QAudioFormat are used for the comparison. + \since 1.0 +*/ +bool QAudioFormat::operator!=(const QAudioFormat& other) const +{ + return !(*this == other); +} + +/*! + Returns true if all of the parameters are valid. + \since 1.0 +*/ +bool QAudioFormat::isValid() const +{ + return d->frequency != -1 && d->channels != -1 && d->sampleSize != -1 && + d->sampleType != QAudioFormat::Unknown && !d->codec.isEmpty(); +} + +/*! + Sets the sample rate to \a samplerate Hertz. + + \since 1.0 +*/ +void QAudioFormat::setSampleRate(int samplerate) +{ + d->frequency = samplerate; +} + +/*! + \obsolete + + Use setSampleRate() instead. +*/ +void QAudioFormat::setFrequency(int frequency) +{ + d->frequency = frequency; +} + +/*! + Returns the current sample rate in Hertz. + + \since 1.0 +*/ +int QAudioFormat::sampleRate() const +{ + return d->frequency; +} + +/*! + \obsolete + + Use sampleRate() instead. +*/ +int QAudioFormat::frequency() const +{ + return d->frequency; +} + +/*! + Sets the channel count to \a channels. + + \since 1.0 +*/ +void QAudioFormat::setChannelCount(int channels) +{ + d->channels = channels; +} + +/*! + \obsolete + + Use setChannelCount() instead. +*/ +void QAudioFormat::setChannels(int channels) +{ + d->channels = channels; +} + +/*! + Returns the current channel count value. + + \since 1.0 +*/ +int QAudioFormat::channelCount() const +{ + return d->channels; +} + +/*! + \obsolete + + Use channelCount() instead. +*/ +int QAudioFormat::channels() const +{ + return d->channels; +} + +/*! + Sets the sample size to the \a sampleSize specified, in bits. + + This is typically 8 or 16, but some systems may support higher sample sizes. + \since 1.0 +*/ +void QAudioFormat::setSampleSize(int sampleSize) +{ + d->sampleSize = sampleSize; +} + +/*! + Returns the current sample size value, in bits. + \since 1.0 +*/ +int QAudioFormat::sampleSize() const +{ + return d->sampleSize; +} + +/*! + Sets the codec to \a codec. + + The parameter to this function should be one of the types + reported by the QAudioDeviceInfo::supportedCodecs() function + for the audio device you are working with. + + \since 1.0 + \sa QAudioDeviceInfo::supportedCodecs() +*/ +void QAudioFormat::setCodec(const QString &codec) +{ + d->codec = codec; +} + +/*! + Returns the current codec identifier. + + \since 1.0 + \sa QAudioDeviceInfo::supportedCodecs() +*/ +QString QAudioFormat::codec() const +{ + return d->codec; +} + +/*! + Sets the byteOrder to \a byteOrder. + \since 1.0 +*/ +void QAudioFormat::setByteOrder(QAudioFormat::Endian byteOrder) +{ + d->byteOrder = byteOrder; +} + +/*! + Returns the current byteOrder value. + \since 1.0 +*/ +QAudioFormat::Endian QAudioFormat::byteOrder() const +{ + return d->byteOrder; +} + +/*! + Sets the sampleType to \a sampleType. + \since 1.0 +*/ +void QAudioFormat::setSampleType(QAudioFormat::SampleType sampleType) +{ + d->sampleType = sampleType; +} + +/*! + Returns the current SampleType value. + \since 1.0 +*/ +QAudioFormat::SampleType QAudioFormat::sampleType() const +{ + return d->sampleType; +} + +/*! + \enum QAudioFormat::SampleType + + \value Unknown Not Set + \value SignedInt Samples are signed integers + \value UnSignedInt Samples are unsigned intergers + \value Float Samples are floats +*/ + +/*! + \enum QAudioFormat::Endian + + \value BigEndian Samples are big endian byte order + \value LittleEndian Samples are little endian byte order +*/ + +QT_END_NAMESPACE + diff --git a/src/multimedia/audio/qaudioformat.h b/src/multimedia/audio/qaudioformat.h new file mode 100644 index 000000000..087a16a9d --- /dev/null +++ b/src/multimedia/audio/qaudioformat.h @@ -0,0 +1,109 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#ifndef QAUDIOFORMAT_H +#define QAUDIOFORMAT_H + +#include <QtCore/qobject.h> +#include <QtCore/qshareddata.h> + +#include <qtmultimediadefs.h> +#include <qtmedianamespace.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + + +class QAudioFormatPrivate; + +class Q_MULTIMEDIA_EXPORT QAudioFormat +{ +public: + enum SampleType { Unknown, SignedInt, UnSignedInt, Float }; + enum Endian { BigEndian = QSysInfo::BigEndian, LittleEndian = QSysInfo::LittleEndian }; + + QAudioFormat(); + QAudioFormat(const QAudioFormat &other); + ~QAudioFormat(); + + QAudioFormat& operator=(const QAudioFormat &other); + bool operator==(const QAudioFormat &other) const; + bool operator!=(const QAudioFormat &other) const; + + bool isValid() const; + + void setFrequency(int frequency); + int frequency() const; + void setSampleRate(int sampleRate); + int sampleRate() const; + + void setChannels(int channels); + int channels() const; + void setChannelCount(int channelCount); + int channelCount() const; + + void setSampleSize(int sampleSize); + int sampleSize() const; + + void setCodec(const QString &codec); + QString codec() const; + + void setByteOrder(QAudioFormat::Endian byteOrder); + QAudioFormat::Endian byteOrder() const; + + void setSampleType(QAudioFormat::SampleType sampleType); + QAudioFormat::SampleType sampleType() const; + +private: + QSharedDataPointer<QAudioFormatPrivate> d; +}; + + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QAUDIOFORMAT_H diff --git a/src/multimedia/audio/qaudioinput.cpp b/src/multimedia/audio/qaudioinput.cpp new file mode 100644 index 000000000..2a5cefcc5 --- /dev/null +++ b/src/multimedia/audio/qaudioinput.cpp @@ -0,0 +1,402 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include "qaudio.h" +#include "qaudiodeviceinfo.h" +#include "qaudiosystem.h" +#include "qaudioinput.h" + +#include "qaudiodevicefactory_p.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QAudioInput + \brief The QAudioInput class provides an interface for receiving audio data from an audio input device. + + \inmodule QtMultimedia + \ingroup multimedia + \since 1.0 + + You can construct an audio input with the system's + \l{QAudioDeviceInfo::defaultInputDevice()}{default audio input + device}. It is also possible to create QAudioInput with a + specific QAudioDeviceInfo. When you create the audio input, you + should also send in the QAudioFormat to be used for the recording + (see the QAudioFormat class description for details). + + To record to a file: + + QAudioInput lets you record audio with an audio input device. The + default constructor of this class will use the systems default + audio device, but you can also specify a QAudioDeviceInfo for a + specific device. You also need to pass in the QAudioFormat in + which you wish to record. + + Starting up the QAudioInput is simply a matter of calling start() + with a QIODevice opened for writing. For instance, to record to a + file, you can: + + \snippet doc/src/snippets/multimedia-snippets/audio.cpp Audio input class members + + \snippet doc/src/snippets/multimedia-snippets/audio.cpp Audio input setup + + This will start recording if the format specified is supported by + the input device (you can check this with + QAudioDeviceInfo::isFormatSupported(). In case there are any + snags, use the error() function to check what went wrong. We stop + recording in the \c stopRecording() slot. + + \snippet doc/src/snippets/multimedia-snippets/audio.cpp Audio input stop recording + + At any point in time, QAudioInput will be in one of four states: + active, suspended, stopped, or idle. These states are specified by + the QAudio::State enum. You can request a state change directly through + suspend(), resume(), stop(), reset(), and start(). The current + state is reported by state(). QAudioOutput will also signal you + when the state changes (stateChanged()). + + QAudioInput provides several ways of measuring the time that has + passed since the start() of the recording. The \c processedUSecs() + function returns the length of the stream in microseconds written, + i.e., it leaves out the times the audio input was suspended or idle. + The elapsedUSecs() function returns the time elapsed since start() was called regardless of + which states the QAudioInput has been in. + + If an error should occur, you can fetch its reason with error(). + The possible error reasons are described by the QAudio::Error + enum. The QAudioInput will enter the \l{QAudio::}{StoppedState} when + an error is encountered. Connect to the stateChanged() signal to + handle the error: + + \snippet doc/src/snippets/multimedia-snippets/audio.cpp Audio input state changed + + \sa QAudioOutput, QAudioDeviceInfo +*/ + +/*! + Construct a new audio input and attach it to \a parent. + The default audio input device is used with the output + \a format parameters. + \since 1.0 +*/ + +QAudioInput::QAudioInput(const QAudioFormat &format, QObject *parent): + QObject(parent) +{ + d = QAudioDeviceFactory::createDefaultInputDevice(format); + connect(d, SIGNAL(notify()), SIGNAL(notify())); + connect(d, SIGNAL(stateChanged(QAudio::State)), SIGNAL(stateChanged(QAudio::State))); +} + +/*! + Construct a new audio input and attach it to \a parent. + The device referenced by \a audioDevice is used with the input + \a format parameters. + \since 1.0 +*/ + +QAudioInput::QAudioInput(const QAudioDeviceInfo &audioDevice, const QAudioFormat &format, QObject *parent): + QObject(parent) +{ + d = QAudioDeviceFactory::createInputDevice(audioDevice, format); + connect(d, SIGNAL(notify()), SIGNAL(notify())); + connect(d, SIGNAL(stateChanged(QAudio::State)), SIGNAL(stateChanged(QAudio::State))); +} + +/*! + Destroy this audio input. +*/ + +QAudioInput::~QAudioInput() +{ + delete d; +} + +/*! + Uses the \a device as the QIODevice to transfer data. + Passing a QIODevice allows the data to be transferred without any extra code. + All that is required is to open the QIODevice. + + If able to successfully get audio data from the systems audio device the + state() is set to either QAudio::ActiveState or QAudio::IdleState, + error() is set to QAudio::NoError and the stateChanged() signal is emitted. + + If a problem occurs during this process the error() is set to QAudio::OpenError, + state() is set to QAudio::StoppedState and stateChanged() signal is emitted. + + \since 1.0 + \sa QIODevice +*/ + +void QAudioInput::start(QIODevice* device) +{ + d->start(device); +} + +/*! + Returns a pointer to the QIODevice being used to handle the data + transfer. This QIODevice can be used to read() audio data + directly. + + If able to access the systems audio device the state() is set to + QAudio::IdleState, error() is set to QAudio::NoError + and the stateChanged() signal is emitted. + + If a problem occurs during this process the error() is set to QAudio::OpenError, + state() is set to QAudio::StoppedState and stateChanged() signal is emitted. + + \since 1.0 + \sa QIODevice +*/ + +QIODevice* QAudioInput::start() +{ + return d->start(); +} + +/*! + Returns the QAudioFormat being used. + \since 1.0 +*/ + +QAudioFormat QAudioInput::format() const +{ + return d->format(); +} + +/*! + Stops the audio input, detaching from the system resource. + + Sets error() to QAudio::NoError, state() to QAudio::StoppedState and + emit stateChanged() signal. + \since 1.0 +*/ + +void QAudioInput::stop() +{ + d->stop(); +} + +/*! + Drops all audio data in the buffers, resets buffers to zero. + \since 1.0 +*/ + +void QAudioInput::reset() +{ + d->reset(); +} + +/*! + Stops processing audio data, preserving buffered audio data. + + Sets error() to QAudio::NoError, state() to QAudio::SuspendedState and + emit stateChanged() signal. + \since 1.0 +*/ + +void QAudioInput::suspend() +{ + d->suspend(); +} + +/*! + Resumes processing audio data after a suspend(). + + Sets error() to QAudio::NoError. + Sets state() to QAudio::ActiveState if you previously called start(QIODevice*). + Sets state() to QAudio::IdleState if you previously called start(). + emits stateChanged() signal. + \since 1.0 +*/ + +void QAudioInput::resume() +{ + d->resume(); +} + +/*! + Sets the audio buffer size to \a value milliseconds. + + Note: This function can be called anytime before start(), calls to this + are ignored after start(). It should not be assumed that the buffer size + set is the actual buffer size used, calling bufferSize() anytime after start() + will return the actual buffer size being used. + + \since 1.0 +*/ + +void QAudioInput::setBufferSize(int value) +{ + d->setBufferSize(value); +} + +/*! + Returns the audio buffer size in milliseconds. + + If called before start(), returns platform default value. + If called before start() but setBufferSize() was called prior, returns value set by setBufferSize(). + If called after start(), returns the actual buffer size being used. This may not be what was set previously + by setBufferSize(). + + \since 1.0 +*/ + +int QAudioInput::bufferSize() const +{ + return d->bufferSize(); +} + +/*! + Returns the amount of audio data available to read in bytes. + + NOTE: returned value is only valid while in QAudio::ActiveState or QAudio::IdleState + state, otherwise returns zero. + \since 1.0 +*/ + +int QAudioInput::bytesReady() const +{ + /* + -If not ActiveState|IdleState, return 0 + -return amount of audio data available to read + */ + return d->bytesReady(); +} + +/*! + Returns the period size in bytes. + + Note: This is the recommended read size in bytes. + \since 1.0 +*/ + +int QAudioInput::periodSize() const +{ + return d->periodSize(); +} + +/*! + Sets the interval for notify() signal to be emitted. + This is based on the \a ms of audio data processed + not on actual real-time. + The minimum resolution of the timer is platform specific and values + should be checked with notifyInterval() to confirm actual value + being used. + \since 1.0 +*/ + +void QAudioInput::setNotifyInterval(int ms) +{ + d->setNotifyInterval(ms); +} + +/*! + Returns the notify interval in milliseconds. + \since 1.0 +*/ + +int QAudioInput::notifyInterval() const +{ + return d->notifyInterval(); +} + +/*! + Returns the amount of audio data processed since start() + was called in microseconds. + \since 1.0 +*/ + +qint64 QAudioInput::processedUSecs() const +{ + return d->processedUSecs(); +} + +/*! + Returns the microseconds since start() was called, including time in Idle and + Suspend states. + \since 1.0 +*/ + +qint64 QAudioInput::elapsedUSecs() const +{ + return d->elapsedUSecs(); +} + +/*! + Returns the error state. + \since 1.0 +*/ + +QAudio::Error QAudioInput::error() const +{ + return d->error(); +} + +/*! + Returns the state of audio processing. + \since 1.0 +*/ + +QAudio::State QAudioInput::state() const +{ + return d->state(); +} + +/*! + \fn QAudioInput::stateChanged(QAudio::State state) + This signal is emitted when the device \a state has changed. + \since 1.0 +*/ + +/*! + \fn QAudioInput::notify() + This signal is emitted when x ms of audio data has been processed + the interval set by setNotifyInterval(x). + \since 1.0 +*/ + +QT_END_NAMESPACE + +#include "moc_qaudioinput.cpp" + diff --git a/src/multimedia/audio/qaudioinput.h b/src/multimedia/audio/qaudioinput.h new file mode 100644 index 000000000..9c893ce95 --- /dev/null +++ b/src/multimedia/audio/qaudioinput.h @@ -0,0 +1,114 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#ifndef QAUDIOINPUT_H +#define QAUDIOINPUT_H + +#include <QtCore/qiodevice.h> + +#include <qtmultimediadefs.h> +#include <qtmedianamespace.h> + +#include <qaudio.h> +#include <qaudioformat.h> +#include <qaudiodeviceinfo.h> + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + + +class QAbstractAudioInput; + +class Q_MULTIMEDIA_EXPORT QAudioInput : public QObject +{ + Q_OBJECT + +public: + explicit QAudioInput(const QAudioFormat &format = QAudioFormat(), QObject *parent = 0); + explicit QAudioInput(const QAudioDeviceInfo &audioDeviceInfo, const QAudioFormat &format = QAudioFormat(), QObject *parent = 0); + ~QAudioInput(); + + QAudioFormat format() const; + + void start(QIODevice *device); + QIODevice* start(); + + void stop(); + void reset(); + void suspend(); + void resume(); + + void setBufferSize(int bytes); + int bufferSize() const; + + int bytesReady() const; + int periodSize() const; + + void setNotifyInterval(int milliSeconds); + int notifyInterval() const; + + qint64 processedUSecs() const; + qint64 elapsedUSecs() const; + + QAudio::Error error() const; + QAudio::State state() const; + +Q_SIGNALS: + void stateChanged(QAudio::State); + void notify(); + +private: + Q_DISABLE_COPY(QAudioInput) + + QAbstractAudioInput* d; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QAUDIOINPUT_H diff --git a/src/multimedia/audio/qaudioinput_alsa_p.cpp b/src/multimedia/audio/qaudioinput_alsa_p.cpp new file mode 100644 index 000000000..044458cd0 --- /dev/null +++ b/src/multimedia/audio/qaudioinput_alsa_p.cpp @@ -0,0 +1,867 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// INTERNAL USE ONLY: Do NOT use for any other purpose. +// + +#include <QtCore/qcoreapplication.h> +#include "qaudioinput_alsa_p.h" +#include "qaudiodeviceinfo_alsa_p.h" + +QT_BEGIN_NAMESPACE + +//#define DEBUG_AUDIO 1 + +QAudioInputPrivate::QAudioInputPrivate(const QByteArray &device) +{ + bytesAvailable = 0; + handle = 0; + ahandler = 0; + access = SND_PCM_ACCESS_RW_INTERLEAVED; + pcmformat = SND_PCM_FORMAT_S16; + buffer_size = 0; + period_size = 0; + buffer_time = 100000; + period_time = 20000; + totalTimeValue = 0; + intervalTime = 1000; + errorState = QAudio::NoError; + deviceState = QAudio::StoppedState; + audioSource = 0; + pullMode = true; + resuming = false; + + m_device = device; + + timer = new QTimer(this); + connect(timer,SIGNAL(timeout()),SLOT(userFeed())); +} + +QAudioInputPrivate::~QAudioInputPrivate() +{ + close(); + disconnect(timer, SIGNAL(timeout())); + QCoreApplication::processEvents(); + delete timer; +} + +QAudio::Error QAudioInputPrivate::error() const +{ + return errorState; +} + +QAudio::State QAudioInputPrivate::state() const +{ + return deviceState; +} + +void QAudioInputPrivate::setFormat(const QAudioFormat& fmt) +{ + if (deviceState == QAudio::StoppedState) + settings = fmt; +} + +QAudioFormat QAudioInputPrivate::format() const +{ + return settings; +} + +int QAudioInputPrivate::xrun_recovery(int err) +{ + int count = 0; + bool reset = false; + + if(err == -EPIPE) { + errorState = QAudio::UnderrunError; + err = snd_pcm_prepare(handle); + if(err < 0) + reset = true; + else { + bytesAvailable = checkBytesReady(); + if (bytesAvailable <= 0) + reset = true; + } + + } else if((err == -ESTRPIPE)||(err == -EIO)) { + errorState = QAudio::IOError; + while((err = snd_pcm_resume(handle)) == -EAGAIN){ + usleep(100); + count++; + if(count > 5) { + reset = true; + break; + } + } + if(err < 0) { + err = snd_pcm_prepare(handle); + if(err < 0) + reset = true; + } + } + if(reset) { + close(); + open(); + snd_pcm_prepare(handle); + return 0; + } + return err; +} + +int QAudioInputPrivate::setFormat() +{ + snd_pcm_format_t format = SND_PCM_FORMAT_UNKNOWN; + + if(settings.sampleSize() == 8) { + format = SND_PCM_FORMAT_U8; + } else if(settings.sampleSize() == 16) { + if(settings.sampleType() == QAudioFormat::SignedInt) { + if(settings.byteOrder() == QAudioFormat::LittleEndian) + format = SND_PCM_FORMAT_S16_LE; + else + format = SND_PCM_FORMAT_S16_BE; + } else if(settings.sampleType() == QAudioFormat::UnSignedInt) { + if(settings.byteOrder() == QAudioFormat::LittleEndian) + format = SND_PCM_FORMAT_U16_LE; + else + format = SND_PCM_FORMAT_U16_BE; + } + } else if(settings.sampleSize() == 24) { + if(settings.sampleType() == QAudioFormat::SignedInt) { + if(settings.byteOrder() == QAudioFormat::LittleEndian) + format = SND_PCM_FORMAT_S24_LE; + else + format = SND_PCM_FORMAT_S24_BE; + } else if(settings.sampleType() == QAudioFormat::UnSignedInt) { + if(settings.byteOrder() == QAudioFormat::LittleEndian) + format = SND_PCM_FORMAT_U24_LE; + else + format = SND_PCM_FORMAT_U24_BE; + } + } else if(settings.sampleSize() == 32) { + if(settings.sampleType() == QAudioFormat::SignedInt) { + if(settings.byteOrder() == QAudioFormat::LittleEndian) + format = SND_PCM_FORMAT_S32_LE; + else + format = SND_PCM_FORMAT_S32_BE; + } else if(settings.sampleType() == QAudioFormat::UnSignedInt) { + if(settings.byteOrder() == QAudioFormat::LittleEndian) + format = SND_PCM_FORMAT_U32_LE; + else + format = SND_PCM_FORMAT_U32_BE; + } else if(settings.sampleType() == QAudioFormat::Float) { + if(settings.byteOrder() == QAudioFormat::LittleEndian) + format = SND_PCM_FORMAT_FLOAT_LE; + else + format = SND_PCM_FORMAT_FLOAT_BE; + } + } else if(settings.sampleSize() == 64) { + if(settings.byteOrder() == QAudioFormat::LittleEndian) + format = SND_PCM_FORMAT_FLOAT64_LE; + else + format = SND_PCM_FORMAT_FLOAT64_BE; + } + + return format != SND_PCM_FORMAT_UNKNOWN + ? snd_pcm_hw_params_set_format( handle, hwparams, format) + : -1; +} + +void QAudioInputPrivate::start(QIODevice* device) +{ + if(deviceState != QAudio::StoppedState) + close(); + + if(!pullMode && audioSource) + delete audioSource; + + pullMode = true; + audioSource = device; + + deviceState = QAudio::ActiveState; + + if( !open() ) + return; + + emit stateChanged(deviceState); +} + +QIODevice* QAudioInputPrivate::start() +{ + if(deviceState != QAudio::StoppedState) + close(); + + if(!pullMode && audioSource) + delete audioSource; + + pullMode = false; + audioSource = new InputPrivate(this); + audioSource->open(QIODevice::ReadOnly | QIODevice::Unbuffered); + + deviceState = QAudio::IdleState; + + if( !open() ) + return 0; + + emit stateChanged(deviceState); + + return audioSource; +} + +void QAudioInputPrivate::stop() +{ + if(deviceState == QAudio::StoppedState) + return; + + deviceState = QAudio::StoppedState; + + close(); + emit stateChanged(deviceState); +} + +bool QAudioInputPrivate::open() +{ +#ifdef DEBUG_AUDIO + QTime now(QTime::currentTime()); + qDebug()<<now.second()<<"s "<<now.msec()<<"ms :open()"; +#endif + clockStamp.restart(); + timeStamp.restart(); + elapsedTimeOffset = 0; + + int dir; + int err = 0; + int count=0; + unsigned int freakuency=settings.frequency(); + + if (!settings.isValid()) { + qWarning("QAudioOutput: open error, invalid format."); + } else if (settings.sampleRate() <= 0) { + qWarning("QAudioOutput: open error, invalid sample rate (%d).", + settings.sampleRate()); + } else { + err = -1; + } + + if (err == 0) { + errorState = QAudio::OpenError; + deviceState = QAudio::StoppedState; + emit errorChanged(errorState); + return false; + } + + + QString dev = QString(QLatin1String(m_device.constData())); + QList<QByteArray> devices = QAudioDeviceInfoInternal::availableDevices(QAudio::AudioInput); + if(dev.compare(QLatin1String("default")) == 0) { +#if(SND_LIB_MAJOR == 1 && SND_LIB_MINOR == 0 && SND_LIB_SUBMINOR >= 14) + if (devices.size() > 0) + dev = QLatin1String(devices.first()); + else + return false; +#else + dev = QLatin1String("hw:0,0"); +#endif + } else { +#if(SND_LIB_MAJOR == 1 && SND_LIB_MINOR == 0 && SND_LIB_SUBMINOR >= 14) + dev = QLatin1String(m_device); +#else + int idx = 0; + char *name; + + QString shortName = QLatin1String(m_device.mid(m_device.indexOf('=',0)+1).constData()); + + while(snd_card_get_name(idx,&name) == 0) { + if(qstrncmp(shortName.toLocal8Bit().constData(),name,shortName.length()) == 0) + break; + idx++; + } + dev = QString(QLatin1String("hw:%1,0")).arg(idx); +#endif + } + + // Step 1: try and open the device + while((count < 5) && (err < 0)) { + err=snd_pcm_open(&handle,dev.toLocal8Bit().constData(),SND_PCM_STREAM_CAPTURE,0); + if(err < 0) + count++; + } + if (( err < 0)||(handle == 0)) { + errorState = QAudio::OpenError; + deviceState = QAudio::StoppedState; + emit stateChanged(deviceState); + return false; + } + snd_pcm_nonblock( handle, 0 ); + + // Step 2: Set the desired HW parameters. + snd_pcm_hw_params_alloca( &hwparams ); + + bool fatal = false; + QString errMessage; + unsigned int chunks = 8; + + err = snd_pcm_hw_params_any( handle, hwparams ); + if ( err < 0 ) { + fatal = true; + errMessage = QString::fromLatin1("QAudioInput: snd_pcm_hw_params_any: err = %1").arg(err); + } + if ( !fatal ) { + err = snd_pcm_hw_params_set_rate_resample( handle, hwparams, 1 ); + if ( err < 0 ) { + fatal = true; + errMessage = QString::fromLatin1("QAudioInput: snd_pcm_hw_params_set_rate_resample: err = %1").arg(err); + } + } + if ( !fatal ) { + err = snd_pcm_hw_params_set_access( handle, hwparams, access ); + if ( err < 0 ) { + fatal = true; + errMessage = QString::fromLatin1("QAudioInput: snd_pcm_hw_params_set_access: err = %1").arg(err); + } + } + if ( !fatal ) { + err = setFormat(); + if ( err < 0 ) { + fatal = true; + errMessage = QString::fromLatin1("QAudioInput: snd_pcm_hw_params_set_format: err = %1").arg(err); + } + } + if ( !fatal ) { + err = snd_pcm_hw_params_set_channels( handle, hwparams, (unsigned int)settings.channels() ); + if ( err < 0 ) { + fatal = true; + errMessage = QString::fromLatin1("QAudioInput: snd_pcm_hw_params_set_channels: err = %1").arg(err); + } + } + if ( !fatal ) { + err = snd_pcm_hw_params_set_rate_near( handle, hwparams, &freakuency, 0 ); + if ( err < 0 ) { + fatal = true; + errMessage = QString::fromLatin1("QAudioInput: snd_pcm_hw_params_set_rate_near: err = %1").arg(err); + } + } + if ( !fatal ) { + err = snd_pcm_hw_params_set_buffer_time_near(handle, hwparams, &buffer_time, &dir); + if ( err < 0 ) { + fatal = true; + errMessage = QString::fromLatin1("QAudioInput: snd_pcm_hw_params_set_buffer_time_near: err = %1").arg(err); + } + } + if ( !fatal ) { + err = snd_pcm_hw_params_set_period_time_near(handle, hwparams, &period_time, &dir); + if ( err < 0 ) { + fatal = true; + errMessage = QString::fromLatin1("QAudioInput: snd_pcm_hw_params_set_period_time_near: err = %1").arg(err); + } + } + if ( !fatal ) { + err = snd_pcm_hw_params_set_periods_near(handle, hwparams, &chunks, &dir); + if ( err < 0 ) { + fatal = true; + errMessage = QString::fromLatin1("QAudioInput: snd_pcm_hw_params_set_periods_near: err = %1").arg(err); + } + } + if ( !fatal ) { + err = snd_pcm_hw_params(handle, hwparams); + if ( err < 0 ) { + fatal = true; + errMessage = QString::fromLatin1("QAudioInput: snd_pcm_hw_params: err = %1").arg(err); + } + } + if( err < 0) { + qWarning()<<errMessage; + errorState = QAudio::OpenError; + deviceState = QAudio::StoppedState; + emit stateChanged(deviceState); + return false; + } + snd_pcm_hw_params_get_buffer_size(hwparams,&buffer_frames); + buffer_size = snd_pcm_frames_to_bytes(handle,buffer_frames); + snd_pcm_hw_params_get_period_size(hwparams,&period_frames, &dir); + period_size = snd_pcm_frames_to_bytes(handle,period_frames); + snd_pcm_hw_params_get_buffer_time(hwparams,&buffer_time, &dir); + snd_pcm_hw_params_get_period_time(hwparams,&period_time, &dir); + + // Step 3: Set the desired SW parameters. + snd_pcm_sw_params_t *swparams; + snd_pcm_sw_params_alloca(&swparams); + snd_pcm_sw_params_current(handle, swparams); + snd_pcm_sw_params_set_start_threshold(handle,swparams,period_frames); + snd_pcm_sw_params_set_stop_threshold(handle,swparams,buffer_frames); + snd_pcm_sw_params_set_avail_min(handle, swparams,period_frames); + snd_pcm_sw_params(handle, swparams); + + // Step 4: Prepare audio + ringBuffer.resize(buffer_size); + snd_pcm_prepare( handle ); + snd_pcm_start(handle); + + // Step 5: Setup timer + bytesAvailable = checkBytesReady(); + + if(pullMode) + connect(audioSource,SIGNAL(readyRead()),this,SLOT(userFeed())); + + // Step 6: Start audio processing + chunks = buffer_size/period_size; + timer->start(period_time*chunks/2000); + + errorState = QAudio::NoError; + + totalTimeValue = 0; + + return true; +} + +void QAudioInputPrivate::close() +{ + timer->stop(); + + if ( handle ) { + snd_pcm_drop( handle ); + snd_pcm_close( handle ); + handle = 0; + } +} + +int QAudioInputPrivate::checkBytesReady() +{ + if(resuming) + bytesAvailable = period_size; + else if(deviceState != QAudio::ActiveState + && deviceState != QAudio::IdleState) + bytesAvailable = 0; + else { + int frames = snd_pcm_avail_update(handle); + if (frames < 0) { + bytesAvailable = frames; + } else { + if((int)frames > (int)buffer_frames) + frames = buffer_frames; + bytesAvailable = snd_pcm_frames_to_bytes(handle, frames); + } + } + return bytesAvailable; +} + +int QAudioInputPrivate::bytesReady() const +{ + return qMax(bytesAvailable, 0); +} + +qint64 QAudioInputPrivate::read(char* data, qint64 len) +{ + // Read in some audio data and write it to QIODevice, pull mode + if ( !handle ) + return 0; + + int bytesRead = 0; + int bytesInRingbufferBeforeRead = ringBuffer.bytesOfDataInBuffer(); + + if (ringBuffer.bytesOfDataInBuffer() < len) { + + // bytesAvaiable is saved as a side effect of checkBytesReady(). + int bytesToRead = checkBytesReady(); + + if (bytesToRead < 0) { + // bytesAvailable as negative is error code, try to recover from it. + xrun_recovery(bytesToRead); + bytesToRead = checkBytesReady(); + if (bytesToRead < 0) { + // recovery failed must stop and set error. + close(); + errorState = QAudio::IOError; + deviceState = QAudio::StoppedState; + emit stateChanged(deviceState); + return 0; + } + } + + bytesToRead = qMin<qint64>(len, bytesToRead); + bytesToRead = qMin<qint64>(ringBuffer.freeBytes(), bytesToRead); + bytesToRead -= bytesToRead % period_size; + + int count=0; + int err = 0; + while(count < 5 && bytesToRead > 0) { + char buffer[bytesToRead]; + int chunks = bytesToRead / period_size; + int frames = chunks * period_frames; + if (frames > (int)buffer_frames) + frames = buffer_frames; + + int readFrames = snd_pcm_readi(handle, buffer, frames); + + if (readFrames >= 0) { + bytesRead = snd_pcm_frames_to_bytes(handle, readFrames); + ringBuffer.write(buffer, bytesRead); +#ifdef DEBUG_AUDIO + qDebug() << QString::fromLatin1("read in bytes = %1 (frames=%2)").arg(bytesRead).arg(readFrames).toLatin1().constData(); +#endif + break; + } else if((readFrames == -EAGAIN) || (readFrames == -EINTR)) { + errorState = QAudio::IOError; + err = 0; + break; + } else { + if(readFrames == -EPIPE) { + errorState = QAudio::UnderrunError; + err = snd_pcm_prepare(handle); + } else if(readFrames == -ESTRPIPE) { + err = snd_pcm_prepare(handle); + } + if(err != 0) break; + } + count++; + } + + } + + bytesRead += bytesInRingbufferBeforeRead; + + if (bytesRead > 0) { + // got some send it onward +#ifdef DEBUG_AUDIO + qDebug() << "frames to write to QIODevice = " << + snd_pcm_bytes_to_frames( handle, (int)bytesRead ) << " (" << bytesRead << ") bytes"; +#endif + if (deviceState != QAudio::ActiveState && deviceState != QAudio::IdleState) + return 0; + + if (pullMode) { + qint64 l = 0; + qint64 bytesWritten = 0; + while (ringBuffer.bytesOfDataInBuffer() > 0) { + l = audioSource->write(ringBuffer.availableData(), ringBuffer.availableDataBlockSize()); + if (l > 0) { + ringBuffer.readBytes(l); + bytesWritten += l; + } else { + break; + } + } + + if (l < 0) { + close(); + errorState = QAudio::IOError; + deviceState = QAudio::StoppedState; + emit stateChanged(deviceState); + } else if (l == 0 && bytesWritten == 0) { + if (deviceState != QAudio::IdleState) { + errorState = QAudio::NoError; + deviceState = QAudio::IdleState; + emit stateChanged(deviceState); + } + } else { + bytesAvailable -= bytesWritten; + totalTimeValue += bytesWritten; + resuming = false; + if (deviceState != QAudio::ActiveState) { + errorState = QAudio::NoError; + deviceState = QAudio::ActiveState; + emit stateChanged(deviceState); + } + } + + return bytesWritten; + } else { + while (ringBuffer.bytesOfDataInBuffer() > 0) { + int size = ringBuffer.availableDataBlockSize(); + memcpy(data, ringBuffer.availableData(), size); + data += size; + ringBuffer.readBytes(size); + } + + bytesAvailable -= bytesRead; + totalTimeValue += bytesRead; + resuming = false; + if (deviceState != QAudio::ActiveState) { + errorState = QAudio::NoError; + deviceState = QAudio::ActiveState; + emit stateChanged(deviceState); + } + + return bytesRead; + } + } + + return 0; +} + +void QAudioInputPrivate::resume() +{ + if(deviceState == QAudio::SuspendedState) { + int err = 0; + + if(handle) { + err = snd_pcm_prepare( handle ); + if(err < 0) + xrun_recovery(err); + + err = snd_pcm_start(handle); + if(err < 0) + xrun_recovery(err); + + bytesAvailable = buffer_size; + } + resuming = true; + deviceState = QAudio::ActiveState; + int chunks = buffer_size/period_size; + timer->start(period_time*chunks/2000); + emit stateChanged(deviceState); + } +} + +void QAudioInputPrivate::setBufferSize(int value) +{ + buffer_size = value; +} + +int QAudioInputPrivate::bufferSize() const +{ + return buffer_size; +} + +int QAudioInputPrivate::periodSize() const +{ + return period_size; +} + +void QAudioInputPrivate::setNotifyInterval(int ms) +{ + intervalTime = qMax(0, ms); +} + +int QAudioInputPrivate::notifyInterval() const +{ + return intervalTime; +} + +qint64 QAudioInputPrivate::processedUSecs() const +{ + qint64 result = qint64(1000000) * totalTimeValue / + (settings.channels()*(settings.sampleSize()/8)) / + settings.frequency(); + + return result; +} + +void QAudioInputPrivate::suspend() +{ + if(deviceState == QAudio::ActiveState||resuming) { + timer->stop(); + deviceState = QAudio::SuspendedState; + emit stateChanged(deviceState); + } +} + +void QAudioInputPrivate::userFeed() +{ + if(deviceState == QAudio::StoppedState || deviceState == QAudio::SuspendedState) + return; +#ifdef DEBUG_AUDIO + QTime now(QTime::currentTime()); + qDebug()<<now.second()<<"s "<<now.msec()<<"ms :userFeed() IN"; +#endif + deviceReady(); +} + +bool QAudioInputPrivate::deviceReady() +{ + if(pullMode) { + // reads some audio data and writes it to QIODevice + read(0, buffer_size); + } else { + // emits readyRead() so user will call read() on QIODevice to get some audio data + InputPrivate* a = qobject_cast<InputPrivate*>(audioSource); + a->trigger(); + } + bytesAvailable = checkBytesReady(); + + if(deviceState != QAudio::ActiveState) + return true; + + if (bytesAvailable < 0) { + // bytesAvailable as negative is error code, try to recover from it. + xrun_recovery(bytesAvailable); + bytesAvailable = checkBytesReady(); + if (bytesAvailable < 0) { + // recovery failed must stop and set error. + close(); + errorState = QAudio::IOError; + deviceState = QAudio::StoppedState; + emit stateChanged(deviceState); + return 0; + } + } + + if(intervalTime && (timeStamp.elapsed() + elapsedTimeOffset) > intervalTime) { + emit notify(); + elapsedTimeOffset = timeStamp.elapsed() + elapsedTimeOffset - intervalTime; + timeStamp.restart(); + } + return true; +} + +qint64 QAudioInputPrivate::elapsedUSecs() const +{ + if (deviceState == QAudio::StoppedState) + return 0; + + return clockStamp.elapsed()*1000; +} + +void QAudioInputPrivate::reset() +{ + if(handle) + snd_pcm_reset(handle); + stop(); + bytesAvailable = 0; +} + +void QAudioInputPrivate::drain() +{ + if(handle) + snd_pcm_drain(handle); +} + +InputPrivate::InputPrivate(QAudioInputPrivate* audio) +{ + audioDevice = qobject_cast<QAudioInputPrivate*>(audio); +} + +InputPrivate::~InputPrivate() +{ +} + +qint64 InputPrivate::readData( char* data, qint64 len) +{ + return audioDevice->read(data,len); +} + +qint64 InputPrivate::writeData(const char* data, qint64 len) +{ + Q_UNUSED(data) + Q_UNUSED(len) + return 0; +} + +void InputPrivate::trigger() +{ + emit readyRead(); +} + +RingBuffer::RingBuffer() : + m_head(0), + m_tail(0) +{ +} + +void RingBuffer::resize(int size) +{ + m_data.resize(size); +} + +int RingBuffer::bytesOfDataInBuffer() const +{ + if (m_head < m_tail) + return m_tail - m_head; + else if (m_tail < m_head) + return m_data.size() + m_tail - m_head; + else + return 0; +} + +int RingBuffer::freeBytes() const +{ + if (m_head > m_tail) + return m_head - m_tail - 1; + else if (m_tail > m_head) + return m_data.size() - m_tail + m_head - 1; + else + return m_data.size() - 1; +} + +const char *RingBuffer::availableData() const +{ + return (m_data.constData() + m_head); +} + +int RingBuffer::availableDataBlockSize() const +{ + if (m_head > m_tail) + return m_data.size() - m_head; + else if (m_tail > m_head) + return m_tail - m_head; + else + return 0; +} + +void RingBuffer::readBytes(int bytes) +{ + m_head = (m_head + bytes) % m_data.size(); +} + +void RingBuffer::write(char *data, int len) +{ + if (m_tail + len < m_data.size()) { + memcpy(m_data.data() + m_tail, data, len); + m_tail += len; + } else { + int bytesUntilEnd = m_data.size() - m_tail; + memcpy(m_data.data() + m_tail, data, bytesUntilEnd); + if (len - bytesUntilEnd > 0) + memcpy(m_data.data(), data + bytesUntilEnd, len - bytesUntilEnd); + m_tail = len - bytesUntilEnd; + } +} + +QT_END_NAMESPACE + +#include "moc_qaudioinput_alsa_p.cpp" diff --git a/src/multimedia/audio/qaudioinput_alsa_p.h b/src/multimedia/audio/qaudioinput_alsa_p.h new file mode 100644 index 000000000..a05f6954d --- /dev/null +++ b/src/multimedia/audio/qaudioinput_alsa_p.h @@ -0,0 +1,191 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + + +#ifndef QAUDIOINPUTALSA_H +#define QAUDIOINPUTALSA_H + +#include <alsa/asoundlib.h> + +#include <QtCore/qfile.h> +#include <QtCore/qdebug.h> +#include <QtCore/qtimer.h> +#include <QtCore/qstring.h> +#include <QtCore/qstringlist.h> +#include <QtCore/qdatetime.h> + +#include "qaudio.h" +#include "qaudiodeviceinfo.h" +#include "qaudiosystem.h" + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + +class InputPrivate; + +class RingBuffer +{ +public: + RingBuffer(); + + void resize(int size); + + int bytesOfDataInBuffer() const; + int freeBytes() const; + + const char *availableData() const; + int availableDataBlockSize() const; + void readBytes(int bytes); + + void write(char *data, int len); + +private: + int m_head; + int m_tail; + + QByteArray m_data; +}; + +class QAudioInputPrivate : public QAbstractAudioInput +{ + Q_OBJECT +public: + QAudioInputPrivate(const QByteArray &device); + ~QAudioInputPrivate(); + + qint64 read(char* data, qint64 len); + + void start(QIODevice* device); + QIODevice* start(); + void stop(); + void reset(); + void suspend(); + void resume(); + int bytesReady() const; + int periodSize() const; + void setBufferSize(int value); + int bufferSize() const; + void setNotifyInterval(int milliSeconds); + int notifyInterval() const; + qint64 processedUSecs() const; + qint64 elapsedUSecs() const; + QAudio::Error error() const; + QAudio::State state() const; + void setFormat(const QAudioFormat& fmt); + QAudioFormat format() const; + bool resuming; + snd_pcm_t* handle; + qint64 totalTimeValue; + QIODevice* audioSource; + QAudioFormat settings; + QAudio::Error errorState; + QAudio::State deviceState; + +private slots: + void userFeed(); + bool deviceReady(); + +private: + int checkBytesReady(); + int xrun_recovery(int err); + int setFormat(); + bool open(); + void close(); + void drain(); + + QTimer* timer; + QTime timeStamp; + QTime clockStamp; + qint64 elapsedTimeOffset; + int intervalTime; + RingBuffer ringBuffer; + int bytesAvailable; + QByteArray m_device; + bool pullMode; + int buffer_size; + int period_size; + unsigned int buffer_time; + unsigned int period_time; + snd_pcm_uframes_t buffer_frames; + snd_pcm_uframes_t period_frames; + snd_async_handler_t* ahandler; + snd_pcm_access_t access; + snd_pcm_format_t pcmformat; + snd_timestamp_t* timestamp; + snd_pcm_hw_params_t *hwparams; +}; + +class InputPrivate : public QIODevice +{ + Q_OBJECT +public: + InputPrivate(QAudioInputPrivate* audio); + ~InputPrivate(); + + qint64 readData( char* data, qint64 len); + qint64 writeData(const char* data, qint64 len); + + void trigger(); +private: + QAudioInputPrivate *audioDevice; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + + +#endif diff --git a/src/multimedia/audio/qaudioinput_mac_p.cpp b/src/multimedia/audio/qaudioinput_mac_p.cpp new file mode 100644 index 000000000..184935add --- /dev/null +++ b/src/multimedia/audio/qaudioinput_mac_p.cpp @@ -0,0 +1,989 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// INTERNAL USE ONLY: Do NOT use for any other purpose. +// + +#include <QtCore/qendian.h> +#include <QtCore/qtimer.h> +#include <QtCore/qdebug.h> + +#include <qaudioinput.h> + +#include "qaudio_mac_p.h" +#include "qaudioinput_mac_p.h" +#include "qaudiodeviceinfo_mac_p.h" + +QT_BEGIN_NAMESPACE + + +namespace QtMultimediaInternal +{ + +static const int default_buffer_size = 4 * 1024; + +class QAudioBufferList +{ +public: + QAudioBufferList(AudioStreamBasicDescription const& streamFormat): + owner(false), + sf(streamFormat) + { + const bool isInterleaved = (sf.mFormatFlags & kAudioFormatFlagIsNonInterleaved) == 0; + const int numberOfBuffers = isInterleaved ? 1 : sf.mChannelsPerFrame; + + dataSize = 0; + + bfs = reinterpret_cast<AudioBufferList*>(qMalloc(sizeof(AudioBufferList) + + (sizeof(AudioBuffer) * numberOfBuffers))); + + bfs->mNumberBuffers = numberOfBuffers; + for (int i = 0; i < numberOfBuffers; ++i) { + bfs->mBuffers[i].mNumberChannels = isInterleaved ? numberOfBuffers : 1; + bfs->mBuffers[i].mDataByteSize = 0; + bfs->mBuffers[i].mData = 0; + } + } + + QAudioBufferList(AudioStreamBasicDescription const& streamFormat, char* buffer, int bufferSize): + owner(false), + sf(streamFormat), + bfs(0) + { + dataSize = bufferSize; + + bfs = reinterpret_cast<AudioBufferList*>(qMalloc(sizeof(AudioBufferList) + sizeof(AudioBuffer))); + + bfs->mNumberBuffers = 1; + bfs->mBuffers[0].mNumberChannels = 1; + bfs->mBuffers[0].mDataByteSize = dataSize; + bfs->mBuffers[0].mData = buffer; + } + + QAudioBufferList(AudioStreamBasicDescription const& streamFormat, int framesToBuffer): + owner(true), + sf(streamFormat), + bfs(0) + { + const bool isInterleaved = (sf.mFormatFlags & kAudioFormatFlagIsNonInterleaved) == 0; + const int numberOfBuffers = isInterleaved ? 1 : sf.mChannelsPerFrame; + + dataSize = framesToBuffer * sf.mBytesPerFrame; + + bfs = reinterpret_cast<AudioBufferList*>(qMalloc(sizeof(AudioBufferList) + + (sizeof(AudioBuffer) * numberOfBuffers))); + bfs->mNumberBuffers = numberOfBuffers; + for (int i = 0; i < numberOfBuffers; ++i) { + bfs->mBuffers[i].mNumberChannels = isInterleaved ? numberOfBuffers : 1; + bfs->mBuffers[i].mDataByteSize = dataSize; + bfs->mBuffers[i].mData = qMalloc(dataSize); + } + } + + ~QAudioBufferList() + { + if (owner) { + for (UInt32 i = 0; i < bfs->mNumberBuffers; ++i) + qFree(bfs->mBuffers[i].mData); + } + + qFree(bfs); + } + + AudioBufferList* audioBufferList() const + { + return bfs; + } + + char* data(int buffer = 0) const + { + return static_cast<char*>(bfs->mBuffers[buffer].mData); + } + + qint64 bufferSize(int buffer = 0) const + { + return bfs->mBuffers[buffer].mDataByteSize; + } + + int frameCount(int buffer = 0) const + { + return bfs->mBuffers[buffer].mDataByteSize / sf.mBytesPerFrame; + } + + int packetCount(int buffer = 0) const + { + return bfs->mBuffers[buffer].mDataByteSize / sf.mBytesPerPacket; + } + + int packetSize() const + { + return sf.mBytesPerPacket; + } + + void reset() + { + for (UInt32 i = 0; i < bfs->mNumberBuffers; ++i) { + bfs->mBuffers[i].mDataByteSize = dataSize; + bfs->mBuffers[i].mData = 0; + } + } + +private: + bool owner; + int dataSize; + AudioStreamBasicDescription sf; + AudioBufferList* bfs; +}; + +class QAudioPacketFeeder +{ +public: + QAudioPacketFeeder(QAudioBufferList* abl): + audioBufferList(abl) + { + totalPackets = audioBufferList->packetCount(); + position = 0; + } + + bool feed(AudioBufferList& dst, UInt32& packetCount) + { + if (position == totalPackets) { + dst.mBuffers[0].mDataByteSize = 0; + packetCount = 0; + return false; + } + + if (totalPackets - position < packetCount) + packetCount = totalPackets - position; + + dst.mBuffers[0].mDataByteSize = packetCount * audioBufferList->packetSize(); + dst.mBuffers[0].mData = audioBufferList->data() + (position * audioBufferList->packetSize()); + + position += packetCount; + + return true; + } + + bool empty() const + { + return position == totalPackets; + } + +private: + UInt32 totalPackets; + UInt32 position; + QAudioBufferList* audioBufferList; +}; + +class QAudioInputBuffer : public QObject +{ + Q_OBJECT + +public: + QAudioInputBuffer(int bufferSize, + int maxPeriodSize, + AudioStreamBasicDescription const& inputFormat, + AudioStreamBasicDescription const& outputFormat, + QObject* parent): + QObject(parent), + m_deviceError(false), + m_audioConverter(0), + m_inputFormat(inputFormat), + m_outputFormat(outputFormat) + { + m_maxPeriodSize = maxPeriodSize; + m_periodTime = m_maxPeriodSize / m_outputFormat.mBytesPerFrame * 1000 / m_outputFormat.mSampleRate; + m_buffer = new QAudioRingBuffer(bufferSize + (bufferSize % maxPeriodSize == 0 ? 0 : maxPeriodSize - (bufferSize % maxPeriodSize))); + m_inputBufferList = new QAudioBufferList(m_inputFormat); + + m_flushTimer = new QTimer(this); + connect(m_flushTimer, SIGNAL(timeout()), SLOT(flushBuffer())); + + if (toQAudioFormat(inputFormat) != toQAudioFormat(outputFormat)) { + if (AudioConverterNew(&m_inputFormat, &m_outputFormat, &m_audioConverter) != noErr) { + qWarning() << "QAudioInput: Unable to create an Audio Converter"; + m_audioConverter = 0; + } + } + } + + ~QAudioInputBuffer() + { + delete m_buffer; + } + + qint64 renderFromDevice(AudioUnit audioUnit, + AudioUnitRenderActionFlags* ioActionFlags, + const AudioTimeStamp* inTimeStamp, + UInt32 inBusNumber, + UInt32 inNumberFrames) + { + const bool pullMode = m_device == 0; + + OSStatus err; + qint64 framesRendered = 0; + + m_inputBufferList->reset(); + err = AudioUnitRender(audioUnit, + ioActionFlags, + inTimeStamp, + inBusNumber, + inNumberFrames, + m_inputBufferList->audioBufferList()); + + if (m_audioConverter != 0) { + QAudioPacketFeeder feeder(m_inputBufferList); + + int copied = 0; + const int available = m_buffer->free(); + + while (err == noErr && !feeder.empty()) { + QAudioRingBuffer::Region region = m_buffer->acquireWriteRegion(available); + + if (region.second == 0) + break; + + AudioBufferList output; + output.mNumberBuffers = 1; + output.mBuffers[0].mNumberChannels = 1; + output.mBuffers[0].mDataByteSize = region.second; + output.mBuffers[0].mData = region.first; + + UInt32 packetSize = region.second / m_outputFormat.mBytesPerPacket; + err = AudioConverterFillComplexBuffer(m_audioConverter, + converterCallback, + &feeder, + &packetSize, + &output, + 0); + region.second = output.mBuffers[0].mDataByteSize; + copied += region.second; + + m_buffer->releaseWriteRegion(region); + } + + framesRendered += copied / m_outputFormat.mBytesPerFrame; + } + else { + const int available = m_inputBufferList->bufferSize(); + bool wecan = true; + int copied = 0; + + while (wecan && copied < available) { + QAudioRingBuffer::Region region = m_buffer->acquireWriteRegion(available - copied); + + if (region.second > 0) { + memcpy(region.first, m_inputBufferList->data() + copied, region.second); + copied += region.second; + } + else + wecan = false; + + m_buffer->releaseWriteRegion(region); + } + + framesRendered = copied / m_outputFormat.mBytesPerFrame; + } + + if (pullMode && framesRendered > 0) + emit readyRead(); + + return framesRendered; + } + + qint64 readBytes(char* data, qint64 len) + { + bool wecan = true; + qint64 bytesCopied = 0; + + len -= len % m_maxPeriodSize; + while (wecan && bytesCopied < len) { + QAudioRingBuffer::Region region = m_buffer->acquireReadRegion(len - bytesCopied); + + if (region.second > 0) { + memcpy(data + bytesCopied, region.first, region.second); + bytesCopied += region.second; + } + else + wecan = false; + + m_buffer->releaseReadRegion(region); + } + + return bytesCopied; + } + + void setFlushDevice(QIODevice* device) + { + if (m_device != device) + m_device = device; + } + + void startFlushTimer() + { + if (m_device != 0) { + m_flushTimer->start((m_buffer->size() - (m_maxPeriodSize * 2)) / m_maxPeriodSize * m_periodTime); + } + } + + void stopFlushTimer() + { + m_flushTimer->stop(); + } + + void flush(bool all = false) + { + if (m_device == 0) + return; + + const int used = m_buffer->used(); + const int readSize = all ? used : used - (used % m_maxPeriodSize); + + if (readSize > 0) { + bool wecan = true; + int flushed = 0; + + while (!m_deviceError && wecan && flushed < readSize) { + QAudioRingBuffer::Region region = m_buffer->acquireReadRegion(readSize - flushed); + + if (region.second > 0) { + int bytesWritten = m_device->write(region.first, region.second); + if (bytesWritten < 0) { + stopFlushTimer(); + m_deviceError = true; + } + else { + region.second = bytesWritten; + flushed += bytesWritten; + wecan = bytesWritten != 0; + } + } + else + wecan = false; + + m_buffer->releaseReadRegion(region); + } + } + } + + void reset() + { + m_buffer->reset(); + m_deviceError = false; + } + + int available() const + { + return m_buffer->free(); + } + + int used() const + { + return m_buffer->used(); + } + +signals: + void readyRead(); + +private slots: + void flushBuffer() + { + flush(); + } + +private: + bool m_deviceError; + int m_maxPeriodSize; + int m_periodTime; + QIODevice* m_device; + QTimer* m_flushTimer; + QAudioRingBuffer* m_buffer; + QAudioBufferList* m_inputBufferList; + AudioConverterRef m_audioConverter; + AudioStreamBasicDescription m_inputFormat; + AudioStreamBasicDescription m_outputFormat; + + const static OSStatus as_empty = 'qtem'; + + // Converter callback + static OSStatus converterCallback(AudioConverterRef inAudioConverter, + UInt32* ioNumberDataPackets, + AudioBufferList* ioData, + AudioStreamPacketDescription** outDataPacketDescription, + void* inUserData) + { + Q_UNUSED(inAudioConverter); + Q_UNUSED(outDataPacketDescription); + + QAudioPacketFeeder* feeder = static_cast<QAudioPacketFeeder*>(inUserData); + + if (!feeder->feed(*ioData, *ioNumberDataPackets)) + return as_empty; + + return noErr; + } +}; + + +class MacInputDevice : public QIODevice +{ + Q_OBJECT + +public: + MacInputDevice(QAudioInputBuffer* audioBuffer, QObject* parent): + QIODevice(parent), + m_audioBuffer(audioBuffer) + { + open(QIODevice::ReadOnly | QIODevice::Unbuffered); + connect(m_audioBuffer, SIGNAL(readyRead()), SIGNAL(readyRead())); + } + + qint64 readData(char* data, qint64 len) + { + return m_audioBuffer->readBytes(data, len); + } + + qint64 writeData(const char* data, qint64 len) + { + Q_UNUSED(data); + Q_UNUSED(len); + + return 0; + } + + bool isSequential() const + { + return true; + } + +private: + QAudioInputBuffer* m_audioBuffer; +}; + +} + + +QAudioInputPrivate::QAudioInputPrivate(const QByteArray& device) +{ + QDataStream ds(device); + quint32 did, mode; + + ds >> did >> mode; + + if (QAudio::Mode(mode) == QAudio::AudioOutput) + errorCode = QAudio::OpenError; + else { + audioDeviceInfo = new QAudioDeviceInfoInternal(device, QAudio::AudioInput); + isOpen = false; + audioDeviceId = AudioDeviceID(did); + audioUnit = 0; + startTime = 0; + totalFrames = 0; + audioBuffer = 0; + internalBufferSize = QtMultimediaInternal::default_buffer_size; + clockFrequency = AudioGetHostClockFrequency() / 1000; + errorCode = QAudio::NoError; + stateCode = QAudio::StoppedState; + + intervalTimer = new QTimer(this); + intervalTimer->setInterval(1000); + connect(intervalTimer, SIGNAL(timeout()), SIGNAL(notify())); + } +} + +QAudioInputPrivate::~QAudioInputPrivate() +{ + close(); + delete audioDeviceInfo; +} + +bool QAudioInputPrivate::open() +{ + UInt32 size = 0; + + if (isOpen) + return true; + + ComponentDescription cd; + cd.componentType = kAudioUnitType_Output; + cd.componentSubType = kAudioUnitSubType_HALOutput; + cd.componentManufacturer = kAudioUnitManufacturer_Apple; + cd.componentFlags = 0; + cd.componentFlagsMask = 0; + + // Open + Component cp = FindNextComponent(NULL, &cd); + if (cp == 0) { + qWarning() << "QAudioInput: Failed to find HAL Output component"; + return false; + } + + if (OpenAComponent(cp, &audioUnit) != noErr) { + qWarning() << "QAudioInput: Unable to Open Output Component"; + return false; + } + + // Set mode + // switch to input mode + UInt32 enable = 1; + if (AudioUnitSetProperty(audioUnit, + kAudioOutputUnitProperty_EnableIO, + kAudioUnitScope_Input, + 1, + &enable, + sizeof(enable)) != noErr) { + qWarning() << "QAudioInput: Unable to switch to input mode (Enable Input)"; + return false; + } + + enable = 0; + if (AudioUnitSetProperty(audioUnit, + kAudioOutputUnitProperty_EnableIO, + kAudioUnitScope_Output, + 0, + &enable, + sizeof(enable)) != noErr) { + qWarning() << "QAudioInput: Unable to switch to input mode (Disable output)"; + return false; + } + + // register callback + AURenderCallbackStruct cb; + cb.inputProc = inputCallback; + cb.inputProcRefCon = this; + + if (AudioUnitSetProperty(audioUnit, + kAudioOutputUnitProperty_SetInputCallback, + kAudioUnitScope_Global, + 0, + &cb, + sizeof(cb)) != noErr) { + qWarning() << "QAudioInput: Failed to set AudioUnit callback"; + return false; + } + + // Set Audio Device + if (AudioUnitSetProperty(audioUnit, + kAudioOutputUnitProperty_CurrentDevice, + kAudioUnitScope_Global, + 0, + &audioDeviceId, + sizeof(audioDeviceId)) != noErr) { + qWarning() << "QAudioInput: Unable to use configured device"; + return false; + } + + // Set format + // Wanted + streamFormat = toAudioStreamBasicDescription(audioFormat); + + // Required on unit + if (audioFormat == audioDeviceInfo->preferredFormat()) { + deviceFormat = streamFormat; + AudioUnitSetProperty(audioUnit, + kAudioUnitProperty_StreamFormat, + kAudioUnitScope_Output, + 1, + &deviceFormat, + sizeof(deviceFormat)); + } + else { + size = sizeof(deviceFormat); + if (AudioUnitGetProperty(audioUnit, + kAudioUnitProperty_StreamFormat, + kAudioUnitScope_Input, + 1, + &deviceFormat, + &size) != noErr) { + qWarning() << "QAudioInput: Unable to retrieve device format"; + return false; + } + + if (AudioUnitSetProperty(audioUnit, + kAudioUnitProperty_StreamFormat, + kAudioUnitScope_Output, + 1, + &deviceFormat, + sizeof(deviceFormat)) != noErr) { + qWarning() << "QAudioInput: Unable to set device format"; + return false; + } + } + + // Setup buffers + UInt32 numberOfFrames; + size = sizeof(UInt32); + if (AudioUnitGetProperty(audioUnit, + kAudioDevicePropertyBufferFrameSize, + kAudioUnitScope_Global, + 0, + &numberOfFrames, + &size) != noErr) { + qWarning() << "QAudioInput: Failed to get audio period size"; + return false; + } + + // Allocate buffer + periodSizeBytes = numberOfFrames * streamFormat.mBytesPerFrame; + + if (internalBufferSize < periodSizeBytes * 2) + internalBufferSize = periodSizeBytes * 2; + else + internalBufferSize -= internalBufferSize % streamFormat.mBytesPerFrame; + + audioBuffer = new QtMultimediaInternal::QAudioInputBuffer(internalBufferSize, + periodSizeBytes, + deviceFormat, + streamFormat, + this); + + audioIO = new QtMultimediaInternal::MacInputDevice(audioBuffer, this); + + // Init + if (AudioUnitInitialize(audioUnit) != noErr) { + qWarning() << "QAudioInput: Failed to initialize AudioUnit"; + return false; + } + + isOpen = true; + + return isOpen; +} + +void QAudioInputPrivate::close() +{ + if (audioUnit != 0) { + AudioOutputUnitStop(audioUnit); + AudioUnitUninitialize(audioUnit); + CloseComponent(audioUnit); + } + + delete audioBuffer; +} + +QAudioFormat QAudioInputPrivate::format() const +{ + return audioFormat; +} + +void QAudioInputPrivate::setFormat(const QAudioFormat& fmt) +{ + if (stateCode == QAudio::StoppedState) + audioFormat = fmt; +} + +void QAudioInputPrivate::start(QIODevice* device) +{ + QIODevice* op = device; + + if (!audioDeviceInfo->isFormatSupported(audioFormat) || !open()) { + stateCode = QAudio::StoppedState; + errorCode = QAudio::OpenError; + return; + } + + reset(); + audioBuffer->reset(); + audioBuffer->setFlushDevice(op); + + if (op == 0) + op = audioIO; + + // Start + startTime = AudioGetCurrentHostTime(); + totalFrames = 0; + + audioThreadStart(); + + stateCode = QAudio::ActiveState; + errorCode = QAudio::NoError; + emit stateChanged(stateCode); +} + +QIODevice* QAudioInputPrivate::start() +{ + QIODevice* op = 0; + + if (!audioDeviceInfo->isFormatSupported(audioFormat) || !open()) { + stateCode = QAudio::StoppedState; + errorCode = QAudio::OpenError; + return audioIO; + } + + reset(); + audioBuffer->reset(); + audioBuffer->setFlushDevice(op); + + if (op == 0) + op = audioIO; + + // Start + startTime = AudioGetCurrentHostTime(); + totalFrames = 0; + + audioThreadStart(); + + stateCode = QAudio::ActiveState; + errorCode = QAudio::NoError; + emit stateChanged(stateCode); + + return op; +} + +void QAudioInputPrivate::stop() +{ + QMutexLocker lock(&mutex); + if (stateCode != QAudio::StoppedState) { + audioThreadStop(); + audioBuffer->flush(true); + + errorCode = QAudio::NoError; + stateCode = QAudio::StoppedState; + QMetaObject::invokeMethod(this, "stateChanged", Qt::QueuedConnection, Q_ARG(QAudio::State, stateCode)); + } +} + +void QAudioInputPrivate::reset() +{ + QMutexLocker lock(&mutex); + if (stateCode != QAudio::StoppedState) { + audioThreadStop(); + + errorCode = QAudio::NoError; + stateCode = QAudio::StoppedState; + QMetaObject::invokeMethod(this, "stateChanged", Qt::QueuedConnection, Q_ARG(QAudio::State, stateCode)); + } +} + +void QAudioInputPrivate::suspend() +{ + QMutexLocker lock(&mutex); + if (stateCode == QAudio::ActiveState || stateCode == QAudio::IdleState) { + audioThreadStop(); + + errorCode = QAudio::NoError; + stateCode = QAudio::SuspendedState; + QMetaObject::invokeMethod(this, "stateChanged", Qt::QueuedConnection, Q_ARG(QAudio::State, stateCode)); + } +} + +void QAudioInputPrivate::resume() +{ + QMutexLocker lock(&mutex); + if (stateCode == QAudio::SuspendedState) { + audioThreadStart(); + + errorCode = QAudio::NoError; + stateCode = QAudio::ActiveState; + QMetaObject::invokeMethod(this, "stateChanged", Qt::QueuedConnection, Q_ARG(QAudio::State, stateCode)); + } +} + +int QAudioInputPrivate::bytesReady() const +{ + return audioBuffer->used(); +} + +int QAudioInputPrivate::periodSize() const +{ + return periodSizeBytes; +} + +void QAudioInputPrivate::setBufferSize(int bs) +{ + internalBufferSize = bs; +} + +int QAudioInputPrivate::bufferSize() const +{ + return internalBufferSize; +} + +void QAudioInputPrivate::setNotifyInterval(int milliSeconds) +{ + if (intervalTimer->interval() == milliSeconds) + return; + + if (milliSeconds <= 0) + milliSeconds = 0; + + intervalTimer->setInterval(milliSeconds); +} + +int QAudioInputPrivate::notifyInterval() const +{ + return intervalTimer->interval(); +} + +qint64 QAudioInputPrivate::processedUSecs() const +{ + return totalFrames * 1000000 / audioFormat.frequency(); +} + +qint64 QAudioInputPrivate::elapsedUSecs() const +{ + if (stateCode == QAudio::StoppedState) + return 0; + + return (AudioGetCurrentHostTime() - startTime) / (clockFrequency / 1000); +} + +QAudio::Error QAudioInputPrivate::error() const +{ + return errorCode; +} + +QAudio::State QAudioInputPrivate::state() const +{ + return stateCode; +} + +void QAudioInputPrivate::audioThreadStop() +{ + stopTimers(); + if (audioThreadState.testAndSetAcquire(Running, Stopped)) + threadFinished.wait(&mutex); +} + +void QAudioInputPrivate::audioThreadStart() +{ + startTimers(); + audioThreadState = Running; + AudioOutputUnitStart(audioUnit); +} + +void QAudioInputPrivate::audioDeviceStop() +{ + AudioOutputUnitStop(audioUnit); + audioThreadState = Stopped; + threadFinished.wakeOne(); +} + +void QAudioInputPrivate::audioDeviceFull() +{ + QMutexLocker lock(&mutex); + if (stateCode == QAudio::ActiveState) { + audioDeviceStop(); + + errorCode = QAudio::UnderrunError; + stateCode = QAudio::IdleState; + QMetaObject::invokeMethod(this, "deviceStopped", Qt::QueuedConnection); + } +} + +void QAudioInputPrivate::audioDeviceError() +{ + QMutexLocker lock(&mutex); + if (stateCode == QAudio::ActiveState) { + audioDeviceStop(); + + errorCode = QAudio::IOError; + stateCode = QAudio::StoppedState; + QMetaObject::invokeMethod(this, "deviceStopped", Qt::QueuedConnection); + } +} + +void QAudioInputPrivate::startTimers() +{ + audioBuffer->startFlushTimer(); + if (intervalTimer->interval() > 0) + intervalTimer->start(); +} + +void QAudioInputPrivate::stopTimers() +{ + audioBuffer->stopFlushTimer(); + intervalTimer->stop(); +} + +void QAudioInputPrivate::deviceStopped() +{ + stopTimers(); + emit stateChanged(stateCode); +} + +// Input callback +OSStatus QAudioInputPrivate::inputCallback(void* inRefCon, + AudioUnitRenderActionFlags* ioActionFlags, + const AudioTimeStamp* inTimeStamp, + UInt32 inBusNumber, + UInt32 inNumberFrames, + AudioBufferList* ioData) +{ + Q_UNUSED(ioData); + + QAudioInputPrivate* d = static_cast<QAudioInputPrivate*>(inRefCon); + + const int threadState = d->audioThreadState.fetchAndAddAcquire(0); + if (threadState == Stopped) + d->audioDeviceStop(); + else { + qint64 framesWritten; + + framesWritten = d->audioBuffer->renderFromDevice(d->audioUnit, + ioActionFlags, + inTimeStamp, + inBusNumber, + inNumberFrames); + + if (framesWritten > 0) + d->totalFrames += framesWritten; + else if (framesWritten == 0) + d->audioDeviceFull(); + else if (framesWritten < 0) + d->audioDeviceError(); + } + + return noErr; +} + + +QT_END_NAMESPACE + +#include "qaudioinput_mac_p.moc" diff --git a/src/multimedia/audio/qaudioinput_mac_p.h b/src/multimedia/audio/qaudioinput_mac_p.h new file mode 100644 index 000000000..99aaba978 --- /dev/null +++ b/src/multimedia/audio/qaudioinput_mac_p.h @@ -0,0 +1,174 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + + +#ifndef QAUDIOINPUT_MAC_P_H +#define QAUDIOINPUT_MAC_P_H + +#include <CoreServices/CoreServices.h> +#include <CoreAudio/CoreAudio.h> +#include <AudioUnit/AudioUnit.h> +#include <AudioToolbox/AudioToolbox.h> + +#include <QtCore/qobject.h> +#include <QtCore/qmutex.h> +#include <QtCore/qwaitcondition.h> +#include <QtCore/qatomic.h> + +#include <qaudio.h> +#include <qaudioformat.h> +#include <qaudiosystem.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + +class QTimer; +class QIODevice; +class QAbstractAudioDeviceInfo; + +namespace QtMultimediaInternal +{ +class QAudioInputBuffer; +} + +class QAudioInputPrivate : public QAbstractAudioInput +{ + Q_OBJECT + +public: + bool isOpen; + int periodSizeBytes; + int internalBufferSize; + qint64 totalFrames; + QAudioFormat audioFormat; + QIODevice* audioIO; + AudioUnit audioUnit; + AudioDeviceID audioDeviceId; + Float64 clockFrequency; + UInt64 startTime; + QAudio::Error errorCode; + QAudio::State stateCode; + QtMultimediaInternal::QAudioInputBuffer* audioBuffer; + QMutex mutex; + QWaitCondition threadFinished; + QAtomicInt audioThreadState; + QTimer* intervalTimer; + AudioStreamBasicDescription streamFormat; + AudioStreamBasicDescription deviceFormat; + QAbstractAudioDeviceInfo *audioDeviceInfo; + + QAudioInputPrivate(const QByteArray& device); + ~QAudioInputPrivate(); + + bool open(); + void close(); + + QAudioFormat format() const; + void setFormat(const QAudioFormat& fmt); + + QIODevice* start(); + void start(QIODevice* device); + void stop(); + void reset(); + void suspend(); + void resume(); + void idle(); + + int bytesReady() const; + int periodSize() const; + + void setBufferSize(int value); + int bufferSize() const; + + void setNotifyInterval(int milliSeconds); + int notifyInterval() const; + + qint64 processedUSecs() const; + qint64 elapsedUSecs() const; + + QAudio::Error error() const; + QAudio::State state() const; + + void audioThreadStart(); + void audioThreadStop(); + + void audioDeviceStop(); + void audioDeviceFull(); + void audioDeviceError(); + + void startTimers(); + void stopTimers(); + +private slots: + void deviceStopped(); + +private: + enum { Running, Stopped }; + + // Input callback + static OSStatus inputCallback(void* inRefCon, + AudioUnitRenderActionFlags* ioActionFlags, + const AudioTimeStamp* inTimeStamp, + UInt32 inBusNumber, + UInt32 inNumberFrames, + AudioBufferList* ioData); +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QAUDIOINPUT_MAC_P_H diff --git a/src/multimedia/audio/qaudioinput_win32_p.cpp b/src/multimedia/audio/qaudioinput_win32_p.cpp new file mode 100644 index 000000000..718656ba3 --- /dev/null +++ b/src/multimedia/audio/qaudioinput_win32_p.cpp @@ -0,0 +1,642 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// INTERNAL USE ONLY: Do NOT use for any other purpose. +// + + +#include "qaudioinput_win32_p.h" + +QT_BEGIN_NAMESPACE + +//#define DEBUG_AUDIO 1 + +QAudioInputPrivate::QAudioInputPrivate(const QByteArray &device) +{ + bytesAvailable = 0; + buffer_size = 0; + period_size = 0; + m_device = device; + totalTimeValue = 0; + intervalTime = 1000; + errorState = QAudio::NoError; + deviceState = QAudio::StoppedState; + audioSource = 0; + pullMode = true; + resuming = false; + finished = false; + waveBlockOffset = 0; +} + +QAudioInputPrivate::~QAudioInputPrivate() +{ + stop(); +} + +void QT_WIN_CALLBACK QAudioInputPrivate::waveInProc( HWAVEIN hWaveIn, UINT uMsg, + DWORD dwInstance, DWORD dwParam1, DWORD dwParam2 ) +{ + Q_UNUSED(dwParam1) + Q_UNUSED(dwParam2) + Q_UNUSED(hWaveIn) + + QAudioInputPrivate* qAudio; + qAudio = (QAudioInputPrivate*)(dwInstance); + if(!qAudio) + return; + + QMutexLocker(&qAudio->mutex); + + switch(uMsg) { + case WIM_OPEN: + break; + case WIM_DATA: + if(qAudio->waveFreeBlockCount > 0) + qAudio->waveFreeBlockCount--; + qAudio->feedback(); + break; + case WIM_CLOSE: + qAudio->finished = true; + break; + default: + return; + } +} + +WAVEHDR* QAudioInputPrivate::allocateBlocks(int size, int count) +{ + int i; + unsigned char* buffer; + WAVEHDR* blocks; + DWORD totalBufferSize = (size + sizeof(WAVEHDR))*count; + + if((buffer=(unsigned char*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, + totalBufferSize)) == 0) { + qWarning("QAudioInput: Memory allocation error"); + return 0; + } + blocks = (WAVEHDR*)buffer; + buffer += sizeof(WAVEHDR)*count; + for(i = 0; i < count; i++) { + blocks[i].dwBufferLength = size; + blocks[i].lpData = (LPSTR)buffer; + blocks[i].dwBytesRecorded=0; + blocks[i].dwUser = 0L; + blocks[i].dwFlags = 0L; + blocks[i].dwLoops = 0L; + result = waveInPrepareHeader(hWaveIn,&blocks[i], sizeof(WAVEHDR)); + if(result != MMSYSERR_NOERROR) { + qWarning("QAudioInput: Can't prepare block %d",i); + return 0; + } + buffer += size; + } + return blocks; +} + +void QAudioInputPrivate::freeBlocks(WAVEHDR* blockArray) +{ + WAVEHDR* blocks = blockArray; + + int count = buffer_size/period_size; + + for(int i = 0; i < count; i++) { + waveInUnprepareHeader(hWaveIn,blocks, sizeof(WAVEHDR)); + blocks++; + } + HeapFree(GetProcessHeap(), 0, blockArray); +} + +QAudio::Error QAudioInputPrivate::error() const +{ + return errorState; +} + +QAudio::State QAudioInputPrivate::state() const +{ + return deviceState; +} + +void QAudioInputPrivate::setFormat(const QAudioFormat& fmt) +{ + if (deviceState == QAudio::StoppedState) + settings = fmt; +} + +QAudioFormat QAudioInputPrivate::format() const +{ + return settings; +} + +void QAudioInputPrivate::start(QIODevice* device) +{ + if(deviceState != QAudio::StoppedState) + close(); + + if(!pullMode && audioSource) + delete audioSource; + + pullMode = true; + audioSource = device; + + deviceState = QAudio::ActiveState; + + if(!open()) + return; + + emit stateChanged(deviceState); +} + +QIODevice* QAudioInputPrivate::start() +{ + if(deviceState != QAudio::StoppedState) + close(); + + if(!pullMode && audioSource) + delete audioSource; + + pullMode = false; + audioSource = new InputPrivate(this); + audioSource->open(QIODevice::ReadOnly | QIODevice::Unbuffered); + + deviceState = QAudio::IdleState; + + if(!open()) + return 0; + + emit stateChanged(deviceState); + + return audioSource; +} + +void QAudioInputPrivate::stop() +{ + if(deviceState == QAudio::StoppedState) + return; + + close(); + emit stateChanged(deviceState); +} + +bool QAudioInputPrivate::open() +{ +#ifdef DEBUG_AUDIO + QTime now(QTime::currentTime()); + qDebug()<<now.second()<<"s "<<now.msec()<<"ms :open()"; +#endif + header = 0; + + period_size = 0; + + if (!settings.isValid()) { + qWarning("QAudioInput: open error, invalid format."); + } else if (settings.channelCount() <= 0) { + qWarning("QAudioInput: open error, invalid number of channels (%d).", + settings.channelCount()); + } else if (settings.sampleSize() <= 0) { + qWarning("QAudioInput: open error, invalid sample size (%d).", + settings.sampleSize()); + } else if (settings.frequency() < 8000 || settings.frequency() > 48000) { + qWarning("QAudioInput: open error, frequency out of range (%d).", settings.frequency()); + } else if (buffer_size == 0) { + + buffer_size + = (settings.frequency() + * settings.channelCount() + * settings.sampleSize() + + 39) / 40; + period_size = buffer_size / 5; + } else { + period_size = buffer_size / 5; + } + + if (period_size == 0) { + errorState = QAudio::OpenError; + deviceState = QAudio::StoppedState; + emit stateChanged(deviceState); + return false; + } + + timeStamp.restart(); + elapsedTimeOffset = 0; + wfx.nSamplesPerSec = settings.frequency(); + wfx.wBitsPerSample = settings.sampleSize(); + wfx.nChannels = settings.channels(); + wfx.cbSize = 0; + + wfx.wFormatTag = WAVE_FORMAT_PCM; + wfx.nBlockAlign = (wfx.wBitsPerSample >> 3) * wfx.nChannels; + wfx.nAvgBytesPerSec = wfx.nBlockAlign * wfx.nSamplesPerSec; + + QDataStream ds(&m_device, QIODevice::ReadOnly); + quint32 deviceId; + ds >> deviceId; + + if (waveInOpen(&hWaveIn, UINT_PTR(deviceId), &wfx, + (DWORD_PTR)&waveInProc, + (DWORD_PTR) this, + CALLBACK_FUNCTION) != MMSYSERR_NOERROR) { + errorState = QAudio::OpenError; + deviceState = QAudio::StoppedState; + emit stateChanged(deviceState); + qWarning("QAudioInput: failed to open audio device"); + return false; + } + waveBlocks = allocateBlocks(period_size, buffer_size/period_size); + waveBlockOffset = 0; + + if(waveBlocks == 0) { + errorState = QAudio::OpenError; + deviceState = QAudio::StoppedState; + emit stateChanged(deviceState); + qWarning("QAudioInput: failed to allocate blocks. open failed"); + return false; + } + + mutex.lock(); + waveFreeBlockCount = buffer_size/period_size; + mutex.unlock(); + + for(int i=0; i<buffer_size/period_size; i++) { + result = waveInAddBuffer(hWaveIn, &waveBlocks[i], sizeof(WAVEHDR)); + if(result != MMSYSERR_NOERROR) { + qWarning("QAudioInput: failed to setup block %d,err=%d",i,result); + errorState = QAudio::OpenError; + deviceState = QAudio::StoppedState; + emit stateChanged(deviceState); + return false; + } + } + result = waveInStart(hWaveIn); + if(result) { + qWarning("QAudioInput: failed to start audio input"); + errorState = QAudio::OpenError; + deviceState = QAudio::StoppedState; + emit stateChanged(deviceState); + return false; + } + timeStampOpened.restart(); + elapsedTimeOffset = 0; + totalTimeValue = 0; + errorState = QAudio::NoError; + return true; +} + +void QAudioInputPrivate::close() +{ + if(deviceState == QAudio::StoppedState) + return; + + deviceState = QAudio::StoppedState; + waveInReset(hWaveIn); + waveInClose(hWaveIn); + + int count = 0; + while(!finished && count < 500) { + count++; + Sleep(10); + } + + mutex.lock(); + for(int i=0; i<waveFreeBlockCount; i++) + waveInUnprepareHeader(hWaveIn,&waveBlocks[i],sizeof(WAVEHDR)); + freeBlocks(waveBlocks); + mutex.unlock(); +} + +int QAudioInputPrivate::bytesReady() const +{ + if(period_size == 0 || buffer_size == 0) + return 0; + + int buf = ((buffer_size/period_size)-waveFreeBlockCount)*period_size; + if(buf < 0) + buf = 0; + return buf; +} + +qint64 QAudioInputPrivate::read(char* data, qint64 len) +{ + bool done = false; + + char* p = data; + qint64 l = 0; + qint64 written = 0; + while(!done) { + // Read in some audio data + if(waveBlocks[header].dwBytesRecorded > 0 && waveBlocks[header].dwFlags & WHDR_DONE) { + if(pullMode) { + l = audioSource->write(waveBlocks[header].lpData + waveBlockOffset, + waveBlocks[header].dwBytesRecorded - waveBlockOffset); +#ifdef DEBUG_AUDIO + qDebug()<<"IN: "<<waveBlocks[header].dwBytesRecorded<<", OUT: "<<l; +#endif + if(l < 0) { + // error + qWarning("QAudioInput: IOError"); + errorState = QAudio::IOError; + + } else if(l == 0) { + // cant write to IODevice + qWarning("QAudioInput: IOError, can't write to QIODevice"); + errorState = QAudio::IOError; + + } else { + totalTimeValue += l; + errorState = QAudio::NoError; + if (deviceState != QAudio::ActiveState) { + deviceState = QAudio::ActiveState; + emit stateChanged(deviceState); + } + resuming = false; + } + } else { + l = qMin<qint64>(len, waveBlocks[header].dwBytesRecorded - waveBlockOffset); + // push mode + memcpy(p, waveBlocks[header].lpData + waveBlockOffset, l); + + len -= l; + +#ifdef DEBUG_AUDIO + qDebug()<<"IN: "<<waveBlocks[header].dwBytesRecorded<<", OUT: "<<l; +#endif + totalTimeValue += l; + errorState = QAudio::NoError; + if (deviceState != QAudio::ActiveState) { + deviceState = QAudio::ActiveState; + emit stateChanged(deviceState); + } + resuming = false; + } + } else { + //no data, not ready yet, next time + break; + } + + if (l < waveBlocks[header].dwBytesRecorded - waveBlockOffset) { + waveBlockOffset += l; + done = true; + } else { + waveBlockOffset = 0; + + waveInUnprepareHeader(hWaveIn,&waveBlocks[header], sizeof(WAVEHDR)); + + mutex.lock(); + waveFreeBlockCount++; + mutex.unlock(); + + waveBlocks[header].dwBytesRecorded=0; + waveBlocks[header].dwFlags = 0L; + result = waveInPrepareHeader(hWaveIn,&waveBlocks[header], sizeof(WAVEHDR)); + if(result != MMSYSERR_NOERROR) { + result = waveInPrepareHeader(hWaveIn,&waveBlocks[header], sizeof(WAVEHDR)); + qWarning("QAudioInput: failed to prepare block %d,err=%d",header,result); + errorState = QAudio::IOError; + + mutex.lock(); + waveFreeBlockCount--; + mutex.unlock(); + + return 0; + } + result = waveInAddBuffer(hWaveIn, &waveBlocks[header], sizeof(WAVEHDR)); + if(result != MMSYSERR_NOERROR) { + qWarning("QAudioInput: failed to setup block %d,err=%d",header,result); + errorState = QAudio::IOError; + + mutex.lock(); + waveFreeBlockCount--; + mutex.unlock(); + + return 0; + } + header++; + if(header >= buffer_size/period_size) + header = 0; + p+=l; + + mutex.lock(); + if(!pullMode) { + if(len < period_size || waveFreeBlockCount == buffer_size/period_size) + done = true; + } else { + if(waveFreeBlockCount == buffer_size/period_size) + done = true; + } + mutex.unlock(); + } + + written+=l; + } +#ifdef DEBUG_AUDIO + qDebug()<<"read in len="<<written; +#endif + return written; +} + +void QAudioInputPrivate::resume() +{ + if(deviceState == QAudio::SuspendedState) { + deviceState = QAudio::ActiveState; + for(int i=0; i<buffer_size/period_size; i++) { + result = waveInAddBuffer(hWaveIn, &waveBlocks[i], sizeof(WAVEHDR)); + if(result != MMSYSERR_NOERROR) { + qWarning("QAudioInput: failed to setup block %d,err=%d",i,result); + errorState = QAudio::OpenError; + deviceState = QAudio::StoppedState; + emit stateChanged(deviceState); + return; + } + } + + mutex.lock(); + waveFreeBlockCount = buffer_size/period_size; + mutex.unlock(); + + header = 0; + resuming = true; + waveBlockOffset = 0; + waveInStart(hWaveIn); + QTimer::singleShot(20,this,SLOT(feedback())); + emit stateChanged(deviceState); + } +} + +void QAudioInputPrivate::setBufferSize(int value) +{ + buffer_size = value; +} + +int QAudioInputPrivate::bufferSize() const +{ + return buffer_size; +} + +int QAudioInputPrivate::periodSize() const +{ + return period_size; +} + +void QAudioInputPrivate::setNotifyInterval(int ms) +{ + intervalTime = qMax(0, ms); +} + +int QAudioInputPrivate::notifyInterval() const +{ + return intervalTime; +} + +qint64 QAudioInputPrivate::processedUSecs() const +{ + if (deviceState == QAudio::StoppedState) + return 0; + qint64 result = qint64(1000000) * totalTimeValue / + (settings.channels()*(settings.sampleSize()/8)) / + settings.frequency(); + + return result; +} + +void QAudioInputPrivate::suspend() +{ + if(deviceState == QAudio::ActiveState) { + waveInReset(hWaveIn); + deviceState = QAudio::SuspendedState; + emit stateChanged(deviceState); + } +} + +void QAudioInputPrivate::feedback() +{ +#ifdef DEBUG_AUDIO + QTime now(QTime::currentTime()); + qDebug()<<now.second()<<"s "<<now.msec()<<"ms :feedback() INPUT "<<this; +#endif + if(!(deviceState==QAudio::StoppedState||deviceState==QAudio::SuspendedState)) + QMetaObject::invokeMethod(this, "deviceReady", Qt::QueuedConnection); +} + +bool QAudioInputPrivate::deviceReady() +{ + bytesAvailable = bytesReady(); +#ifdef DEBUG_AUDIO + QTime now(QTime::currentTime()); + qDebug()<<now.second()<<"s "<<now.msec()<<"ms :deviceReady() INPUT"; +#endif + if(deviceState != QAudio::ActiveState && deviceState != QAudio::IdleState) + return true; + + if(pullMode) { + // reads some audio data and writes it to QIODevice + read(0, buffer_size); + } else { + // emits readyRead() so user will call read() on QIODevice to get some audio data + InputPrivate* a = qobject_cast<InputPrivate*>(audioSource); + a->trigger(); + } + + if(intervalTime && (timeStamp.elapsed() + elapsedTimeOffset) > intervalTime) { + emit notify(); + elapsedTimeOffset = timeStamp.elapsed() + elapsedTimeOffset - intervalTime; + timeStamp.restart(); + } + return true; +} + +qint64 QAudioInputPrivate::elapsedUSecs() const +{ + if (deviceState == QAudio::StoppedState) + return 0; + + return timeStampOpened.elapsed()*1000; +} + +void QAudioInputPrivate::reset() +{ + stop(); + if (period_size > 0) + waveFreeBlockCount = buffer_size / period_size; +} + +InputPrivate::InputPrivate(QAudioInputPrivate* audio) +{ + audioDevice = qobject_cast<QAudioInputPrivate*>(audio); +} + +InputPrivate::~InputPrivate() {} + +qint64 InputPrivate::readData( char* data, qint64 len) +{ + // push mode, user read() called + if(audioDevice->deviceState != QAudio::ActiveState && + audioDevice->deviceState != QAudio::IdleState) + return 0; + // Read in some audio data + return audioDevice->read(data,len); +} + +qint64 InputPrivate::writeData(const char* data, qint64 len) +{ + Q_UNUSED(data) + Q_UNUSED(len) + + emit readyRead(); + return 0; +} + +void InputPrivate::trigger() +{ + emit readyRead(); +} + +QT_END_NAMESPACE + +#include "moc_qaudioinput_win32_p.cpp" + diff --git a/src/multimedia/audio/qaudioinput_win32_p.h b/src/multimedia/audio/qaudioinput_win32_p.h new file mode 100644 index 000000000..10d41a552 --- /dev/null +++ b/src/multimedia/audio/qaudioinput_win32_p.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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#ifndef QAUDIOINPUTWIN_H +#define QAUDIOINPUTWIN_H + +#include <windows.h> +#include <mmsystem.h> + +#include <QtCore/qfile.h> +#include <QtCore/qdebug.h> +#include <QtCore/qtimer.h> +#include <QtCore/qstring.h> +#include <QtCore/qstringlist.h> +#include <QtCore/qdatetime.h> +#include <QtCore/qmutex.h> + +#include <qaudio.h> +#include <qaudiodeviceinfo.h> +#include <qaudiosystem.h> + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + +// For compat with 4.6 +#if !defined(QT_WIN_CALLBACK) +# if defined(Q_CC_MINGW) +# define QT_WIN_CALLBACK CALLBACK __attribute__ ((force_align_arg_pointer)) +# else +# define QT_WIN_CALLBACK CALLBACK +# endif +#endif + +class QAudioInputPrivate : public QAbstractAudioInput +{ + Q_OBJECT +public: + QAudioInputPrivate(const QByteArray &device); + ~QAudioInputPrivate(); + + qint64 read(char* data, qint64 len); + + void setFormat(const QAudioFormat& fmt); + QAudioFormat format() const; + QIODevice* start(); + void start(QIODevice* device); + void stop(); + void reset(); + void suspend(); + void resume(); + int bytesReady() const; + int periodSize() const; + void setBufferSize(int value); + int bufferSize() const; + void setNotifyInterval(int milliSeconds); + int notifyInterval() const; + qint64 processedUSecs() const; + qint64 elapsedUSecs() const; + QAudio::Error error() const; + QAudio::State state() const; + + QIODevice* audioSource; + QAudioFormat settings; + QAudio::Error errorState; + QAudio::State deviceState; + +private: + qint32 buffer_size; + qint32 period_size; + qint32 header; + QByteArray m_device; + int bytesAvailable; + int intervalTime; + QTime timeStamp; + qint64 elapsedTimeOffset; + QTime timeStampOpened; + qint64 totalTimeValue; + bool pullMode; + bool resuming; + WAVEFORMATEX wfx; + HWAVEIN hWaveIn; + MMRESULT result; + WAVEHDR* waveBlocks; + volatile bool finished; + volatile int waveFreeBlockCount; + int waveBlockOffset; + + QMutex mutex; + static void QT_WIN_CALLBACK waveInProc( HWAVEIN hWaveIn, UINT uMsg, + DWORD dwInstance, DWORD dwParam1, DWORD dwParam2 ); + + WAVEHDR* allocateBlocks(int size, int count); + void freeBlocks(WAVEHDR* blockArray); + bool open(); + void close(); + +private slots: + void feedback(); + bool deviceReady(); + +signals: + void processMore(); +}; + +class InputPrivate : public QIODevice +{ + Q_OBJECT +public: + InputPrivate(QAudioInputPrivate* audio); + ~InputPrivate(); + + qint64 readData( char* data, qint64 len); + qint64 writeData(const char* data, qint64 len); + + void trigger(); +private: + QAudioInputPrivate *audioDevice; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + + +#endif diff --git a/src/multimedia/audio/qaudiooutput.cpp b/src/multimedia/audio/qaudiooutput.cpp new file mode 100644 index 000000000..05db98bd6 --- /dev/null +++ b/src/multimedia/audio/qaudiooutput.cpp @@ -0,0 +1,404 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include "qaudio.h" +#include "qaudiodeviceinfo.h" +#include "qaudiosystem.h" +#include "qaudiooutput.h" + +#include "qaudiodevicefactory_p.h" + + +QT_BEGIN_NAMESPACE + +/*! + \class QAudioOutput + \brief The QAudioOutput class provides an interface for sending audio data to an audio output device. + + \inmodule QtMultimedia + \ingroup multimedia + \since 1.0 + + You can construct an audio output with the system's + \l{QAudioDeviceInfo::defaultOutputDevice()}{default audio output + device}. It is also possible to create QAudioOutput with a + specific QAudioDeviceInfo. When you create the audio output, you + should also send in the QAudioFormat to be used for the playback + (see the QAudioFormat class description for details). + + To play a file: + + Starting to play an audio stream is simply a matter of calling + start() with a QIODevice. QAudioOutput will then fetch the data it + needs from the io device. So playing back an audio file is as + simple as: + + \snippet doc/src/snippets/multimedia-snippets/audio.cpp Audio output class members + + \snippet doc/src/snippets/multimedia-snippets/audio.cpp Audio output setup + + The file will start playing assuming that the audio system and + output device support it. If you run out of luck, check what's + up with the error() function. + + After the file has finished playing, we need to stop the device: + + \snippet doc/src/snippets/multimedia-snippets/audio.cpp Audio output state changed + + At any given time, the QAudioOutput will be in one of four states: + active, suspended, stopped, or idle. These states are described + by the QAudio::State enum. + State changes are reported through the stateChanged() signal. You + can use this signal to, for instance, update the GUI of the + application; the mundane example here being changing the state of + a \c { play/pause } button. You request a state change directly + with suspend(), stop(), reset(), resume(), and start(). + + While the stream is playing, you can set a notify interval in + milliseconds with setNotifyInterval(). This interval specifies the + time between two emissions of the notify() signal. This is + relative to the position in the stream, i.e., if the QAudioOutput + is in the SuspendedState or the IdleState, the notify() signal is + not emitted. A typical use-case would be to update a + \l{QSlider}{slider} that allows seeking in the stream. + If you want the time since playback started regardless of which + states the audio output has been in, elapsedUSecs() is the function for you. + + If an error occurs, you can fetch the \l{QAudio::Error}{error + type} with the error() function. Please see the QAudio::Error enum + for a description of the possible errors that are reported. When + an error is encountered, the state changes to QAudio::StoppedState. + You can check for errors by connecting to the stateChanged() + signal: + + \snippet doc/src/snippets/multimedia-snippets/audio.cpp Audio output state changed + + \sa QAudioInput, QAudioDeviceInfo +*/ + +/*! + Construct a new audio output and attach it to \a parent. + The default audio output device is used with the output + \a format parameters. + \since 1.0 +*/ +QAudioOutput::QAudioOutput(const QAudioFormat &format, QObject *parent): + QObject(parent) +{ + d = QAudioDeviceFactory::createDefaultOutputDevice(format); + connect(d, SIGNAL(notify()), SIGNAL(notify())); + connect(d, SIGNAL(stateChanged(QAudio::State)), SIGNAL(stateChanged(QAudio::State))); +} + +/*! + Construct a new audio output and attach it to \a parent. + The device referenced by \a audioDevice is used with the output + \a format parameters. + \since 1.0 +*/ +QAudioOutput::QAudioOutput(const QAudioDeviceInfo &audioDevice, const QAudioFormat &format, QObject *parent): + QObject(parent) +{ + d = QAudioDeviceFactory::createOutputDevice(audioDevice, format); + connect(d, SIGNAL(notify()), SIGNAL(notify())); + connect(d, SIGNAL(stateChanged(QAudio::State)), SIGNAL(stateChanged(QAudio::State))); +} + +/*! + Destroys this audio output. + + This will release any system resources used and free any buffers. +*/ +QAudioOutput::~QAudioOutput() +{ + delete d; +} + +/*! + Returns the QAudioFormat being used. + + \since 1.0 +*/ +QAudioFormat QAudioOutput::format() const +{ + return d->format(); +} + +/*! + Uses the \a device as the QIODevice to transfer data. + Passing a QIODevice allows the data to be transferred without any extra code. + All that is required is to open the QIODevice. + + If able to successfully output audio data to the systems audio device the + state() is set to QAudio::ActiveState, error() is set to QAudio::NoError + and the stateChanged() signal is emitted. + + If a problem occurs during this process the error() is set to QAudio::OpenError, + state() is set to QAudio::StoppedState and stateChanged() signal is emitted. + + \since 1.0 + \sa QIODevice +*/ +void QAudioOutput::start(QIODevice* device) +{ + d->start(device); +} + +/*! + Returns a pointer to the QIODevice being used to handle the data + transfer. This QIODevice can be used to write() audio data directly. + + If able to access the systems audio device the state() is set to + QAudio::IdleState, error() is set to QAudio::NoError + and the stateChanged() signal is emitted. + + If a problem occurs during this process the error() is set to QAudio::OpenError, + state() is set to QAudio::StoppedState and stateChanged() signal is emitted. + + \since 1.0 + \sa QIODevice +*/ +QIODevice* QAudioOutput::start() +{ + return d->start(); +} + +/*! + Stops the audio output, detaching from the system resource. + + Sets error() to QAudio::NoError, state() to QAudio::StoppedState and + emit stateChanged() signal. + \since 1.0 +*/ +void QAudioOutput::stop() +{ + d->stop(); +} + +/*! + Drops all audio data in the buffers, resets buffers to zero. + + \since 1.0 +*/ +void QAudioOutput::reset() +{ + d->reset(); +} + +/*! + Stops processing audio data, preserving buffered audio data. + + Sets error() to QAudio::NoError, state() to QAudio::SuspendedState and + emits stateChanged() signal. + \since 1.0 +*/ +void QAudioOutput::suspend() +{ + d->suspend(); +} + +/*! + Resumes processing audio data after a suspend(). + + Sets error() to QAudio::NoError. + Sets state() to QAudio::ActiveState if you previously called start(QIODevice*). + Sets state() to QAudio::IdleState if you previously called start(). + emits stateChanged() signal. + \since 1.0 +*/ +void QAudioOutput::resume() +{ + d->resume(); +} + +/*! + Returns the number of free bytes available in the audio buffer. + + \note The returned value is only valid while in QAudio::ActiveState or QAudio::IdleState + state, otherwise returns zero. + \since 1.0 +*/ +int QAudioOutput::bytesFree() const +{ + return d->bytesFree(); +} + +/*! + Returns the period size in bytes. This is the amount of data required each period + to prevent buffer underrun, and to ensure uninterrupted playback. + + \note It is recommended to provide at least enough data for a full period with each + write operation. + \since 1.0 +*/ +int QAudioOutput::periodSize() const +{ + return d->periodSize(); +} + +/*! + Sets the audio buffer size to \a value in bytes. + + \note This function can be called anytime before start(). Calls to this + are ignored after start(). It should not be assumed that the buffer size + set is the actual buffer size used - call bufferSize() anytime after start() + to return the actual buffer size being used. + \since 1.0 +*/ +void QAudioOutput::setBufferSize(int value) +{ + d->setBufferSize(value); +} + +/*! + Returns the audio buffer size in bytes. + + If called before start(), returns platform default value. + If called before start() but setBufferSize() was called prior, returns value set by setBufferSize(). + If called after start(), returns the actual buffer size being used. This may not be what was set previously + by setBufferSize(). + + \since 1.0 +*/ +int QAudioOutput::bufferSize() const +{ + return d->bufferSize(); +} + +/*! + Sets the interval for notify() signal to be emitted. + This is based on the \a ms of audio data processed, + not on wall clock time. + The minimum resolution of the timer is platform specific and values + should be checked with notifyInterval() to confirm the actual value + being used. + \since 1.0 +*/ +void QAudioOutput::setNotifyInterval(int ms) +{ + d->setNotifyInterval(ms); +} + +/*! + Returns the notify interval in milliseconds. + \since 1.0 +*/ +int QAudioOutput::notifyInterval() const +{ + return d->notifyInterval(); +} + +/*! + Returns the amount of audio data processed since start() + was called (in microseconds). + \since 1.0 +*/ +qint64 QAudioOutput::processedUSecs() const +{ + return d->processedUSecs(); +} + +/*! + Returns the microseconds since start() was called, including time in Idle and + Suspend states. + \since 1.0 +*/ +qint64 QAudioOutput::elapsedUSecs() const +{ + return d->elapsedUSecs(); +} + +/*! + Returns the error state. + \since 1.0 +*/ +QAudio::Error QAudioOutput::error() const +{ + return d->error(); +} + +/*! + Returns the state of audio processing. + \since 1.0 +*/ +QAudio::State QAudioOutput::state() const +{ + return d->state(); +} + +/*! + Sets the volume. + Where \a volume is between 0.0 and 1.0 inclusive. + \since 5.0 +*/ +void QAudioOutput::setVolume(qreal volume) +{ + d->setVolume(volume); +} + +/*! + Returns the volume between 0.0 and 1.0 inclusive. + \since 5.0 +*/ +qreal QAudioOutput::volume() const +{ + return d->volume(); +} + +/*! + \fn QAudioOutput::stateChanged(QAudio::State state) + This signal is emitted when the device \a state has changed. + This is the current state of the audio output. + \since 1.0 +*/ + +/*! + \fn QAudioOutput::notify() + This signal is emitted when a certain interval of milliseconds + of audio data has been processed. The interval is set by + setNotifyInterval(). + \since 1.0 +*/ + +QT_END_NAMESPACE + +#include "moc_qaudiooutput.cpp" diff --git a/src/multimedia/audio/qaudiooutput.h b/src/multimedia/audio/qaudiooutput.h new file mode 100644 index 000000000..3edec1b4a --- /dev/null +++ b/src/multimedia/audio/qaudiooutput.h @@ -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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#ifndef QAUDIOOUTPUT_H +#define QAUDIOOUTPUT_H + +#include <QtCore/qiodevice.h> + +#include <qtmultimediadefs.h> +#include <qtmedianamespace.h> + +#include <qaudio.h> +#include <qaudioformat.h> +#include <qaudiodeviceinfo.h> + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + + +class QAbstractAudioOutput; + +class Q_MULTIMEDIA_EXPORT QAudioOutput : public QObject +{ + Q_OBJECT + +public: + explicit QAudioOutput(const QAudioFormat &format = QAudioFormat(), QObject *parent = 0); + explicit QAudioOutput(const QAudioDeviceInfo &audioDeviceInfo, const QAudioFormat &format = QAudioFormat(), QObject *parent = 0); + ~QAudioOutput(); + + QAudioFormat format() const; + + void start(QIODevice *device); + QIODevice* start(); + + void stop(); + void reset(); + void suspend(); + void resume(); + + void setBufferSize(int bytes); + int bufferSize() const; + + int bytesFree() const; + int periodSize() const; + + void setNotifyInterval(int milliSeconds); + int notifyInterval() const; + + qint64 processedUSecs() const; + qint64 elapsedUSecs() const; + + QAudio::Error error() const; + QAudio::State state() const; + + void setVolume(qreal); + qreal volume() const; + +Q_SIGNALS: + void stateChanged(QAudio::State); + void notify(); + +private: + Q_DISABLE_COPY(QAudioOutput) + + QAbstractAudioOutput* d; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QAUDIOOUTPUT_H diff --git a/src/multimedia/audio/qaudiooutput_alsa_p.cpp b/src/multimedia/audio/qaudiooutput_alsa_p.cpp new file mode 100644 index 000000000..8ef4e2819 --- /dev/null +++ b/src/multimedia/audio/qaudiooutput_alsa_p.cpp @@ -0,0 +1,834 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// INTERNAL USE ONLY: Do NOT use for any other purpose. +// + +#include <QtCore/qcoreapplication.h> +#include "qaudiooutput_alsa_p.h" +#include "qaudiodeviceinfo_alsa_p.h" + +QT_BEGIN_NAMESPACE + +//#define DEBUG_AUDIO 1 + +QAudioOutputPrivate::QAudioOutputPrivate(const QByteArray &device) +{ + bytesAvailable = 0; + handle = 0; + ahandler = 0; + access = SND_PCM_ACCESS_RW_INTERLEAVED; + pcmformat = SND_PCM_FORMAT_S16; + buffer_frames = 0; + period_frames = 0; + buffer_size = 0; + period_size = 0; + buffer_time = 100000; + period_time = 20000; + totalTimeValue = 0; + intervalTime = 1000; + audioBuffer = 0; + errorState = QAudio::NoError; + deviceState = QAudio::StoppedState; + audioSource = 0; + pullMode = true; + resuming = false; + opened = false; + + m_device = device; + + timer = new QTimer(this); + connect(timer,SIGNAL(timeout()),SLOT(userFeed())); +} + +QAudioOutputPrivate::~QAudioOutputPrivate() +{ + close(); + disconnect(timer, SIGNAL(timeout())); + QCoreApplication::processEvents(); + delete timer; +} + +QAudio::Error QAudioOutputPrivate::error() const +{ + return errorState; +} + +QAudio::State QAudioOutputPrivate::state() const +{ + return deviceState; +} + +void QAudioOutputPrivate::async_callback(snd_async_handler_t *ahandler) +{ + QAudioOutputPrivate* audioOut; + + audioOut = static_cast<QAudioOutputPrivate*> + (snd_async_handler_get_callback_private(ahandler)); + + if((audioOut->deviceState==QAudio::ActiveState)||(audioOut->resuming)) + audioOut->feedback(); +} + +int QAudioOutputPrivate::xrun_recovery(int err) +{ + int count = 0; + bool reset = false; + + if(err == -EPIPE) { + errorState = QAudio::UnderrunError; + emit errorChanged(errorState); + err = snd_pcm_prepare(handle); + if(err < 0) + reset = true; + + } else if((err == -ESTRPIPE)||(err == -EIO)) { + errorState = QAudio::IOError; + emit errorChanged(errorState); + while((err = snd_pcm_resume(handle)) == -EAGAIN){ + usleep(100); + count++; + if(count > 5) { + reset = true; + break; + } + } + if(err < 0) { + err = snd_pcm_prepare(handle); + if(err < 0) + reset = true; + } + } + if(reset) { + close(); + open(); + snd_pcm_prepare(handle); + return 0; + } + return err; +} + +int QAudioOutputPrivate::setFormat() +{ + snd_pcm_format_t pcmformat = SND_PCM_FORMAT_UNKNOWN; + + if(settings.sampleSize() == 8) { + pcmformat = SND_PCM_FORMAT_U8; + + } else if(settings.sampleSize() == 16) { + if(settings.sampleType() == QAudioFormat::SignedInt) { + if(settings.byteOrder() == QAudioFormat::LittleEndian) + pcmformat = SND_PCM_FORMAT_S16_LE; + else + pcmformat = SND_PCM_FORMAT_S16_BE; + } else if(settings.sampleType() == QAudioFormat::UnSignedInt) { + if(settings.byteOrder() == QAudioFormat::LittleEndian) + pcmformat = SND_PCM_FORMAT_U16_LE; + else + pcmformat = SND_PCM_FORMAT_U16_BE; + } + } else if(settings.sampleSize() == 24) { + if(settings.sampleType() == QAudioFormat::SignedInt) { + if(settings.byteOrder() == QAudioFormat::LittleEndian) + pcmformat = SND_PCM_FORMAT_S24_LE; + else + pcmformat = SND_PCM_FORMAT_S24_BE; + } else if(settings.sampleType() == QAudioFormat::UnSignedInt) { + if(settings.byteOrder() == QAudioFormat::LittleEndian) + pcmformat = SND_PCM_FORMAT_U24_LE; + else + pcmformat = SND_PCM_FORMAT_U24_BE; + } + } else if(settings.sampleSize() == 32) { + if(settings.sampleType() == QAudioFormat::SignedInt) { + if(settings.byteOrder() == QAudioFormat::LittleEndian) + pcmformat = SND_PCM_FORMAT_S32_LE; + else + pcmformat = SND_PCM_FORMAT_S32_BE; + } else if(settings.sampleType() == QAudioFormat::UnSignedInt) { + if(settings.byteOrder() == QAudioFormat::LittleEndian) + pcmformat = SND_PCM_FORMAT_U32_LE; + else + pcmformat = SND_PCM_FORMAT_U32_BE; + } else if(settings.sampleType() == QAudioFormat::Float) { + if(settings.byteOrder() == QAudioFormat::LittleEndian) + pcmformat = SND_PCM_FORMAT_FLOAT_LE; + else + pcmformat = SND_PCM_FORMAT_FLOAT_BE; + } + } else if(settings.sampleSize() == 64) { + if(settings.byteOrder() == QAudioFormat::LittleEndian) + pcmformat = SND_PCM_FORMAT_FLOAT64_LE; + else + pcmformat = SND_PCM_FORMAT_FLOAT64_BE; + } + + return pcmformat != SND_PCM_FORMAT_UNKNOWN + ? snd_pcm_hw_params_set_format( handle, hwparams, pcmformat) + : -1; +} + +void QAudioOutputPrivate::start(QIODevice* device) +{ + if(deviceState != QAudio::StoppedState) + deviceState = QAudio::StoppedState; + + errorState = QAudio::NoError; + + // Handle change of mode + if(audioSource && !pullMode) { + delete audioSource; + audioSource = 0; + } + + close(); + + pullMode = true; + audioSource = device; + + deviceState = QAudio::ActiveState; + + open(); + + emit stateChanged(deviceState); +} + +QIODevice* QAudioOutputPrivate::start() +{ + if(deviceState != QAudio::StoppedState) + deviceState = QAudio::StoppedState; + + errorState = QAudio::NoError; + + // Handle change of mode + if(audioSource && !pullMode) { + delete audioSource; + audioSource = 0; + } + + close(); + + audioSource = new OutputPrivate(this); + audioSource->open(QIODevice::WriteOnly|QIODevice::Unbuffered); + pullMode = false; + + deviceState = QAudio::IdleState; + + open(); + + emit stateChanged(deviceState); + + return audioSource; +} + +void QAudioOutputPrivate::stop() +{ + if(deviceState == QAudio::StoppedState) + return; + errorState = QAudio::NoError; + deviceState = QAudio::StoppedState; + close(); + emit stateChanged(deviceState); +} + +bool QAudioOutputPrivate::open() +{ + if(opened) + return true; + +#ifdef DEBUG_AUDIO + QTime now(QTime::currentTime()); + qDebug()<<now.second()<<"s "<<now.msec()<<"ms :open()"; +#endif + timeStamp.restart(); + elapsedTimeOffset = 0; + + int dir; + int err = 0; + int count=0; + unsigned int freakuency=settings.frequency(); + + if (!settings.isValid()) { + qWarning("QAudioOutput: open error, invalid format."); + } else if (settings.sampleRate() <= 0) { + qWarning("QAudioOutput: open error, invalid sample rate (%d).", + settings.sampleRate()); + } else { + err = -1; + } + + if (err == 0) { + errorState = QAudio::OpenError; + deviceState = QAudio::StoppedState; + emit errorChanged(errorState); + return false; + } + + QString dev = QString(QLatin1String(m_device.constData())); + QList<QByteArray> devices = QAudioDeviceInfoInternal::availableDevices(QAudio::AudioOutput); + if(dev.compare(QLatin1String("default")) == 0) { +#if(SND_LIB_MAJOR == 1 && SND_LIB_MINOR == 0 && SND_LIB_SUBMINOR >= 14) + if (devices.size() > 0) + dev = QLatin1String(devices.first()); + else + return false; +#else + dev = QLatin1String("hw:0,0"); +#endif + } else { +#if(SND_LIB_MAJOR == 1 && SND_LIB_MINOR == 0 && SND_LIB_SUBMINOR >= 14) + dev = QLatin1String(m_device); +#else + int idx = 0; + char *name; + + QString shortName = QLatin1String(m_device.mid(m_device.indexOf('=',0)+1).constData()); + + while(snd_card_get_name(idx,&name) == 0) { + if(qstrncmp(shortName.toLocal8Bit().constData(),name,shortName.length()) == 0) + break; + idx++; + } + dev = QString(QLatin1String("hw:%1,0")).arg(idx); +#endif + } + + // Step 1: try and open the device + while((count < 5) && (err < 0)) { + err=snd_pcm_open(&handle,dev.toLocal8Bit().constData(),SND_PCM_STREAM_PLAYBACK,0); + if(err < 0) + count++; + } + if (( err < 0)||(handle == 0)) { + errorState = QAudio::OpenError; + emit errorChanged(errorState); + deviceState = QAudio::StoppedState; + return false; + } + snd_pcm_nonblock( handle, 0 ); + + // Step 2: Set the desired HW parameters. + snd_pcm_hw_params_alloca( &hwparams ); + + bool fatal = false; + QString errMessage; + unsigned int chunks = 8; + + err = snd_pcm_hw_params_any( handle, hwparams ); + if ( err < 0 ) { + fatal = true; + errMessage = QString::fromLatin1("QAudioOutput: snd_pcm_hw_params_any: err = %1").arg(err); + } + if ( !fatal ) { + err = snd_pcm_hw_params_set_rate_resample( handle, hwparams, 1 ); + if ( err < 0 ) { + fatal = true; + errMessage = QString::fromLatin1("QAudioOutput: snd_pcm_hw_params_set_rate_resample: err = %1").arg(err); + } + } + if ( !fatal ) { + err = snd_pcm_hw_params_set_access( handle, hwparams, access ); + if ( err < 0 ) { + fatal = true; + errMessage = QString::fromLatin1("QAudioOutput: snd_pcm_hw_params_set_access: err = %1").arg(err); + } + } + if ( !fatal ) { + err = setFormat(); + if ( err < 0 ) { + fatal = true; + errMessage = QString::fromLatin1("QAudioOutput: snd_pcm_hw_params_set_format: err = %1").arg(err); + } + } + if ( !fatal ) { + err = snd_pcm_hw_params_set_channels( handle, hwparams, (unsigned int)settings.channels() ); + if ( err < 0 ) { + fatal = true; + errMessage = QString::fromLatin1("QAudioOutput: snd_pcm_hw_params_set_channels: err = %1").arg(err); + } + } + if ( !fatal ) { + err = snd_pcm_hw_params_set_rate_near( handle, hwparams, &freakuency, 0 ); + if ( err < 0 ) { + fatal = true; + errMessage = QString::fromLatin1("QAudioOutput: snd_pcm_hw_params_set_rate_near: err = %1").arg(err); + } + } + if ( !fatal ) { + unsigned int maxBufferTime = 0; + unsigned int minBufferTime = 0; + unsigned int maxPeriodTime = 0; + unsigned int minPeriodTime = 0; + + err = snd_pcm_hw_params_get_buffer_time_max(hwparams, &maxBufferTime, &dir); + if ( err >= 0) + err = snd_pcm_hw_params_get_buffer_time_min(hwparams, &minBufferTime, &dir); + if ( err >= 0) + err = snd_pcm_hw_params_get_period_time_max(hwparams, &maxPeriodTime, &dir); + if ( err >= 0) + err = snd_pcm_hw_params_get_period_time_min(hwparams, &minPeriodTime, &dir); + + if ( err < 0 ) { + fatal = true; + errMessage = QString::fromLatin1("QAudioOutput: buffer/period min and max: err = %1").arg(err); + } else { + if (maxBufferTime < buffer_time || buffer_time < minBufferTime || maxPeriodTime < period_time || minPeriodTime > period_time) { +#ifdef DEBUG_AUDIO + qDebug()<<"defaults out of range"; + qDebug()<<"pmin="<<minPeriodTime<<", pmax="<<maxPeriodTime<<", bmin="<<minBufferTime<<", bmax="<<maxBufferTime; +#endif + period_time = minPeriodTime; + if (period_time*4 <= maxBufferTime) { + // Use 4 periods if possible + buffer_time = period_time*4; + chunks = 4; + } else if (period_time*2 <= maxBufferTime) { + // Use 2 periods if possible + buffer_time = period_time*2; + chunks = 2; + } else { + qWarning()<<"QAudioOutput: alsa only supports single period!"; + fatal = true; + } +#ifdef DEBUG_AUDIO + qDebug()<<"used: buffer_time="<<buffer_time<<", period_time="<<period_time; +#endif + } + } + } + if ( !fatal ) { + err = snd_pcm_hw_params_set_buffer_time_near(handle, hwparams, &buffer_time, &dir); + if ( err < 0 ) { + fatal = true; + errMessage = QString::fromLatin1("QAudioOutput: snd_pcm_hw_params_set_buffer_time_near: err = %1").arg(err); + } + } + if ( !fatal ) { + err = snd_pcm_hw_params_set_period_time_near(handle, hwparams, &period_time, &dir); + if ( err < 0 ) { + fatal = true; + errMessage = QString::fromLatin1("QAudioOutput: snd_pcm_hw_params_set_period_time_near: err = %1").arg(err); + } + } + if ( !fatal ) { + err = snd_pcm_hw_params_set_periods_near(handle, hwparams, &chunks, &dir); + if ( err < 0 ) { + fatal = true; + errMessage = QString::fromLatin1("QAudioOutput: snd_pcm_hw_params_set_periods_near: err = %1").arg(err); + } + } + if ( !fatal ) { + err = snd_pcm_hw_params(handle, hwparams); + if ( err < 0 ) { + fatal = true; + errMessage = QString::fromLatin1("QAudioOutput: snd_pcm_hw_params: err = %1").arg(err); + } + } + if( err < 0) { + qWarning()<<errMessage; + errorState = QAudio::OpenError; + emit errorChanged(errorState); + deviceState = QAudio::StoppedState; + return false; + } + snd_pcm_hw_params_get_buffer_size(hwparams,&buffer_frames); + buffer_size = snd_pcm_frames_to_bytes(handle,buffer_frames); + snd_pcm_hw_params_get_period_size(hwparams,&period_frames, &dir); + period_size = snd_pcm_frames_to_bytes(handle,period_frames); + snd_pcm_hw_params_get_buffer_time(hwparams,&buffer_time, &dir); + snd_pcm_hw_params_get_period_time(hwparams,&period_time, &dir); + + // Step 3: Set the desired SW parameters. + snd_pcm_sw_params_t *swparams; + snd_pcm_sw_params_alloca(&swparams); + snd_pcm_sw_params_current(handle, swparams); + snd_pcm_sw_params_set_start_threshold(handle,swparams,period_frames); + snd_pcm_sw_params_set_stop_threshold(handle,swparams,buffer_frames); + snd_pcm_sw_params_set_avail_min(handle, swparams,period_frames); + snd_pcm_sw_params(handle, swparams); + + // Step 4: Prepare audio + if(audioBuffer == 0) + audioBuffer = new char[snd_pcm_frames_to_bytes(handle,buffer_frames)]; + snd_pcm_prepare( handle ); + snd_pcm_start(handle); + + // Step 5: Setup callback and timer fallback + snd_async_add_pcm_handler(&ahandler, handle, async_callback, this); + bytesAvailable = bytesFree(); + + // Step 6: Start audio processing + timer->start(period_time/1000); + + clockStamp.restart(); + timeStamp.restart(); + elapsedTimeOffset = 0; + errorState = QAudio::NoError; + totalTimeValue = 0; + opened = true; + + return true; +} + +void QAudioOutputPrivate::close() +{ + timer->stop(); + + if ( handle ) { + snd_pcm_drain( handle ); + snd_pcm_close( handle ); + handle = 0; + delete [] audioBuffer; + audioBuffer=0; + } + if(!pullMode && audioSource) { + delete audioSource; + audioSource = 0; + } + opened = false; +} + +int QAudioOutputPrivate::bytesFree() const +{ + if(resuming) + return period_size; + + if(deviceState != QAudio::ActiveState && deviceState != QAudio::IdleState) + return 0; + + int frames = snd_pcm_avail_update(handle); + if (frames == -EPIPE) { + // Try and handle buffer underrun + int err = snd_pcm_recover(handle, frames, 0); + if (err < 0) + return 0; + else + frames = snd_pcm_avail_update(handle); + } else if (frames < 0) { + return 0; + } + + if ((int)frames > (int)buffer_frames) + frames = buffer_frames; + + return snd_pcm_frames_to_bytes(handle, frames); +} + +qint64 QAudioOutputPrivate::write( const char *data, qint64 len ) +{ + // Write out some audio data + if ( !handle ) + return 0; +#ifdef DEBUG_AUDIO + qDebug()<<"frames to write out = "<< + snd_pcm_bytes_to_frames( handle, (int)len )<<" ("<<len<<") bytes"; +#endif + int frames, err; + int space = bytesFree(); + if(len < space) { + // Just write it + frames = snd_pcm_bytes_to_frames( handle, (int)len ); + err = snd_pcm_writei( handle, data, frames ); + } else { + // Only write space worth + frames = snd_pcm_bytes_to_frames( handle, (int)space ); + err = snd_pcm_writei( handle, data, frames ); + } + if(err > 0) { + totalTimeValue += err; + resuming = false; + errorState = QAudio::NoError; + if (deviceState != QAudio::ActiveState) { + deviceState = QAudio::ActiveState; + emit stateChanged(deviceState); + } + return snd_pcm_frames_to_bytes( handle, err ); + } else + err = xrun_recovery(err); + + if(err < 0) { + close(); + errorState = QAudio::FatalError; + emit errorChanged(errorState); + deviceState = QAudio::StoppedState; + emit stateChanged(deviceState); + } + return 0; +} + +int QAudioOutputPrivate::periodSize() const +{ + return period_size; +} + +void QAudioOutputPrivate::setBufferSize(int value) +{ + if(deviceState == QAudio::StoppedState) + buffer_size = value; +} + +int QAudioOutputPrivate::bufferSize() const +{ + return buffer_size; +} + +void QAudioOutputPrivate::setNotifyInterval(int ms) +{ + intervalTime = qMax(0, ms); +} + +int QAudioOutputPrivate::notifyInterval() const +{ + return intervalTime; +} + +qint64 QAudioOutputPrivate::processedUSecs() const +{ + return qint64(1000000) * totalTimeValue / settings.frequency(); +} + +void QAudioOutputPrivate::resume() +{ + if(deviceState == QAudio::SuspendedState) { + int err = 0; + + if(handle) { + err = snd_pcm_prepare( handle ); + if(err < 0) + xrun_recovery(err); + + err = snd_pcm_start(handle); + if(err < 0) + xrun_recovery(err); + + bytesAvailable = (int)snd_pcm_frames_to_bytes(handle, buffer_frames); + } + resuming = true; + + deviceState = QAudio::ActiveState; + + errorState = QAudio::NoError; + timer->start(period_time/1000); + emit stateChanged(deviceState); + } +} + +void QAudioOutputPrivate::setFormat(const QAudioFormat& fmt) +{ + if (deviceState == QAudio::StoppedState) + settings = fmt; +} + +QAudioFormat QAudioOutputPrivate::format() const +{ + return settings; +} + +void QAudioOutputPrivate::suspend() +{ + if(deviceState == QAudio::ActiveState || deviceState == QAudio::IdleState || resuming) { + timer->stop(); + deviceState = QAudio::SuspendedState; + errorState = QAudio::NoError; + emit stateChanged(deviceState); + } +} + +void QAudioOutputPrivate::userFeed() +{ + if(deviceState == QAudio::StoppedState || deviceState == QAudio::SuspendedState) + return; +#ifdef DEBUG_AUDIO + QTime now(QTime::currentTime()); + qDebug()<<now.second()<<"s "<<now.msec()<<"ms :userFeed() OUT"; +#endif + if(deviceState == QAudio::IdleState) + bytesAvailable = bytesFree(); + + deviceReady(); +} + +void QAudioOutputPrivate::feedback() +{ + updateAvailable(); +} + + +void QAudioOutputPrivate::updateAvailable() +{ +#ifdef DEBUG_AUDIO + QTime now(QTime::currentTime()); + qDebug()<<now.second()<<"s "<<now.msec()<<"ms :updateAvailable()"; +#endif + bytesAvailable = bytesFree(); +} + +bool QAudioOutputPrivate::deviceReady() +{ + if(pullMode) { + int l = 0; + int chunks = bytesAvailable/period_size; + if(chunks==0) { + bytesAvailable = bytesFree(); + return false; + } +#ifdef DEBUG_AUDIO + qDebug()<<"deviceReady() avail="<<bytesAvailable<<" bytes, period size="<<period_size<<" bytes"; + qDebug()<<"deviceReady() no. of chunks that can fit ="<<chunks<<", chunks in bytes ="<<period_size*chunks; +#endif + int input = period_frames*chunks; + if(input > (int)buffer_frames) + input = buffer_frames; + l = audioSource->read(audioBuffer,snd_pcm_frames_to_bytes(handle, input)); + if(l > 0) { + // Got some data to output + if(deviceState != QAudio::ActiveState) + return true; + qint64 bytesWritten = write(audioBuffer,l); + if (bytesWritten != l) + audioSource->seek(audioSource->pos()-(l-bytesWritten)); + bytesAvailable = bytesFree(); + + } else if(l == 0) { + // Did not get any data to output + bytesAvailable = bytesFree(); + if(bytesAvailable > snd_pcm_frames_to_bytes(handle, buffer_frames-period_frames)) { + // Underrun + if (deviceState != QAudio::IdleState) { + errorState = QAudio::UnderrunError; + emit errorChanged(errorState); + deviceState = QAudio::IdleState; + emit stateChanged(deviceState); + } + } + + } else if(l < 0) { + close(); + deviceState = QAudio::StoppedState; + errorState = QAudio::IOError; + emit errorChanged(errorState); + emit stateChanged(deviceState); + } + } else { + bytesAvailable = bytesFree(); + if(bytesAvailable > snd_pcm_frames_to_bytes(handle, buffer_frames-period_frames)) { + // Underrun + if (deviceState != QAudio::IdleState) { + errorState = QAudio::UnderrunError; + emit errorChanged(errorState); + deviceState = QAudio::IdleState; + emit stateChanged(deviceState); + } + } + } + + if(deviceState != QAudio::ActiveState) + return true; + + if(intervalTime && (timeStamp.elapsed() + elapsedTimeOffset) > intervalTime) { + emit notify(); + elapsedTimeOffset = timeStamp.elapsed() + elapsedTimeOffset - intervalTime; + timeStamp.restart(); + } + return true; +} + +qint64 QAudioOutputPrivate::elapsedUSecs() const +{ + if (deviceState == QAudio::StoppedState) + return 0; + + return clockStamp.elapsed()*1000; +} + +void QAudioOutputPrivate::reset() +{ + if(handle) + snd_pcm_reset(handle); + + stop(); +} + +OutputPrivate::OutputPrivate(QAudioOutputPrivate* audio) +{ + audioDevice = qobject_cast<QAudioOutputPrivate*>(audio); +} + +OutputPrivate::~OutputPrivate() {} + +qint64 OutputPrivate::readData( char* data, qint64 len) +{ + Q_UNUSED(data) + Q_UNUSED(len) + + return 0; +} + +qint64 OutputPrivate::writeData(const char* data, qint64 len) +{ + int retry = 0; + qint64 written = 0; + if((audioDevice->deviceState == QAudio::ActiveState) + ||(audioDevice->deviceState == QAudio::IdleState)) { + while(written < len) { + int chunk = audioDevice->write(data+written,(len-written)); + if(chunk <= 0) + retry++; + written+=chunk; + if(retry > 10) + return written; + } + } + return written; + +} + +QT_END_NAMESPACE + +#include "moc_qaudiooutput_alsa_p.cpp" diff --git a/src/multimedia/audio/qaudiooutput_alsa_p.h b/src/multimedia/audio/qaudiooutput_alsa_p.h new file mode 100644 index 000000000..f914ded2c --- /dev/null +++ b/src/multimedia/audio/qaudiooutput_alsa_p.h @@ -0,0 +1,175 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#ifndef QAUDIOOUTPUTALSA_H +#define QAUDIOOUTPUTALSA_H + +#include <alsa/asoundlib.h> + +#include <QtCore/qfile.h> +#include <QtCore/qdebug.h> +#include <QtCore/qtimer.h> +#include <QtCore/qstring.h> +#include <QtCore/qstringlist.h> +#include <QtCore/qdatetime.h> + +#include "qaudio.h" +#include "qaudiodeviceinfo.h" +#include "qaudiosystem.h" + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + +class OutputPrivate; + +class QAudioOutputPrivate : public QAbstractAudioOutput +{ + friend class OutputPrivate; + Q_OBJECT +public: + QAudioOutputPrivate(const QByteArray &device); + ~QAudioOutputPrivate(); + + qint64 write( const char *data, qint64 len ); + + void start(QIODevice* device); + QIODevice* start(); + void stop(); + void reset(); + void suspend(); + void resume(); + int bytesFree() const; + int periodSize() const; + void setBufferSize(int value); + int bufferSize() const; + void setNotifyInterval(int milliSeconds); + int notifyInterval() const; + qint64 processedUSecs() const; + qint64 elapsedUSecs() const; + QAudio::Error error() const; + QAudio::State state() const; + void setFormat(const QAudioFormat& fmt); + QAudioFormat format() const; + + QIODevice* audioSource; + QAudioFormat settings; + QAudio::Error errorState; + QAudio::State deviceState; + +private slots: + void userFeed(); + void feedback(); + void updateAvailable(); + bool deviceReady(); + +signals: + void processMore(); + +private: + bool opened; + bool pullMode; + bool resuming; + int buffer_size; + int period_size; + int intervalTime; + qint64 totalTimeValue; + unsigned int buffer_time; + unsigned int period_time; + snd_pcm_uframes_t buffer_frames; + snd_pcm_uframes_t period_frames; + static void async_callback(snd_async_handler_t *ahandler); + int xrun_recovery(int err); + + int setFormat(); + bool open(); + void close(); + + QTimer* timer; + QByteArray m_device; + int bytesAvailable; + QTime timeStamp; + QTime clockStamp; + qint64 elapsedTimeOffset; + char* audioBuffer; + snd_pcm_t* handle; + snd_async_handler_t* ahandler; + snd_pcm_access_t access; + snd_pcm_format_t pcmformat; + snd_timestamp_t* timestamp; + snd_pcm_hw_params_t *hwparams; +}; + +class OutputPrivate : public QIODevice +{ + friend class QAudioOutputPrivate; + Q_OBJECT +public: + OutputPrivate(QAudioOutputPrivate* audio); + ~OutputPrivate(); + + qint64 readData( char* data, qint64 len); + qint64 writeData(const char* data, qint64 len); + +private: + QAudioOutputPrivate *audioDevice; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + + +#endif diff --git a/src/multimedia/audio/qaudiooutput_mac_p.cpp b/src/multimedia/audio/qaudiooutput_mac_p.cpp new file mode 100644 index 000000000..5e0c1cb07 --- /dev/null +++ b/src/multimedia/audio/qaudiooutput_mac_p.cpp @@ -0,0 +1,734 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// INTERNAL USE ONLY: Do NOT use for any other purpose. +// + +#include <CoreServices/CoreServices.h> +#include <CoreAudio/CoreAudio.h> +#include <AudioUnit/AudioUnit.h> +#include <AudioToolbox/AudioToolbox.h> + +#include <QtCore/qendian.h> +#include <QtCore/qbuffer.h> +#include <QtCore/qtimer.h> +#include <QtCore/qdebug.h> + +#include <qaudiooutput.h> + +#include "qaudio_mac_p.h" +#include "qaudiooutput_mac_p.h" +#include "qaudiodeviceinfo_mac_p.h" + + +QT_BEGIN_NAMESPACE + + +namespace QtMultimediaInternal +{ + +static const int default_buffer_size = 8 * 1024; + + +class QAudioOutputBuffer : public QObject +{ + Q_OBJECT + +public: + QAudioOutputBuffer(int bufferSize, int maxPeriodSize, QAudioFormat const& audioFormat): + m_deviceError(false), + m_maxPeriodSize(maxPeriodSize), + m_device(0) + { + m_buffer = new QAudioRingBuffer(bufferSize + (bufferSize % maxPeriodSize == 0 ? 0 : maxPeriodSize - (bufferSize % maxPeriodSize))); + m_bytesPerFrame = (audioFormat.sampleSize() / 8) * audioFormat.channels(); + m_periodTime = m_maxPeriodSize / m_bytesPerFrame * 1000 / audioFormat.frequency(); + + m_fillTimer = new QTimer(this); + connect(m_fillTimer, SIGNAL(timeout()), SLOT(fillBuffer())); + } + + ~QAudioOutputBuffer() + { + delete m_buffer; + } + + qint64 readFrames(char* data, qint64 maxFrames) + { + bool wecan = true; + qint64 framesRead = 0; + + while (wecan && framesRead < maxFrames) { + QAudioRingBuffer::Region region = m_buffer->acquireReadRegion((maxFrames - framesRead) * m_bytesPerFrame); + + if (region.second > 0) { + // Ensure that we only read whole frames. + region.second -= region.second % m_bytesPerFrame; + + if (region.second > 0) { + memcpy(data + (framesRead * m_bytesPerFrame), region.first, region.second); + framesRead += region.second / m_bytesPerFrame; + } else + wecan = false; // If there is only a partial frame left we should exit. + } + else + wecan = false; + + m_buffer->releaseReadRegion(region); + } + + if (framesRead == 0 && m_deviceError) + framesRead = -1; + + return framesRead; + } + + qint64 writeBytes(const char* data, qint64 maxSize) + { + bool wecan = true; + qint64 bytesWritten = 0; + + maxSize -= maxSize % m_bytesPerFrame; + while (wecan && bytesWritten < maxSize) { + QAudioRingBuffer::Region region = m_buffer->acquireWriteRegion(maxSize - bytesWritten); + + if (region.second > 0) { + memcpy(region.first, data + bytesWritten, region.second); + bytesWritten += region.second; + } + else + wecan = false; + + m_buffer->releaseWriteRegion(region); + } + + if (bytesWritten > 0) + emit readyRead(); + + return bytesWritten; + } + + int available() const + { + return m_buffer->free(); + } + + void reset() + { + m_buffer->reset(); + m_device = 0; + m_deviceError = false; + } + + void setPrefetchDevice(QIODevice* device) + { + if (m_device != device) { + m_device = device; + if (m_device != 0) + fillBuffer(); + } + } + + void startFillTimer() + { + if (m_device != 0) + m_fillTimer->start(m_buffer->size() / 2 / m_maxPeriodSize * m_periodTime); + } + + void stopFillTimer() + { + m_fillTimer->stop(); + } + +signals: + void readyRead(); + +private slots: + void fillBuffer() + { + const int free = m_buffer->free(); + const int writeSize = free - (free % m_maxPeriodSize); + + if (writeSize > 0) { + bool wecan = true; + int filled = 0; + + while (!m_deviceError && wecan && filled < writeSize) { + QAudioRingBuffer::Region region = m_buffer->acquireWriteRegion(writeSize - filled); + + if (region.second > 0) { + region.second = m_device->read(region.first, region.second); + if (region.second > 0) + filled += region.second; + else if (region.second == 0) + wecan = false; + else if (region.second < 0) { + m_fillTimer->stop(); + region.second = 0; + m_deviceError = true; + } + } + else + wecan = false; + + m_buffer->releaseWriteRegion(region); + } + + if (filled > 0) + emit readyRead(); + } + } + +private: + bool m_deviceError; + int m_maxPeriodSize; + int m_bytesPerFrame; + int m_periodTime; + QIODevice* m_device; + QTimer* m_fillTimer; + QAudioRingBuffer* m_buffer; +}; + + +} + +class MacOutputDevice : public QIODevice +{ + Q_OBJECT + +public: + MacOutputDevice(QtMultimediaInternal::QAudioOutputBuffer* audioBuffer, QObject* parent): + QIODevice(parent), + m_audioBuffer(audioBuffer) + { + open(QIODevice::WriteOnly | QIODevice::Unbuffered); + } + + qint64 readData(char* data, qint64 len) + { + Q_UNUSED(data); + Q_UNUSED(len); + + return 0; + } + + qint64 writeData(const char* data, qint64 len) + { + return m_audioBuffer->writeBytes(data, len); + } + + bool isSequential() const + { + return true; + } + +private: + QtMultimediaInternal::QAudioOutputBuffer* m_audioBuffer; +}; + + +QAudioOutputPrivate::QAudioOutputPrivate(const QByteArray& device) +{ + QDataStream ds(device); + quint32 did, mode; + + ds >> did >> mode; + + if (QAudio::Mode(mode) == QAudio::AudioInput) + errorCode = QAudio::OpenError; + else { + audioDeviceInfo = new QAudioDeviceInfoInternal(device, QAudio::AudioOutput); + isOpen = false; + audioDeviceId = AudioDeviceID(did); + audioUnit = 0; + audioIO = 0; + startTime = 0; + totalFrames = 0; + audioBuffer = 0; + internalBufferSize = QtMultimediaInternal::default_buffer_size; + clockFrequency = AudioGetHostClockFrequency() / 1000; + errorCode = QAudio::NoError; + stateCode = QAudio::StoppedState; + audioThreadState = Stopped; + + intervalTimer = new QTimer(this); + intervalTimer->setInterval(1000); + connect(intervalTimer, SIGNAL(timeout()), SIGNAL(notify())); + } +} + +QAudioOutputPrivate::~QAudioOutputPrivate() +{ + delete audioDeviceInfo; + close(); +} + +bool QAudioOutputPrivate::open() +{ + if (errorCode != QAudio::NoError) + return false; + + if (isOpen) + return true; + + ComponentDescription cd; + cd.componentType = kAudioUnitType_Output; + cd.componentSubType = kAudioUnitSubType_HALOutput; + cd.componentManufacturer = kAudioUnitManufacturer_Apple; + cd.componentFlags = 0; + cd.componentFlagsMask = 0; + + // Open + Component cp = FindNextComponent(NULL, &cd); + if (cp == 0) { + qWarning() << "QAudioOutput: Failed to find HAL Output component"; + return false; + } + + if (OpenAComponent(cp, &audioUnit) != noErr) { + qWarning() << "QAudioOutput: Unable to Open Output Component"; + return false; + } + + // register callback + AURenderCallbackStruct cb; + cb.inputProc = renderCallback; + cb.inputProcRefCon = this; + + if (AudioUnitSetProperty(audioUnit, + kAudioUnitProperty_SetRenderCallback, + kAudioUnitScope_Global, + 0, + &cb, + sizeof(cb)) != noErr) { + qWarning() << "QAudioOutput: Failed to set AudioUnit callback"; + return false; + } + + // Set Audio Device + if (AudioUnitSetProperty(audioUnit, + kAudioOutputUnitProperty_CurrentDevice, + kAudioUnitScope_Global, + 0, + &audioDeviceId, + sizeof(audioDeviceId)) != noErr) { + qWarning() << "QAudioOutput: Unable to use configured device"; + return false; + } + + // Set stream format + streamFormat = toAudioStreamBasicDescription(audioFormat); + + UInt32 size = sizeof(streamFormat); + if (AudioUnitSetProperty(audioUnit, + kAudioUnitProperty_StreamFormat, + kAudioUnitScope_Input, + 0, + &streamFormat, + sizeof(streamFormat)) != noErr) { + qWarning() << "QAudioOutput: Unable to Set Stream information"; + return false; + } + + // Allocate buffer + UInt32 numberOfFrames = 0; + size = sizeof(UInt32); + if (AudioUnitGetProperty(audioUnit, + kAudioDevicePropertyBufferFrameSize, + kAudioUnitScope_Global, + 0, + &numberOfFrames, + &size) != noErr) { + qWarning() << "QAudioInput: Failed to get audio period size"; + return false; + } + + periodSizeBytes = numberOfFrames * streamFormat.mBytesPerFrame; + if (internalBufferSize < periodSizeBytes * 2) + internalBufferSize = periodSizeBytes * 2; + else + internalBufferSize -= internalBufferSize % streamFormat.mBytesPerFrame; + + audioBuffer = new QtMultimediaInternal::QAudioOutputBuffer(internalBufferSize, periodSizeBytes, audioFormat); + connect(audioBuffer, SIGNAL(readyRead()), SLOT(inputReady())); // Pull + + audioIO = new MacOutputDevice(audioBuffer, this); + + // Init + if (AudioUnitInitialize(audioUnit)) { + qWarning() << "QAudioOutput: Failed to initialize AudioUnit"; + return false; + } + + isOpen = true; + + return true; +} + +void QAudioOutputPrivate::close() +{ + if (audioUnit != 0) { + AudioOutputUnitStop(audioUnit); + AudioUnitUninitialize(audioUnit); + CloseComponent(audioUnit); + } + + delete audioBuffer; +} + +QAudioFormat QAudioOutputPrivate::format() const +{ + return audioFormat; +} + +void QAudioOutputPrivate::setFormat(const QAudioFormat& fmt) +{ + if (stateCode == QAudio::StoppedState) + audioFormat = fmt; +} + +void QAudioOutputPrivate::start(QIODevice* device) +{ + QIODevice* op = device; + + if (!audioDeviceInfo->isFormatSupported(audioFormat) || !open()) { + stateCode = QAudio::StoppedState; + errorCode = QAudio::OpenError; + } + + reset(); + audioBuffer->reset(); + audioBuffer->setPrefetchDevice(op); + + if (op == 0) { + op = audioIO; + stateCode = QAudio::IdleState; + } + else + stateCode = QAudio::ActiveState; + + // Start + errorCode = QAudio::NoError; + totalFrames = 0; + startTime = AudioGetCurrentHostTime(); + + if (stateCode == QAudio::ActiveState) + audioThreadStart(); + + emit stateChanged(stateCode); +} + +QIODevice* QAudioOutputPrivate::start() +{ + if (!audioDeviceInfo->isFormatSupported(audioFormat) || !open()) { + stateCode = QAudio::StoppedState; + errorCode = QAudio::OpenError; + return audioIO; + } + + reset(); + audioBuffer->reset(); + audioBuffer->setPrefetchDevice(0); + + stateCode = QAudio::IdleState; + + // Start + errorCode = QAudio::NoError; + totalFrames = 0; + startTime = AudioGetCurrentHostTime(); + + emit stateChanged(stateCode); + + return audioIO; +} + +void QAudioOutputPrivate::stop() +{ + QMutexLocker lock(&mutex); + if (stateCode != QAudio::StoppedState) { + audioThreadDrain(); + + stateCode = QAudio::StoppedState; + errorCode = QAudio::NoError; + QMetaObject::invokeMethod(this, "stateChanged", Qt::QueuedConnection, Q_ARG(QAudio::State, stateCode)); + } +} + +void QAudioOutputPrivate::reset() +{ + QMutexLocker lock(&mutex); + if (stateCode != QAudio::StoppedState) { + audioThreadStop(); + + stateCode = QAudio::StoppedState; + errorCode = QAudio::NoError; + QMetaObject::invokeMethod(this, "stateChanged", Qt::QueuedConnection, Q_ARG(QAudio::State, stateCode)); + } +} + +void QAudioOutputPrivate::suspend() +{ + QMutexLocker lock(&mutex); + if (stateCode == QAudio::ActiveState || stateCode == QAudio::IdleState) { + audioThreadStop(); + + stateCode = QAudio::SuspendedState; + errorCode = QAudio::NoError; + QMetaObject::invokeMethod(this, "stateChanged", Qt::QueuedConnection, Q_ARG(QAudio::State, stateCode)); + } +} + +void QAudioOutputPrivate::resume() +{ + QMutexLocker lock(&mutex); + if (stateCode == QAudio::SuspendedState) { + audioThreadStart(); + + stateCode = QAudio::ActiveState; + errorCode = QAudio::NoError; + QMetaObject::invokeMethod(this, "stateChanged", Qt::QueuedConnection, Q_ARG(QAudio::State, stateCode)); + } +} + +int QAudioOutputPrivate::bytesFree() const +{ + return audioBuffer->available(); +} + +int QAudioOutputPrivate::periodSize() const +{ + return periodSizeBytes; +} + +void QAudioOutputPrivate::setBufferSize(int bs) +{ + if (stateCode == QAudio::StoppedState) + internalBufferSize = bs; +} + +int QAudioOutputPrivate::bufferSize() const +{ + return internalBufferSize; +} + +void QAudioOutputPrivate::setNotifyInterval(int milliSeconds) +{ + if (intervalTimer->interval() == milliSeconds) + return; + + if (milliSeconds <= 0) + milliSeconds = 0; + + intervalTimer->setInterval(milliSeconds); +} + +int QAudioOutputPrivate::notifyInterval() const +{ + return intervalTimer->interval(); +} + +qint64 QAudioOutputPrivate::processedUSecs() const +{ + return totalFrames * 1000000 / audioFormat.frequency(); +} + +qint64 QAudioOutputPrivate::elapsedUSecs() const +{ + if (stateCode == QAudio::StoppedState) + return 0; + + return (AudioGetCurrentHostTime() - startTime) / (clockFrequency / 1000); +} + +QAudio::Error QAudioOutputPrivate::error() const +{ + return errorCode; +} + +QAudio::State QAudioOutputPrivate::state() const +{ + return stateCode; +} + +void QAudioOutputPrivate::audioThreadStart() +{ + startTimers(); + audioThreadState = Running; + AudioOutputUnitStart(audioUnit); +} + +void QAudioOutputPrivate::audioThreadStop() +{ + stopTimers(); + if (audioThreadState.testAndSetAcquire(Running, Stopped)) + threadFinished.wait(&mutex); +} + +void QAudioOutputPrivate::audioThreadDrain() +{ + stopTimers(); + if (audioThreadState.testAndSetAcquire(Running, Draining)) + threadFinished.wait(&mutex); +} + +void QAudioOutputPrivate::audioDeviceStop() +{ + AudioOutputUnitStop(audioUnit); + audioThreadState = Stopped; + threadFinished.wakeOne(); +} + +void QAudioOutputPrivate::audioDeviceIdle() +{ + QMutexLocker lock(&mutex); + if (stateCode == QAudio::ActiveState) { + audioDeviceStop(); + + errorCode = QAudio::UnderrunError; + stateCode = QAudio::IdleState; + QMetaObject::invokeMethod(this, "deviceStopped", Qt::QueuedConnection); + } +} + +void QAudioOutputPrivate::audioDeviceError() +{ + QMutexLocker lock(&mutex); + if (stateCode == QAudio::ActiveState) { + audioDeviceStop(); + + errorCode = QAudio::IOError; + stateCode = QAudio::StoppedState; + QMetaObject::invokeMethod(this, "deviceStopped", Qt::QueuedConnection); + } +} + +void QAudioOutputPrivate::startTimers() +{ + audioBuffer->startFillTimer(); + if (intervalTimer->interval() > 0) + intervalTimer->start(); +} + +void QAudioOutputPrivate::stopTimers() +{ + audioBuffer->stopFillTimer(); + intervalTimer->stop(); +} + + +void QAudioOutputPrivate::deviceStopped() +{ + intervalTimer->stop(); + emit stateChanged(stateCode); +} + +void QAudioOutputPrivate::inputReady() +{ + QMutexLocker lock(&mutex); + if (stateCode == QAudio::IdleState) { + audioThreadStart(); + + stateCode = QAudio::ActiveState; + errorCode = QAudio::NoError; + + QMetaObject::invokeMethod(this, "stateChanged", Qt::QueuedConnection, Q_ARG(QAudio::State, stateCode)); + } +} + + +OSStatus QAudioOutputPrivate::renderCallback(void* inRefCon, + AudioUnitRenderActionFlags* ioActionFlags, + const AudioTimeStamp* inTimeStamp, + UInt32 inBusNumber, + UInt32 inNumberFrames, + AudioBufferList* ioData) +{ + Q_UNUSED(ioActionFlags) + Q_UNUSED(inTimeStamp) + Q_UNUSED(inBusNumber) + Q_UNUSED(inNumberFrames) + + QAudioOutputPrivate* d = static_cast<QAudioOutputPrivate*>(inRefCon); + + const int threadState = d->audioThreadState.fetchAndAddAcquire(0); + if (threadState == Stopped) { + ioData->mBuffers[0].mDataByteSize = 0; + d->audioDeviceStop(); + } + else { + const UInt32 bytesPerFrame = d->streamFormat.mBytesPerFrame; + qint64 framesRead; + + framesRead = d->audioBuffer->readFrames((char*)ioData->mBuffers[0].mData, + ioData->mBuffers[0].mDataByteSize / bytesPerFrame); + + if (framesRead > 0) { + ioData->mBuffers[0].mDataByteSize = framesRead * bytesPerFrame; + d->totalFrames += framesRead; + } + else { + ioData->mBuffers[0].mDataByteSize = 0; + if (framesRead == 0) { + if (threadState == Draining) + d->audioDeviceStop(); + else + d->audioDeviceIdle(); + } + else + d->audioDeviceError(); + } + } + + return noErr; +} + + +QT_END_NAMESPACE + +#include "qaudiooutput_mac_p.moc" diff --git a/src/multimedia/audio/qaudiooutput_mac_p.h b/src/multimedia/audio/qaudiooutput_mac_p.h new file mode 100644 index 000000000..ded618cbb --- /dev/null +++ b/src/multimedia/audio/qaudiooutput_mac_p.h @@ -0,0 +1,174 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#ifndef QAUDIOOUTPUT_MAC_P_H +#define QAUDIOOUTPUT_MAC_P_H + +#include <CoreServices/CoreServices.h> +#include <CoreAudio/CoreAudio.h> +#include <AudioUnit/AudioUnit.h> +#include <AudioToolbox/AudioToolbox.h> + +#include <QtCore/qobject.h> +#include <QtCore/qmutex.h> +#include <QtCore/qwaitcondition.h> +#include <QtCore/qtimer.h> +#include <QtCore/qatomic.h> + +#include <qaudio.h> +#include <qaudioformat.h> +#include <qaudiosystem.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + +class QIODevice; +class QAbstractAudioDeviceInfo; + +namespace QtMultimediaInternal +{ +class QAudioOutputBuffer; +} + +class QAudioOutputPrivate : public QAbstractAudioOutput +{ + Q_OBJECT + +public: + bool isOpen; + int internalBufferSize; + int periodSizeBytes; + qint64 totalFrames; + QAudioFormat audioFormat; + QIODevice* audioIO; + AudioDeviceID audioDeviceId; + AudioUnit audioUnit; + Float64 clockFrequency; + UInt64 startTime; + AudioStreamBasicDescription deviceFormat; + AudioStreamBasicDescription streamFormat; + QtMultimediaInternal::QAudioOutputBuffer* audioBuffer; + QAtomicInt audioThreadState; + QWaitCondition threadFinished; + QMutex mutex; + QTimer* intervalTimer; + QAbstractAudioDeviceInfo *audioDeviceInfo; + + QAudio::Error errorCode; + QAudio::State stateCode; + + QAudioOutputPrivate(const QByteArray& device); + ~QAudioOutputPrivate(); + + bool open(); + void close(); + + QAudioFormat format() const; + void setFormat(const QAudioFormat& fmt); + + QIODevice* start(); + void start(QIODevice* device); + void stop(); + void reset(); + void suspend(); + void resume(); + + int bytesFree() const; + int periodSize() const; + + void setBufferSize(int value); + int bufferSize() const; + + void setNotifyInterval(int milliSeconds); + int notifyInterval() const; + + qint64 processedUSecs() const; + qint64 elapsedUSecs() const; + + QAudio::Error error() const; + QAudio::State state() const; + + void audioThreadStart(); + void audioThreadStop(); + void audioThreadDrain(); + + void audioDeviceStop(); + void audioDeviceIdle(); + void audioDeviceError(); + + void startTimers(); + void stopTimers(); + +private slots: + void deviceStopped(); + void inputReady(); + +private: + enum { Running, Draining, Stopped }; + + static OSStatus renderCallback(void* inRefCon, + AudioUnitRenderActionFlags* ioActionFlags, + const AudioTimeStamp* inTimeStamp, + UInt32 inBusNumber, + UInt32 inNumberFrames, + AudioBufferList* ioData); +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/multimedia/audio/qaudiooutput_win32_p.cpp b/src/multimedia/audio/qaudiooutput_win32_p.cpp new file mode 100644 index 000000000..d5b31a30f --- /dev/null +++ b/src/multimedia/audio/qaudiooutput_win32_p.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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// INTERNAL USE ONLY: Do NOT use for any other purpose. +// + +#include "qaudiooutput_win32_p.h" + +#ifndef SPEAKER_FRONT_LEFT + #define SPEAKER_FRONT_LEFT 0x00000001 + #define SPEAKER_FRONT_RIGHT 0x00000002 + #define SPEAKER_FRONT_CENTER 0x00000004 + #define SPEAKER_LOW_FREQUENCY 0x00000008 + #define SPEAKER_BACK_LEFT 0x00000010 + #define SPEAKER_BACK_RIGHT 0x00000020 + #define SPEAKER_FRONT_LEFT_OF_CENTER 0x00000040 + #define SPEAKER_FRONT_RIGHT_OF_CENTER 0x00000080 + #define SPEAKER_BACK_CENTER 0x00000100 + #define SPEAKER_SIDE_LEFT 0x00000200 + #define SPEAKER_SIDE_RIGHT 0x00000400 + #define SPEAKER_TOP_CENTER 0x00000800 + #define SPEAKER_TOP_FRONT_LEFT 0x00001000 + #define SPEAKER_TOP_FRONT_CENTER 0x00002000 + #define SPEAKER_TOP_FRONT_RIGHT 0x00004000 + #define SPEAKER_TOP_BACK_LEFT 0x00008000 + #define SPEAKER_TOP_BACK_CENTER 0x00010000 + #define SPEAKER_TOP_BACK_RIGHT 0x00020000 + #define SPEAKER_RESERVED 0x7FFC0000 + #define SPEAKER_ALL 0x80000000 +#endif + +#ifndef _WAVEFORMATEXTENSIBLE_ + + #define _WAVEFORMATEXTENSIBLE_ + typedef struct + { + WAVEFORMATEX Format; // Base WAVEFORMATEX data + union + { + WORD wValidBitsPerSample; // Valid bits in each sample container + WORD wSamplesPerBlock; // Samples per block of audio data; valid + // if wBitsPerSample=0 (but rarely used). + WORD wReserved; // Zero if neither case above applies. + } Samples; + DWORD dwChannelMask; // Positions of the audio channels + GUID SubFormat; // Format identifier GUID + } WAVEFORMATEXTENSIBLE, *PWAVEFORMATEXTENSIBLE, *LPPWAVEFORMATEXTENSIBLE; + typedef const WAVEFORMATEXTENSIBLE* LPCWAVEFORMATEXTENSIBLE; + +#endif + +#if !defined(WAVE_FORMAT_EXTENSIBLE) +#define WAVE_FORMAT_EXTENSIBLE 0xFFFE +#endif + +//#define DEBUG_AUDIO 1 + +QT_BEGIN_NAMESPACE + +QAudioOutputPrivate::QAudioOutputPrivate(const QByteArray &device) +{ + bytesAvailable = 0; + buffer_size = 0; + period_size = 0; + m_device = device; + totalTimeValue = 0; + intervalTime = 1000; + audioBuffer = 0; + errorState = QAudio::NoError; + deviceState = QAudio::StoppedState; + audioSource = 0; + pullMode = true; + finished = false; +} + +QAudioOutputPrivate::~QAudioOutputPrivate() +{ + mutex.lock(); + finished = true; + mutex.unlock(); + + close(); +} + +void CALLBACK QAudioOutputPrivate::waveOutProc( HWAVEOUT hWaveOut, UINT uMsg, + DWORD dwInstance, DWORD dwParam1, DWORD dwParam2 ) +{ + Q_UNUSED(dwParam1) + Q_UNUSED(dwParam2) + Q_UNUSED(hWaveOut) + + QAudioOutputPrivate* qAudio; + qAudio = (QAudioOutputPrivate*)(dwInstance); + if(!qAudio) + return; + + QMutexLocker(&qAudio->mutex); + + switch(uMsg) { + case WOM_OPEN: + qAudio->feedback(); + break; + case WOM_CLOSE: + return; + case WOM_DONE: + if(qAudio->finished || qAudio->buffer_size == 0 || qAudio->period_size == 0) { + return; + } + qAudio->waveFreeBlockCount++; + if(qAudio->waveFreeBlockCount >= qAudio->buffer_size/qAudio->period_size) + qAudio->waveFreeBlockCount = qAudio->buffer_size/qAudio->period_size; + qAudio->feedback(); + break; + default: + return; + } +} + +WAVEHDR* QAudioOutputPrivate::allocateBlocks(int size, int count) +{ + int i; + unsigned char* buffer; + WAVEHDR* blocks; + DWORD totalBufferSize = (size + sizeof(WAVEHDR))*count; + + if((buffer=(unsigned char*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, + totalBufferSize)) == 0) { + qWarning("QAudioOutput: Memory allocation error"); + return 0; + } + blocks = (WAVEHDR*)buffer; + buffer += sizeof(WAVEHDR)*count; + for(i = 0; i < count; i++) { + blocks[i].dwBufferLength = size; + blocks[i].lpData = (LPSTR)buffer; + buffer += size; + } + return blocks; +} + +void QAudioOutputPrivate::freeBlocks(WAVEHDR* blockArray) +{ + WAVEHDR* blocks = blockArray; + + int count = buffer_size/period_size; + + for(int i = 0; i < count; i++) { + waveOutUnprepareHeader(hWaveOut,blocks, sizeof(WAVEHDR)); + blocks++; + } + HeapFree(GetProcessHeap(), 0, blockArray); +} + +QAudioFormat QAudioOutputPrivate::format() const +{ + return settings; +} + +void QAudioOutputPrivate::setFormat(const QAudioFormat& fmt) +{ + if (deviceState == QAudio::StoppedState) + settings = fmt; +} + +void QAudioOutputPrivate::start(QIODevice* device) +{ + if(deviceState != QAudio::StoppedState) + close(); + + if(!pullMode && audioSource) + delete audioSource; + + pullMode = true; + audioSource = device; + + deviceState = QAudio::ActiveState; + + if(!open()) + return; + + emit stateChanged(deviceState); +} + +QIODevice* QAudioOutputPrivate::start() +{ + if(deviceState != QAudio::StoppedState) + close(); + + if(!pullMode && audioSource) + delete audioSource; + + pullMode = false; + audioSource = new OutputPrivate(this); + audioSource->open(QIODevice::WriteOnly|QIODevice::Unbuffered); + + deviceState = QAudio::IdleState; + + if(!open()) + return 0; + + emit stateChanged(deviceState); + + return audioSource; +} + +void QAudioOutputPrivate::stop() +{ + if(deviceState == QAudio::StoppedState) + return; + close(); + if(!pullMode && audioSource) { + delete audioSource; + audioSource = 0; + } + emit stateChanged(deviceState); +} + +bool QAudioOutputPrivate::open() +{ +#ifdef DEBUG_AUDIO + QTime now(QTime::currentTime()); + qDebug()<<now.second()<<"s "<<now.msec()<<"ms :open()"; +#endif + + period_size = 0; + + if (!settings.isValid()) { + qWarning("QAudioOutput: open error, invalid format."); + } else if (settings.channelCount() <= 0) { + qWarning("QAudioOutput: open error, invalid number of channels (%d).", + settings.channelCount()); + } else if (settings.sampleSize() <= 0) { + qWarning("QAudioOutput: open error, invalid sample size (%d).", + settings.sampleSize()); + } else if (settings.frequency() < 8000 || settings.frequency() > 96000) { + qWarning("QAudioOutput: open error, frequency out of range (%d).", settings.frequency()); + } else if (buffer_size == 0) { + // Default buffer size, 200ms, default period size is 40ms + buffer_size + = (settings.frequency() + * settings.channelCount() + * settings.sampleSize() + + 39) / 40; + period_size = buffer_size / 5; + } else { + period_size = buffer_size / 5; + } + + if (period_size == 0) { + errorState = QAudio::OpenError; + deviceState = QAudio::StoppedState; + emit stateChanged(deviceState); + return false; + } + + waveBlocks = allocateBlocks(period_size, buffer_size/period_size); + + mutex.lock(); + waveFreeBlockCount = buffer_size/period_size; + mutex.unlock(); + + waveCurrentBlock = 0; + + if(audioBuffer == 0) + audioBuffer = new char[buffer_size]; + + timeStamp.restart(); + elapsedTimeOffset = 0; + + wfx.nSamplesPerSec = settings.frequency(); + wfx.wBitsPerSample = settings.sampleSize(); + wfx.nChannels = settings.channels(); + wfx.cbSize = 0; + + bool surround = false; + + if (settings.channels() > 2) + surround = true; + + wfx.wFormatTag = WAVE_FORMAT_PCM; + wfx.nBlockAlign = (wfx.wBitsPerSample >> 3) * wfx.nChannels; + wfx.nAvgBytesPerSec = wfx.nBlockAlign * wfx.nSamplesPerSec; + + QDataStream ds(&m_device, QIODevice::ReadOnly); + quint32 deviceId; + ds >> deviceId; + + if (!surround) { + if (waveOutOpen(&hWaveOut, UINT_PTR(deviceId), &wfx, + (DWORD_PTR)&waveOutProc, + (DWORD_PTR) this, + CALLBACK_FUNCTION) != MMSYSERR_NOERROR) { + errorState = QAudio::OpenError; + deviceState = QAudio::StoppedState; + emit stateChanged(deviceState); + qWarning("QAudioOutput: open error"); + return false; + } + } else { + WAVEFORMATEXTENSIBLE wfex; + wfex.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; + wfex.Format.nChannels = settings.channels(); + wfex.Format.wBitsPerSample = settings.sampleSize(); + wfex.Format.nSamplesPerSec = settings.frequency(); + wfex.Format.nBlockAlign = wfex.Format.nChannels*wfex.Format.wBitsPerSample/8; + wfex.Format.nAvgBytesPerSec=wfex.Format.nSamplesPerSec*wfex.Format.nBlockAlign; + wfex.Samples.wValidBitsPerSample=wfex.Format.wBitsPerSample; + static const GUID _KSDATAFORMAT_SUBTYPE_PCM = { + 0x00000001, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}}; + wfex.SubFormat=_KSDATAFORMAT_SUBTYPE_PCM; + wfex.Format.cbSize=22; + + wfex.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT; + if (settings.channels() >= 4) + wfex.dwChannelMask |= SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT; + if (settings.channels() >= 6) + wfex.dwChannelMask |= SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY; + if (settings.channels() == 8) + wfex.dwChannelMask |= SPEAKER_SIDE_LEFT | SPEAKER_SIDE_RIGHT; + + if (waveOutOpen(&hWaveOut, UINT_PTR(deviceId), &wfex.Format, + (DWORD_PTR)&waveOutProc, + (DWORD_PTR) this, + CALLBACK_FUNCTION) != MMSYSERR_NOERROR) { + errorState = QAudio::OpenError; + deviceState = QAudio::StoppedState; + emit stateChanged(deviceState); + qWarning("QAudioOutput: open error"); + return false; + } + } + + totalTimeValue = 0; + timeStampOpened.restart(); + elapsedTimeOffset = 0; + + errorState = QAudio::NoError; + if(pullMode) { + deviceState = QAudio::ActiveState; + QTimer::singleShot(10, this, SLOT(feedback())); + } else + deviceState = QAudio::IdleState; + + return true; +} + +void QAudioOutputPrivate::close() +{ + if(deviceState == QAudio::StoppedState) + return; + + deviceState = QAudio::StoppedState; + errorState = QAudio::NoError; + int delay = (buffer_size-bytesFree())*1000/(settings.frequency() + *settings.channels()*(settings.sampleSize()/8)); + waveOutReset(hWaveOut); + Sleep(delay+10); + + freeBlocks(waveBlocks); + waveOutClose(hWaveOut); + delete [] audioBuffer; + audioBuffer = 0; + buffer_size = 0; +} + +int QAudioOutputPrivate::bytesFree() const +{ + int buf; + buf = waveFreeBlockCount*period_size; + + return buf; +} + +int QAudioOutputPrivate::periodSize() const +{ + return period_size; +} + +void QAudioOutputPrivate::setBufferSize(int value) +{ + if(deviceState == QAudio::StoppedState) + buffer_size = value; +} + +int QAudioOutputPrivate::bufferSize() const +{ + return buffer_size; +} + +void QAudioOutputPrivate::setNotifyInterval(int ms) +{ + intervalTime = qMax(0, ms); +} + +int QAudioOutputPrivate::notifyInterval() const +{ + return intervalTime; +} + +qint64 QAudioOutputPrivate::processedUSecs() const +{ + if (deviceState == QAudio::StoppedState) + return 0; + qint64 result = qint64(1000000) * totalTimeValue / + (settings.channels()*(settings.sampleSize()/8)) / + settings.frequency(); + + return result; +} + +qint64 QAudioOutputPrivate::write( const char *data, qint64 len ) +{ + // Write out some audio data + if (deviceState != QAudio::ActiveState && deviceState != QAudio::IdleState) + return 0; + + char* p = (char*)data; + int l = (int)len; + + WAVEHDR* current; + int remain; + current = &waveBlocks[waveCurrentBlock]; + while(l > 0) { + mutex.lock(); + if(waveFreeBlockCount==0) { + mutex.unlock(); + break; + } + mutex.unlock(); + + if(current->dwFlags & WHDR_PREPARED) + waveOutUnprepareHeader(hWaveOut, current, sizeof(WAVEHDR)); + + if(l < period_size) + remain = l; + else + remain = period_size; + memcpy(current->lpData, p, remain); + + l -= remain; + p += remain; + current->dwBufferLength = remain; + waveOutPrepareHeader(hWaveOut, current, sizeof(WAVEHDR)); + waveOutWrite(hWaveOut, current, sizeof(WAVEHDR)); + + mutex.lock(); + waveFreeBlockCount--; +#ifdef DEBUG_AUDIO + qDebug("write out l=%d, waveFreeBlockCount=%d", + current->dwBufferLength,waveFreeBlockCount); +#endif + mutex.unlock(); + + totalTimeValue += current->dwBufferLength; + waveCurrentBlock++; + waveCurrentBlock %= buffer_size/period_size; + current = &waveBlocks[waveCurrentBlock]; + current->dwUser = 0; + errorState = QAudio::NoError; + if (deviceState != QAudio::ActiveState) { + deviceState = QAudio::ActiveState; + emit stateChanged(deviceState); + } + } + return (len-l); +} + +void QAudioOutputPrivate::resume() +{ + if(deviceState == QAudio::SuspendedState) { + deviceState = QAudio::ActiveState; + errorState = QAudio::NoError; + waveOutRestart(hWaveOut); + QTimer::singleShot(10, this, SLOT(feedback())); + emit stateChanged(deviceState); + } +} + +void QAudioOutputPrivate::suspend() +{ + if(deviceState == QAudio::ActiveState || deviceState == QAudio::IdleState) { + int delay = (buffer_size-bytesFree())*1000/(settings.frequency() + *settings.channels()*(settings.sampleSize()/8)); + waveOutPause(hWaveOut); + Sleep(delay+10); + deviceState = QAudio::SuspendedState; + errorState = QAudio::NoError; + emit stateChanged(deviceState); + } +} + +void QAudioOutputPrivate::feedback() +{ +#ifdef DEBUG_AUDIO + QTime now(QTime::currentTime()); + qDebug()<<now.second()<<"s "<<now.msec()<<"ms :feedback()"; +#endif + bytesAvailable = bytesFree(); + + if(!(deviceState==QAudio::StoppedState||deviceState==QAudio::SuspendedState)) { + if(bytesAvailable >= period_size) + QMetaObject::invokeMethod(this, "deviceReady", Qt::QueuedConnection); + } +} + +bool QAudioOutputPrivate::deviceReady() +{ + if(deviceState == QAudio::StoppedState || deviceState == QAudio::SuspendedState) + return false; + + if(pullMode) { + int chunks = bytesAvailable/period_size; +#ifdef DEBUG_AUDIO + qDebug()<<"deviceReady() avail="<<bytesAvailable<<" bytes, period size="<<period_size<<" bytes"; + qDebug()<<"deviceReady() no. of chunks that can fit ="<<chunks<<", chunks in bytes ="<<chunks*period_size; +#endif + bool startup = false; + if(totalTimeValue == 0) + startup = true; + + bool full=false; + + mutex.lock(); + if(waveFreeBlockCount==0) full = true; + mutex.unlock(); + + if (full){ +#ifdef DEBUG_AUDIO + qDebug() << "Skipping data as unable to write"; +#endif + if((timeStamp.elapsed() + elapsedTimeOffset) > intervalTime ) { + emit notify(); + elapsedTimeOffset = timeStamp.elapsed() + elapsedTimeOffset - intervalTime; + timeStamp.restart(); + } + return true; + } + + if(startup) + waveOutPause(hWaveOut); + int input = period_size*chunks; + int l = audioSource->read(audioBuffer,input); + if(l > 0) { + int out= write(audioBuffer,l); + if(out > 0) { + if (deviceState != QAudio::ActiveState) { + deviceState = QAudio::ActiveState; + emit stateChanged(deviceState); + } + } + if ( out < l) { + // Didn't write all data + audioSource->seek(audioSource->pos()-(l-out)); + } + if(startup) + waveOutRestart(hWaveOut); + } else if(l == 0) { + bytesAvailable = bytesFree(); + + int check = 0; + + mutex.lock(); + check = waveFreeBlockCount; + mutex.unlock(); + + if(check == buffer_size/period_size) { + if (deviceState != QAudio::IdleState) { + errorState = QAudio::UnderrunError; + deviceState = QAudio::IdleState; + emit stateChanged(deviceState); + } + } + + } else if(l < 0) { + bytesAvailable = bytesFree(); + if (errorState != QAudio::IOError) + errorState = QAudio::IOError; + } + } else { + int buffered; + + mutex.lock(); + buffered = waveFreeBlockCount; + mutex.unlock(); + + if (buffered >= buffer_size/period_size && deviceState == QAudio::ActiveState) { + if (deviceState != QAudio::IdleState) { + errorState = QAudio::UnderrunError; + deviceState = QAudio::IdleState; + emit stateChanged(deviceState); + } + } + } + if(deviceState != QAudio::ActiveState && deviceState != QAudio::IdleState) + return true; + + if(intervalTime && (timeStamp.elapsed() + elapsedTimeOffset) > intervalTime) { + emit notify(); + elapsedTimeOffset = timeStamp.elapsed() + elapsedTimeOffset - intervalTime; + timeStamp.restart(); + } + + return true; +} + +qint64 QAudioOutputPrivate::elapsedUSecs() const +{ + if (deviceState == QAudio::StoppedState) + return 0; + + return timeStampOpened.elapsed()*1000; +} + +QAudio::Error QAudioOutputPrivate::error() const +{ + return errorState; +} + +QAudio::State QAudioOutputPrivate::state() const +{ + return deviceState; +} + +void QAudioOutputPrivate::reset() +{ + close(); +} + +OutputPrivate::OutputPrivate(QAudioOutputPrivate* audio) +{ + audioDevice = qobject_cast<QAudioOutputPrivate*>(audio); +} + +OutputPrivate::~OutputPrivate() {} + +qint64 OutputPrivate::readData( char* data, qint64 len) +{ + Q_UNUSED(data) + Q_UNUSED(len) + + return 0; +} + +qint64 OutputPrivate::writeData(const char* data, qint64 len) +{ + int retry = 0; + qint64 written = 0; + + if((audioDevice->deviceState == QAudio::ActiveState) + ||(audioDevice->deviceState == QAudio::IdleState)) { + qint64 l = len; + while(written < l) { + int chunk = audioDevice->write(data+written,(l-written)); + if(chunk <= 0) + retry++; + else + written+=chunk; + + if(retry > 10) + return written; + } + audioDevice->deviceState = QAudio::ActiveState; + } + return written; +} + +QT_END_NAMESPACE + +#include "moc_qaudiooutput_win32_p.cpp" diff --git a/src/multimedia/audio/qaudiooutput_win32_p.h b/src/multimedia/audio/qaudiooutput_win32_p.h new file mode 100644 index 000000000..aa86d4e9b --- /dev/null +++ b/src/multimedia/audio/qaudiooutput_win32_p.h @@ -0,0 +1,175 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#ifndef QAUDIOOUTPUTWIN_H +#define QAUDIOOUTPUTWIN_H + +#include <windows.h> +#include <mmsystem.h> + +#include <QtCore/qdebug.h> +#include <QtCore/qtimer.h> +#include <QtCore/qstring.h> +#include <QtCore/qstringlist.h> +#include <QtCore/qdatetime.h> +#include <QtCore/qmutex.h> + +#include <qaudio.h> +#include <qaudiodeviceinfo.h> +#include <qaudiosystem.h> + +// For compat with 4.6 +#if !defined(QT_WIN_CALLBACK) +# if defined(Q_CC_MINGW) +# define QT_WIN_CALLBACK CALLBACK __attribute__ ((force_align_arg_pointer)) +# else +# define QT_WIN_CALLBACK CALLBACK +# endif +#endif + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + +class QAudioOutputPrivate : public QAbstractAudioOutput +{ + Q_OBJECT +public: + QAudioOutputPrivate(const QByteArray &device); + ~QAudioOutputPrivate(); + + qint64 write( const char *data, qint64 len ); + + void setFormat(const QAudioFormat& fmt); + QAudioFormat format() const; + QIODevice* start(); + void start(QIODevice* device); + void stop(); + void reset(); + void suspend(); + void resume(); + int bytesFree() const; + int periodSize() const; + void setBufferSize(int value); + int bufferSize() const; + void setNotifyInterval(int milliSeconds); + int notifyInterval() const; + qint64 processedUSecs() const; + qint64 elapsedUSecs() const; + QAudio::Error error() const; + QAudio::State state() const; + + QIODevice* audioSource; + QAudioFormat settings; + QAudio::Error errorState; + QAudio::State deviceState; + +private slots: + void feedback(); + bool deviceReady(); + +private: + QByteArray m_device; + bool resuming; + int bytesAvailable; + QTime timeStamp; + qint64 elapsedTimeOffset; + QTime timeStampOpened; + qint32 buffer_size; + qint32 period_size; + qint64 totalTimeValue; + bool pullMode; + int intervalTime; + static void QT_WIN_CALLBACK waveOutProc( HWAVEOUT hWaveOut, UINT uMsg, + DWORD dwInstance, DWORD dwParam1, DWORD dwParam2 ); + + QMutex mutex; + + WAVEHDR* allocateBlocks(int size, int count); + void freeBlocks(WAVEHDR* blockArray); + bool open(); + void close(); + + WAVEFORMATEX wfx; + HWAVEOUT hWaveOut; + MMRESULT result; + WAVEHDR header; + WAVEHDR* waveBlocks; + volatile bool finished; + volatile int waveFreeBlockCount; + int waveCurrentBlock; + char* audioBuffer; +}; + +class OutputPrivate : public QIODevice +{ + Q_OBJECT +public: + OutputPrivate(QAudioOutputPrivate* audio); + ~OutputPrivate(); + + qint64 readData( char* data, qint64 len); + qint64 writeData(const char* data, qint64 len); + +private: + QAudioOutputPrivate *audioDevice; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + + +#endif diff --git a/src/multimedia/audio/qaudiopluginloader.cpp b/src/multimedia/audio/qaudiopluginloader.cpp new file mode 100644 index 000000000..58006356a --- /dev/null +++ b/src/multimedia/audio/qaudiopluginloader.cpp @@ -0,0 +1,176 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qaudiosystemplugin.h" +#include "qaudiopluginloader_p.h" + +#include <QtCore/qcoreapplication.h> +#include <QtCore/qpluginloader.h> +#include <QtCore/qfactoryinterface.h> +#include <QtCore/qdir.h> +#include <QtCore/qdebug.h> + +QT_BEGIN_NAMESPACE + +QAudioPluginLoader::QAudioPluginLoader(const char *iid, const QString &location, Qt::CaseSensitivity): + m_iid(iid) +{ + m_location = location + QLatin1Char('/'); + load(); +} + +QAudioPluginLoader::~QAudioPluginLoader() +{ + for (int i = 0; i < m_plugins.count(); i++ ) { + delete m_plugins.at(i); + } +} + +QStringList QAudioPluginLoader::pluginList() const +{ +#if !defined QT_NO_DEBUG + const bool showDebug = qgetenv("QT_DEBUG_PLUGINS").toInt() > 0; +#endif + + QStringList paths = QCoreApplication::libraryPaths(); +#ifdef QTM_PLUGIN_PATH + paths << QLatin1String(QTM_PLUGIN_PATH); +#endif +#if !defined QT_NO_DEBUG + if (showDebug) + qDebug() << "Plugin paths:" << paths; +#endif + + //temp variable to avoid multiple identic path + QSet<QString> processed; + + /* Discover a bunch o plugins */ + QStringList plugins; + + /* Enumerate our plugin paths */ + for (int i=0; i < paths.count(); i++) { + if (processed.contains(paths.at(i))) + continue; + processed.insert(paths.at(i)); + QDir pluginsDir(paths.at(i)+m_location); + if (!pluginsDir.exists()) + continue; + + QStringList files = pluginsDir.entryList(QDir::Files); +#if !defined QT_NO_DEBUG + if (showDebug) + qDebug()<<"Looking for plugins in "<<pluginsDir.path()<<files; +#endif + for (int j=0; j < files.count(); j++) { + const QString &file = files.at(j); + plugins << pluginsDir.absoluteFilePath(file); + } + } + return plugins; +} + +QStringList QAudioPluginLoader::keys() const +{ + QMutexLocker locker(const_cast<QMutex *>(&m_mutex)); + + QStringList list; + for (int i = 0; i < m_plugins.count(); i++) { + QAudioSystemPlugin* p = qobject_cast<QAudioSystemPlugin*>(m_plugins.at(i)->instance()); + if (p) list << p->keys(); + } + + return list; +} + +QObject* QAudioPluginLoader::instance(QString const &key) +{ + QMutexLocker locker(&m_mutex); + + for (int i = 0; i < m_plugins.count(); i++) { + QAudioSystemPlugin* p = qobject_cast<QAudioSystemPlugin*>(m_plugins.at(i)->instance()); + if (p && p->keys().contains(key)) + return m_plugins.at(i)->instance(); + } + return 0; +} + +QList<QObject*> QAudioPluginLoader::instances(QString const &key) +{ + QMutexLocker locker(&m_mutex); + + QList<QObject*> list; + for (int i = 0; i < m_plugins.count(); i++) { + QAudioSystemPlugin* p = qobject_cast<QAudioSystemPlugin*>(m_plugins.at(i)->instance()); + if (p && p->keys().contains(key)) + list << m_plugins.at(i)->instance(); + } + return list; +} + +void QAudioPluginLoader::load() +{ + if (!m_plugins.isEmpty()) + return; + +#if !defined QT_NO_DEBUG + const bool showDebug = qgetenv("QT_DEBUG_PLUGINS").toInt() > 0; +#endif + + QStringList plugins = pluginList(); + for (int i=0; i < plugins.count(); i++) { + QPluginLoader* loader = new QPluginLoader(plugins.at(i)); + QObject *o = loader->instance(); + if (o != 0 && o->qt_metacast(m_iid) != 0) { + m_plugins.append(loader); + } else { +#if !defined QT_NO_DEBUG + if (showDebug) + qWarning() << "QAudioPluginLoader: Failed to load plugin: " + << plugins.at(i) << loader->errorString(); +#endif + delete o; + //we are not calling loader->unload here for it may cause problem on some device + delete loader; + } + } +} +QT_END_NAMESPACE + diff --git a/src/multimedia/audio/qaudiopluginloader_p.h b/src/multimedia/audio/qaudiopluginloader_p.h new file mode 100644 index 000000000..2e6fdbdd7 --- /dev/null +++ b/src/multimedia/audio/qaudiopluginloader_p.h @@ -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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QAUDIOPLUGINLOADER_H +#define QAUDIOPLUGINLOADER_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <qtmultimediadefs.h> +#include <QObject> +#include <QtCore/qstring.h> +#include <QtCore/qmap.h> +#include <QtCore/qmutex.h> +#include <QtCore/qpluginloader.h> + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + +class QAudioPluginLoader +{ +public: + QAudioPluginLoader(const char *iid, + const QString &suffix = QString(), + Qt::CaseSensitivity = Qt::CaseSensitive); + + ~QAudioPluginLoader(); + + QStringList keys() const; + QObject* instance(QString const &key); + QList<QObject*> instances(QString const &key); + +private: + QStringList pluginList() const; + void load(); + + QMutex m_mutex; + + QByteArray m_iid; + QString m_location; + QList<QPluginLoader*> m_plugins; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + + +#endif // QAUDIOPLUGINLOADER_H diff --git a/src/multimedia/audio/qaudiosystem.cpp b/src/multimedia/audio/qaudiosystem.cpp new file mode 100644 index 000000000..a8837b06f --- /dev/null +++ b/src/multimedia/audio/qaudiosystem.cpp @@ -0,0 +1,436 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qaudiosystem.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QAbstractAudioDeviceInfo + \brief The QAbstractAudioDeviceInfo class is a base class for audio backends. + + \ingroup multimedia + \inmodule QtMultimedia + \internal + \since 1.0 + + This class implements the audio functionality for + QAudioDeviceInfo, i.e., QAudioDeviceInfo keeps a + QAbstractAudioDeviceInfo and routes function calls to it. For a + description of the functionality that QAbstractAudioDeviceInfo + implements, you can read the class and functions documentation of + QAudioDeviceInfo. + + \sa QAudioDeviceInfo + \sa QAbstractAudioOutput, QAbstractAudioInput +*/ + +/*! + \fn virtual QAudioFormat QAbstractAudioDeviceInfo::preferredFormat() const + Returns the recommended settings to use. + \since 1.0 +*/ + +/*! + \fn virtual bool QAbstractAudioDeviceInfo::isFormatSupported(const QAudioFormat& format) const + Returns true if \a format is available from audio device. + \since 1.0 +*/ + +/*! + \fn virtual QString QAbstractAudioDeviceInfo::deviceName() const + Returns the audio device name. + \since 1.0 +*/ + +/*! + \fn virtual QStringList QAbstractAudioDeviceInfo::supportedCodecs() + Returns the list of currently available codecs. + \since 1.0 +*/ + +/*! + \fn virtual QList<int> QAbstractAudioDeviceInfo::supportedSampleRates() + Returns the list of currently available sample rates. + \since 1.0 +*/ + +/*! + \fn virtual QList<int> QAbstractAudioDeviceInfo::supportedChannelCounts() + Returns the list of currently available channels. + \since 1.0 +*/ + +/*! + \fn virtual QList<int> QAbstractAudioDeviceInfo::supportedSampleSizes() + Returns the list of currently available sample sizes. + \since 1.0 +*/ + +/*! + \fn virtual QList<QAudioFormat::Endian> QAbstractAudioDeviceInfo::supportedByteOrders() + Returns the list of currently available byte orders. + \since 1.0 +*/ + +/*! + \fn virtual QList<QAudioFormat::SampleType> QAbstractAudioDeviceInfo::supportedSampleTypes() + Returns the list of currently available sample types. + \since 1.0 +*/ + +/*! + \class QAbstractAudioOutput + \brief The QAbstractAudioOutput class is a base class for audio backends. + \since 1.0 + + \ingroup multimedia + \inmodule QtMultimedia + \internal + + QAbstractAudioOutput implements audio functionality for + QAudioOutput, i.e., QAudioOutput routes function calls to + QAbstractAudioOutput. For a description of the functionality that + is implemented, see the QAudioOutput class and function + descriptions. + + \sa QAudioOutput +*/ + +/*! + \fn virtual void QAbstractAudioOutput::start(QIODevice* device) + Uses the \a device as the QIODevice to transfer data. + \since 1.0 +*/ + +/*! + \fn virtual QIODevice* QAbstractAudioOutput::start() + Returns a pointer to the QIODevice being used to handle + the data transfer. This QIODevice can be used to write() audio data directly. + \since 1.0 +*/ + +/*! + \fn virtual void QAbstractAudioOutput::stop() + Stops the audio output. + \since 1.0 +*/ + +/*! + \fn virtual void QAbstractAudioOutput::reset() + Drops all audio data in the buffers, resets buffers to zero. + \since 1.0 +*/ + +/*! + \fn virtual void QAbstractAudioOutput::suspend() + Stops processing audio data, preserving buffered audio data. + \since 1.0 +*/ + +/*! + \fn virtual void QAbstractAudioOutput::resume() + Resumes processing audio data after a suspend() + \since 1.0 +*/ + +/*! + \fn virtual int QAbstractAudioOutput::bytesFree() const + Returns the free space available in bytes in the audio buffer. + \since 1.0 +*/ + +/*! + \fn virtual int QAbstractAudioOutput::periodSize() const + Returns the period size in bytes. + \since 1.0 +*/ + +/*! + \fn virtual void QAbstractAudioOutput::setBufferSize(int value) + Sets the audio buffer size to \a value in bytes. + \since 1.0 +*/ + +/*! + \fn virtual int QAbstractAudioOutput::bufferSize() const + Returns the audio buffer size in bytes. + \since 1.0 +*/ + +/*! + \fn virtual void QAbstractAudioOutput::setNotifyInterval(int ms) + Sets the interval for notify() signal to be emitted. This is based on the \a ms + of audio data processed not on actual real-time. The resolution of the timer + is platform specific. + \since 1.0 +*/ + +/*! + \fn virtual int QAbstractAudioOutput::notifyInterval() const + Returns the notify interval in milliseconds. + \since 1.0 +*/ + +/*! + \fn virtual qint64 QAbstractAudioOutput::processedUSecs() const + Returns the amount of audio data processed since start() was called in milliseconds. + \since 1.0 +*/ + +/*! + \fn virtual qint64 QAbstractAudioOutput::elapsedUSecs() const + Returns the milliseconds since start() was called, including time in Idle and suspend states. + \since 1.0 +*/ + +/*! + \fn virtual QAudio::Error QAbstractAudioOutput::error() const + Returns the error state. + \since 1.0 +*/ + +/*! + \fn virtual QAudio::State QAbstractAudioOutput::state() const + Returns the state of audio processing. + \since 1.0 +*/ + +/*! + \fn virtual void QAbstractAudioOutput::setFormat(const QAudioFormat& fmt) + Set the QAudioFormat to use to \a fmt. + Setting the format is only allowable while in QAudio::StoppedState. + \since 1.0 +*/ + +/*! + \fn virtual QAudioFormat QAbstractAudioOutput::format() const + Returns the QAudioFormat being used. + \since 1.0 +*/ + +/*! + \fn virtual void QAbstractAudioOutput::setVolume(qreal volume) + Sets the volume. + Where \a volume is between 0.0 and 1.0. + \since 5.0 +*/ + +/*! + \fn virtual qreal QAbstractAudioOutput::volume() const + Returns the volume in the range 0.0 and 1.0. + \since 5.0 +*/ + +/*! + \fn QAbstractAudioOutput::errorChanged(QAudio::Error error) + This signal is emitted when the \a error state has changed. + \since 1.0 +*/ + +/*! + \fn QAbstractAudioOutput::stateChanged(QAudio::State state) + This signal is emitted when the device \a state has changed. + \since 1.0 +*/ + +/*! + \fn QAbstractAudioOutput::notify() + This signal is emitted when x ms of audio data has been processed + the interval set by setNotifyInterval(x). + \since 1.0 +*/ + + +/*! + \class QAbstractAudioInput + \brief The QAbstractAudioInput class provides access for QAudioInput to access the audio + device provided by the plugin. + \since 1.0 + + \ingroup multimedia + \inmodule QtMultimedia + \internal + + QAudioDeviceInput keeps an instance of QAbstractAudioInput and + routes calls to functions of the same name to QAbstractAudioInput. + This means that it is QAbstractAudioInput that implements the + audio functionality. For a description of the functionality, see + the QAudioInput class description. + + \sa QAudioInput +*/ + +/*! + \fn virtual void QAbstractAudioInput::start(QIODevice* device) + Uses the \a device as the QIODevice to transfer data. + \since 1.0 +*/ + +/*! + \fn virtual QIODevice* QAbstractAudioInput::start() + Returns a pointer to the QIODevice being used to handle + the data transfer. This QIODevice can be used to read() audio data directly. + \since 1.0 +*/ + +/*! + \fn virtual void QAbstractAudioInput::stop() + Stops the audio input. + \since 1.0 +*/ + +/*! + \fn virtual void QAbstractAudioInput::reset() + Drops all audio data in the buffers, resets buffers to zero. + \since 1.0 +*/ + +/*! + \fn virtual void QAbstractAudioInput::suspend() + Stops processing audio data, preserving buffered audio data. + \since 1.0 +*/ + +/*! + \fn virtual void QAbstractAudioInput::resume() + Resumes processing audio data after a suspend(). + \since 1.0 +*/ + +/*! + \fn virtual int QAbstractAudioInput::bytesReady() const + Returns the amount of audio data available to read in bytes. + \since 1.0 +*/ + +/*! + \fn virtual int QAbstractAudioInput::periodSize() const + Returns the period size in bytes. + \since 1.0 +*/ + +/*! + \fn virtual void QAbstractAudioInput::setBufferSize(int value) + Sets the audio buffer size to \a value in milliseconds. + \since 1.0 +*/ + +/*! + \fn virtual int QAbstractAudioInput::bufferSize() const + Returns the audio buffer size in milliseconds. + \since 1.0 +*/ + +/*! + \fn virtual void QAbstractAudioInput::setNotifyInterval(int ms) + Sets the interval for notify() signal to be emitted. This is based + on the \a ms of audio data processed not on actual real-time. + The resolution of the timer is platform specific. + \since 1.0 +*/ + +/*! + \fn virtual int QAbstractAudioInput::notifyInterval() const + Returns the notify interval in milliseconds. + \since 1.0 +*/ + +/*! + \fn virtual qint64 QAbstractAudioInput::processedUSecs() const + Returns the amount of audio data processed since start() was called in milliseconds. + \since 1.0 +*/ + +/*! + \fn virtual qint64 QAbstractAudioInput::elapsedUSecs() const + Returns the milliseconds since start() was called, including time in Idle and suspend states. + \since 1.0 +*/ + +/*! + \fn virtual QAudio::Error QAbstractAudioInput::error() const + Returns the error state. + \since 1.0 +*/ + +/*! + \fn virtual QAudio::State QAbstractAudioInput::state() const + Returns the state of audio processing. + \since 1.0 +*/ + +/*! + \fn virtual void QAbstractAudioInput::setFormat(const QAudioFormat& fmt) + Set the QAudioFormat to use to \a fmt. + Setting the format is only allowable while in QAudio::StoppedState. + \since 1.0 +*/ + +/*! + \fn virtual QAudioFormat QAbstractAudioInput::format() const + Returns the QAudioFormat being used + \since 1.0 +*/ + +/*! + \fn QAbstractAudioInput::errorChanged(QAudio::Error error) + This signal is emitted when the \a error state has changed. + \since 1.0 +*/ + +/*! + \fn QAbstractAudioInput::stateChanged(QAudio::State state) + This signal is emitted when the device \a state has changed. + \since 1.0 +*/ + +/*! + \fn QAbstractAudioInput::notify() + This signal is emitted when x ms of audio data has been processed + the interval set by setNotifyInterval(x). + \since 1.0 +*/ + + +QT_END_NAMESPACE + +#include "moc_qaudiosystem.cpp" diff --git a/src/multimedia/audio/qaudiosystem.h b/src/multimedia/audio/qaudiosystem.h new file mode 100644 index 000000000..59b4eb432 --- /dev/null +++ b/src/multimedia/audio/qaudiosystem.h @@ -0,0 +1,141 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QAUDIOSYSTEM_H +#define QAUDIOSYSTEM_H + +#include <qtmultimediadefs.h> +#include <qtmedianamespace.h> + +#include "qaudio.h" +#include "qaudioformat.h" +#include "qaudiodeviceinfo.h" + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + +class Q_MULTIMEDIA_EXPORT QAbstractAudioDeviceInfo : public QObject +{ + Q_OBJECT + +public: + virtual QAudioFormat preferredFormat() const = 0; + virtual bool isFormatSupported(const QAudioFormat &format) const = 0; + virtual QString deviceName() const = 0; + virtual QStringList supportedCodecs() = 0; + virtual QList<int> supportedSampleRates() = 0; + virtual QList<int> supportedChannelCounts() = 0; + virtual QList<int> supportedSampleSizes() = 0; + virtual QList<QAudioFormat::Endian> supportedByteOrders() = 0; + virtual QList<QAudioFormat::SampleType> supportedSampleTypes() = 0; +}; + +class Q_MULTIMEDIA_EXPORT QAbstractAudioOutput : public QObject +{ + Q_OBJECT + +public: + virtual void start(QIODevice *device) = 0; + virtual QIODevice* start() = 0; + virtual void stop() = 0; + virtual void reset() = 0; + virtual void suspend() = 0; + virtual void resume() = 0; + virtual int bytesFree() const = 0; + virtual int periodSize() const = 0; + virtual void setBufferSize(int value) = 0; + virtual int bufferSize() const = 0; + virtual void setNotifyInterval(int milliSeconds) = 0; + virtual int notifyInterval() const = 0; + virtual qint64 processedUSecs() const = 0; + virtual qint64 elapsedUSecs() const = 0; + virtual QAudio::Error error() const = 0; + virtual QAudio::State state() const = 0; + virtual void setFormat(const QAudioFormat& fmt) = 0; + virtual QAudioFormat format() const = 0; + virtual void setVolume(qreal) {} + virtual qreal volume() const { return 1.0; } + +Q_SIGNALS: + void errorChanged(QAudio::Error); + void stateChanged(QAudio::State); + void notify(); +}; + +class Q_MULTIMEDIA_EXPORT QAbstractAudioInput : public QObject +{ + Q_OBJECT + +public: + virtual void start(QIODevice *device) = 0; + virtual QIODevice* start() = 0; + virtual void stop() = 0; + virtual void reset() = 0; + virtual void suspend() = 0; + virtual void resume() = 0; + virtual int bytesReady() const = 0; + virtual int periodSize() const = 0; + virtual void setBufferSize(int value) = 0; + virtual int bufferSize() const = 0; + virtual void setNotifyInterval(int milliSeconds) = 0; + virtual int notifyInterval() const = 0; + virtual qint64 processedUSecs() const = 0; + virtual qint64 elapsedUSecs() const = 0; + virtual QAudio::Error error() const = 0; + virtual QAudio::State state() const = 0; + virtual void setFormat(const QAudioFormat& fmt) = 0; + virtual QAudioFormat format() const = 0; + +Q_SIGNALS: + void errorChanged(QAudio::Error); + void stateChanged(QAudio::State); + void notify(); +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QAUDIOSYSTEM_H diff --git a/src/multimedia/audio/qaudiosystemplugin.cpp b/src/multimedia/audio/qaudiosystemplugin.cpp new file mode 100644 index 000000000..5cbcf1d60 --- /dev/null +++ b/src/multimedia/audio/qaudiosystemplugin.cpp @@ -0,0 +1,143 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include "qaudiosystemplugin.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QAudioSystemPlugin + \brief The QAudioSystemPlugin class provides an abstract base for audio plugins. + \since 1.0 + + \ingroup multimedia + \inmodule QtMultimedia + \internal + + Writing a audio plugin is achieved by subclassing this base class, + reimplementing the pure virtual functions keys(), availableDevices(), + createInput(), createOutput() and createDeviceInfo() then exporting + the class with the Q_EXPORT_PLUGIN2() macro. + + Unit tests are available to help in debugging new plugins. + + \sa QAbstractAudioDeviceInfo, QAbstractAudioOutput, QAbstractAudioInput + + Qt supports win32, linux(alsa) and Mac OS X standard (builtin to the + QtMultimedia library at compile time). + + You can support other backends other than these predefined ones by + creating a plugin subclassing QAudioSystemPlugin, QAbstractAudioDeviceInfo, + QAbstractAudioOutput and QAbstractAudioInput. + + Add "default" to your list of keys() available to override the default + audio device to be provided by your plugin. + + -audio-backend configure option will force compiling in of the builtin backend + into the QtMultimedia library at compile time. This is automatic by default + and will only be compiled into the library if the dependencies are installed. + eg. alsa-devel package installed for linux. + + If the builtin backend is not compiled into the QtMultimedia library and + no audio plugins are available a fallback dummy backend will be used. + This should print out warnings if this is the case when you try and use QAudioInput or QAudioOutput. To fix this problem + reconfigure Qt using -audio-backend or create your own plugin with a default + key to always override the dummy fallback. The easiest way to determine + if you have only a dummy backend is to get a list of available audio devices. + + QAudioDeviceInfo::availableDevices(QAudio::AudioOutput).size() = 0 (dummy backend) +*/ + +/*! + Construct a new audio plugin with \a parent. + This is invoked automatically by the Q_EXPORT_PLUGIN2() macro. +*/ + +QAudioSystemPlugin::QAudioSystemPlugin(QObject* parent) : + QObject(parent) +{} + +/*! + Destroy the audio plugin + + You never have to call this explicitly. Qt destroys a plugin automatically when it is no longer used. +*/ + +QAudioSystemPlugin::~QAudioSystemPlugin() +{} + +/*! + \fn QStringList QAudioSystemPlugin::keys() const + Returns the list of device identifiers this plugin supports. + \since 1.0 +*/ + +/*! + \fn QList<QByteArray> QAudioSystemPlugin::availableDevices(QAudio::Mode mode) const + Returns a list of available audio devices for \a mode + \since 1.0 +*/ + +/*! + \fn QAbstractAudioInput* QAudioSystemPlugin::createInput(const QByteArray& device) + Returns a pointer to a QAbstractAudioInput created using \a device identifier + \since 1.0 +*/ + +/*! + \fn QAbstractAudioOutput* QAudioSystemPlugin::createOutput(const QByteArray& device) + Returns a pointer to a QAbstractAudioOutput created using \a device identifier + + \since 1.0 +*/ + +/*! + \fn QAbstractAudioDeviceInfo* QAudioSystemPlugin::createDeviceInfo(const QByteArray& device, QAudio::Mode mode) + Returns a pointer to a QAbstractAudioDeviceInfo created using \a device and \a mode + + \since 1.0 +*/ + + +QT_END_NAMESPACE + +#include "moc_qaudiosystemplugin.cpp" diff --git a/src/multimedia/audio/qaudiosystemplugin.h b/src/multimedia/audio/qaudiosystemplugin.h new file mode 100644 index 000000000..f61dbcfd1 --- /dev/null +++ b/src/multimedia/audio/qaudiosystemplugin.h @@ -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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#ifndef QAUDIOSYSTEMPLUGIN_H +#define QAUDIOSYSTEMPLUGIN_H + +#include <QtCore/qstring.h> +#include <QtCore/qplugin.h> +#include <QtCore/qfactoryinterface.h> + +#include <qtmultimediadefs.h> +#include <qtmedianamespace.h> + +#include "qaudioformat.h" +#include "qaudiodeviceinfo.h" +#include "qaudiosystem.h" + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + +struct Q_MULTIMEDIA_EXPORT QAudioSystemFactoryInterface : public QFactoryInterface +{ + virtual QList<QByteArray> availableDevices(QAudio::Mode) const = 0; + virtual QAbstractAudioInput* createInput(const QByteArray& device) = 0; + virtual QAbstractAudioOutput* createOutput(const QByteArray& device) = 0; + virtual QAbstractAudioDeviceInfo* createDeviceInfo(const QByteArray& device, QAudio::Mode mode) = 0; +}; + +#define QAudioSystemFactoryInterface_iid \ + "com.nokia.qt.QAudioSystemFactoryInterface" +Q_DECLARE_INTERFACE(QAudioSystemFactoryInterface, QAudioSystemFactoryInterface_iid) + +class Q_MULTIMEDIA_EXPORT QAudioSystemPlugin : public QObject, public QAudioSystemFactoryInterface +{ + Q_OBJECT + Q_INTERFACES(QAudioSystemFactoryInterface:QFactoryInterface) + +public: + QAudioSystemPlugin(QObject *parent = 0); + ~QAudioSystemPlugin(); + + virtual QStringList keys() const = 0; + virtual QList<QByteArray> availableDevices(QAudio::Mode) const = 0; + virtual QAbstractAudioInput* createInput(const QByteArray& device) = 0; + virtual QAbstractAudioOutput* createOutput(const QByteArray& device) = 0; + virtual QAbstractAudioDeviceInfo* createDeviceInfo(const QByteArray& device, QAudio::Mode mode) = 0; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QAUDIOSYSTEMPLUGIN_H diff --git a/src/multimedia/effects/effects.pri b/src/multimedia/effects/effects.pri new file mode 100644 index 000000000..48c9906b6 --- /dev/null +++ b/src/multimedia/effects/effects.pri @@ -0,0 +1,36 @@ +INCLUDEPATH += effects + +unix:!mac { + contains(config_test_pulseaudio, yes) { + CONFIG += link_pkgconfig + PKGCONFIG += libpulse + + DEFINES += QT_MULTIMEDIA_PULSEAUDIO + PRIVATE_HEADERS += effects/qsoundeffect_pulse_p.h + SOURCES += effects/qsoundeffect_pulse_p.cpp + !maemo*:DEFINES += QTM_PULSEAUDIO_DEFAULTBUFFER + } else { + DEFINES += QT_MULTIMEDIA_QMEDIAPLAYER + PRIVATE_HEADERS += effects/qsoundeffect_qmedia_p.h + SOURCES += effects/qsoundeffect_qmedia_p.cpp + } +} else:!qpa { + PRIVATE_HEADERS += effects/qsoundeffect_qsound_p.h + SOURCES += effects/qsoundeffect_qsound_p.cpp +} else { + DEFINES += QT_MULTIMEDIA_QMEDIAPLAYER + PRIVATE_HEADERS += effects/qsoundeffect_qmedia_p.h + SOURCES += effects/qsoundeffect_qmedia_p.cpp +} + +PRIVATE_HEADERS += \ + effects/qsoundeffect_p.h \ + effects/qwavedecoder_p.h \ + effects/qsamplecache_p.h + +SOURCES += \ + effects/qsoundeffect.cpp \ + effects/qwavedecoder_p.cpp \ + effects/qsamplecache_p.cpp + +HEADERS += diff --git a/src/multimedia/effects/qsamplecache_p.cpp b/src/multimedia/effects/qsamplecache_p.cpp new file mode 100644 index 000000000..1610a4382 --- /dev/null +++ b/src/multimedia/effects/qsamplecache_p.cpp @@ -0,0 +1,398 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qsamplecache_p.h" +#include "qwavedecoder_p.h" +#include <QtNetwork> + +//#define QT_SAMPLECACHE_DEBUG + +QT_BEGIN_NAMESPACE + + +/*! + \class QSampleCache + \internal + + When you want to get a sound sample data, you need to request the QSample reference from QSampleCache. + + \since 1.1 + + \code + QSample *m_sample; // class member. + + private Q_SLOTS: + void decoderError(); + void sampleReady(); + \endcode + + \code + Q_GLOBAL_STATIC(QSampleCache, sampleCache) //declare a singleton manager + \endcode + + \code + m_sample = sampleCache()->requestSample(url); + switch(m_sample->state()) { + case QSample::Ready: + sampleReady(); + break; + case QSample::Error: + decoderError(); + break; + default: + connect(m_sample, SIGNAL(error()), this, SLOT(decoderError())); + connect(m_sample, SIGNAL(ready()), this, SLOT(sampleReady())); + break; + } + \endcode + + When you no longer need the sound sample data, you need to release it: + + \code + if (m_sample) { + m_sample->release(); + m_sample = 0; + } + \endcode +*/ + +QSampleCache::QSampleCache() + : m_networkAccessManager(0) + , m_mutex(QMutex::Recursive) + , m_capacity(0) + , m_usage(0) +{ + m_loadingThread.setObjectName(QLatin1String("QSampleCache::LoadingThread")); +} + +QNetworkAccessManager& QSampleCache::networkAccessManager() +{ + if (!m_networkAccessManager) + m_networkAccessManager = new QNetworkAccessManager(); + return *m_networkAccessManager; +} + +QSampleCache::~QSampleCache() +{ + QMutexLocker m(&m_mutex); + + m_loadingThread.quit(); + m_loadingThread.wait(); + + // Killing the loading thread means that no samples can be + // deleted using deleteLater. And some samples that had deleteLater + // already called won't have been processed (m_staleSamples) + foreach (QSample* sample, m_samples) + delete sample; + + foreach (QSample* sample, m_staleSamples) + delete sample; // deleting a sample does affect the m_staleSamples list, but foreach copies it + + delete m_networkAccessManager; +} + +QSample* QSampleCache::requestSample(const QUrl& url) +{ + if (!m_loadingThread.isRunning()) + m_loadingThread.start(); +#ifdef QT_SAMPLECACHE_DEBUG + qDebug() << "QSampleCache: request sample [" << url << "]"; +#endif + QMutexLocker locker(&m_mutex); + QMap<QUrl, QSample*>::iterator it = m_samples.find(url); + QSample* sample; + if (it == m_samples.end()) { + sample = new QSample(url, this); + m_samples.insert(url, sample); + sample->moveToThread(&m_loadingThread); + } else { + sample = *it; + } + + sample->addRef(); + locker.unlock(); + + sample->loadIfNecessary(); + return sample; +} + +void QSampleCache::setCapacity(qint64 capacity) +{ + QMutexLocker locker(&m_mutex); + if (m_capacity == capacity) + return; +#ifdef QT_SAMPLECACHE_DEBUG + qDebug() << "QSampleCache: capacity changes from " << m_capacity << "to " << capacity; +#endif + if (m_capacity > 0 && capacity <= 0) { //memory management strategy changed + for (QMap<QUrl, QSample*>::iterator it = m_samples.begin(); it != m_samples.end();) { + QSample* sample = *it; + if (sample->m_ref == 0) { + unloadSample(sample); + it = m_samples.erase(it); + } else + it++; + } + } + + m_capacity = capacity; + refresh(0); +} + +// Called locked +void QSampleCache::unloadSample(QSample *sample) +{ + m_usage -= sample->m_soundData.size(); + m_staleSamples.insert(sample); + sample->deleteLater(); +} + +// Called in both threads +void QSampleCache::refresh(qint64 usageChange) +{ + QMutexLocker locker(&m_mutex); + m_usage += usageChange; + if (m_capacity <= 0 || m_usage <= m_capacity) + return; + +#ifdef QT_SAMPLECACHE_DEBUG + qint64 recoveredSize = 0; +#endif + + //free unused samples to keep usage under capacity limit. + for (QMap<QUrl, QSample*>::iterator it = m_samples.begin(); it != m_samples.end();) { + QSample* sample = *it; + if (sample->m_ref > 0) { + ++it; + continue; + } +#ifdef QT_SAMPLECACHE_DEBUG + recoveredSize += sample->m_soundData.size(); +#endif + unloadSample(sample); + it = m_samples.erase(it); + if (m_usage <= m_capacity) + return; + } + +#ifdef QT_SAMPLECACHE_DEBUG + qDebug() << "QSampleCache: refresh(" << usageChange + << ") recovered size =" << recoveredSize + << "new usage =" << m_usage; +#endif + + if (m_usage > m_capacity) + qWarning() << "QSampleCache: usage[" << m_usage << " out of limit[" << m_capacity << "]"; +} + +// Called in both threads +void QSampleCache::removeUnreferencedSample(QSample *sample) +{ + QMutexLocker m(&m_mutex); + m_staleSamples.remove(sample); +} + +// Called in loader thread (since this lives in that thread) +// Also called from application thread after loader thread dies. +QSample::~QSample() +{ + // Remove ourselves from our parent + m_parent->removeUnreferencedSample(this); + + QMutexLocker locker(&m_mutex); +#ifdef QT_SAMPLECACHE_DEBUG + qDebug() << "~QSample" << this << ": deleted [" << m_url << "]" << QThread::currentThread(); +#endif + cleanup(); +} + +// Called in application thread +void QSample::loadIfNecessary() +{ + QMutexLocker locker(&m_mutex); + if (m_state == QSample::Error || m_state == QSample::Creating) { + m_state = QSample::Loading; + QMetaObject::invokeMethod(this, "load", Qt::QueuedConnection); + } +} + +// Called in both threads +bool QSampleCache::notifyUnreferencedSample(QSample* sample) +{ + QMutexLocker locker(&m_mutex); + if (m_capacity > 0) + return false; + m_samples.remove(sample->m_url); + m_staleSamples.insert(sample); + sample->deleteLater(); + return true; +} + +// Called in application threadd +void QSample::release() +{ + QMutexLocker locker(&m_mutex); +#ifdef QT_SAMPLECACHE_DEBUG + qDebug() << "Sample:: release" << this << QThread::currentThread() << m_ref; +#endif + m_ref--; + if (m_ref == 0) + m_parent->notifyUnreferencedSample(this); +} + +// Called in dtor and when stream is loaded +// must be called locked. +void QSample::cleanup() +{ + delete m_waveDecoder; + delete m_stream; + m_waveDecoder = 0; + m_stream = 0; +} + +// Called in application thread +void QSample::addRef() +{ + m_ref++; +} + +// Called in loading thread +void QSample::readSample() +{ + Q_ASSERT(QThread::currentThread()->objectName() == QLatin1String("QSampleCache::LoadingThread")); + QMutexLocker m(&m_mutex); +#ifdef QT_SAMPLECACHE_DEBUG + qDebug() << "QSample: readSample"; +#endif + qint64 read = m_waveDecoder->read(m_soundData.data() + m_sampleReadLength, + qMin(m_waveDecoder->bytesAvailable(), + qint64(m_waveDecoder->size() - m_sampleReadLength))); + if (read > 0) + m_sampleReadLength += read; + if (m_sampleReadLength < m_waveDecoder->size()) + return; + Q_ASSERT(m_sampleReadLength == qint64(m_soundData.size())); + onReady(); +} + +// Called in loading thread +void QSample::decoderReady() +{ + Q_ASSERT(QThread::currentThread()->objectName() == QLatin1String("QSampleCache::LoadingThread")); + QMutexLocker m(&m_mutex); +#ifdef QT_SAMPLECACHE_DEBUG + qDebug() << "QSample: decoder ready"; +#endif + m_parent->refresh(m_waveDecoder->size()); + + m_soundData.resize(m_waveDecoder->size()); + m_sampleReadLength = 0; + qint64 read = m_waveDecoder->read(m_soundData.data(), m_waveDecoder->size()); + if (read > 0) + m_sampleReadLength += read; + if (m_sampleReadLength >= m_waveDecoder->size()) + onReady(); +} + +// Called in all threads +QSample::State QSample::state() const +{ + QMutexLocker m(&m_mutex); + return m_state; +} + +// Called in loading thread +// Essentially a second ctor, doesn't need locks (?) +void QSample::load() +{ + Q_ASSERT(QThread::currentThread()->objectName() == QLatin1String("QSampleCache::LoadingThread")); +#ifdef QT_SAMPLECACHE_DEBUG + qDebug() << "QSample: load [" << m_url << "]"; +#endif + m_stream = m_parent->networkAccessManager().get(QNetworkRequest(m_url)); + connect(m_stream, SIGNAL(error(QNetworkReply::NetworkError)), SLOT(decoderError())); + m_waveDecoder = new QWaveDecoder(m_stream); + connect(m_waveDecoder, SIGNAL(formatKnown()), SLOT(decoderReady())); + connect(m_waveDecoder, SIGNAL(invalidFormat()), SLOT(decoderError())); + connect(m_waveDecoder, SIGNAL(readyRead()), SLOT(readSample())); +} + +// Called in loading thread +void QSample::decoderError() +{ + Q_ASSERT(QThread::currentThread()->objectName() == QLatin1String("QSampleCache::LoadingThread")); + QMutexLocker m(&m_mutex); +#ifdef QT_SAMPLECACHE_DEBUG + qDebug() << "QSample: decoder error"; +#endif + cleanup(); + m_state = QSample::Error; + emit error(); +} + +// Called in loading thread from decoder when sample is done. Locked already. +void QSample::onReady() +{ + Q_ASSERT(QThread::currentThread()->objectName() == QLatin1String("QSampleCache::LoadingThread")); +#ifdef QT_SAMPLECACHE_DEBUG + qDebug() << "QSample: load ready"; +#endif + m_audioFormat = m_waveDecoder->audioFormat(); + cleanup(); + m_state = QSample::Ready; + emit ready(); +} + +// Called in application thread, then moved to loader thread +QSample::QSample(const QUrl& url, QSampleCache *parent) + : m_parent(parent) + , m_stream(0) + , m_waveDecoder(0) + , m_url(url) + , m_sampleReadLength(0) + , m_state(Creating) + , m_ref(0) +{ +} + +QT_END_NAMESPACE + +#include "moc_qsamplecache_p.cpp" diff --git a/src/multimedia/effects/qsamplecache_p.h b/src/multimedia/effects/qsamplecache_p.h new file mode 100644 index 000000000..91ca457e6 --- /dev/null +++ b/src/multimedia/effects/qsamplecache_p.h @@ -0,0 +1,161 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSAMPLECACHE_P_H +#define QSAMPLECACHE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtCore/qobject.h> +#include <QtCore/qthread.h> +#include <QtCore/qurl.h> +#include <QtCore/qmutex.h> +#include <QtCore/qmap.h> +#include <QtCore/qset.h> +#include <qaudioformat.h> + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + +class QNetworkAccessManager; +class QSampleCache; +class QWaveDecoder; + +// Lives in application thread +class QSample : public QObject +{ + Q_OBJECT +public: + friend class QSampleCache; + enum State + { + Creating, + Loading, + Error, + Ready, + }; + + State state() const; + // These are not (currently) locked because they are only meant to be called after these + // variables are updated to their final states + const QByteArray& data() const { Q_ASSERT(state() == Ready); return m_soundData; } + const QAudioFormat& format() const { Q_ASSERT(state() == Ready); return m_audioFormat; } + void release(); + +Q_SIGNALS: + void error(); + void ready(); + +protected: + QSample(const QUrl& url, QSampleCache *parent); + +private Q_SLOTS: + void load(); + void decoderError(); + void readSample(); + void decoderReady(); + +private: + void onReady(); + void cleanup(); + void addRef(); + void loadIfNecessary(); + QSample(); + ~QSample(); + + mutable QMutex m_mutex; + QSampleCache *m_parent; + QByteArray m_soundData; + QAudioFormat m_audioFormat; + QIODevice *m_stream; + QWaveDecoder *m_waveDecoder; + QUrl m_url; + qint64 m_sampleReadLength; + State m_state; + int m_ref; +}; + +class QSampleCache +{ +public: + friend class QSample; + + QSampleCache(); + ~QSampleCache(); + + QSample* requestSample(const QUrl& url); + void setCapacity(qint64 capacity); + +private: + QMap<QUrl, QSample*> m_samples; + QSet<QSample*> m_staleSamples; + QNetworkAccessManager *m_networkAccessManager; + QMutex m_mutex; + qint64 m_capacity; + qint64 m_usage; + QThread m_loadingThread; + + QNetworkAccessManager& networkAccessManager(); + void refresh(qint64 usageChange); + bool notifyUnreferencedSample(QSample* sample); + void removeUnreferencedSample(QSample* sample); + void unloadSample(QSample* sample); +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QSAMPLECACHE_P_H diff --git a/src/multimedia/effects/qsoundeffect.cpp b/src/multimedia/effects/qsoundeffect.cpp new file mode 100644 index 000000000..b1137a22e --- /dev/null +++ b/src/multimedia/effects/qsoundeffect.cpp @@ -0,0 +1,301 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qsoundeffect_p.h" + +#if defined(QT_MULTIMEDIA_PULSEAUDIO) +#include "qsoundeffect_pulse_p.h" +#elif(QT_MULTIMEDIA_QMEDIAPLAYER) +#include "qsoundeffect_qmedia_p.h" +#else +#include "qsoundeffect_qsound_p.h" +#endif + +QT_BEGIN_NAMESPACE + +/*! + \qmlclass SoundEffect QSoundEffect + \brief The SoundEffect element provides a way to play sound effects in QML. + \since 1.0 + + \inmodule QtMultimedia + + This element is part of the \bold{QtMultimedia 4.0} module. + + The following example plays a WAV file on mouse click. + + \snippet doc/src/snippets/multimedia-snippets/soundeffect.qml complete snippet +*/ + +/*! + \qmlproperty url SoundEffect::source + \since 1.0 + + This property provides a way to control the sound to play. +*/ + +/*! + \qmlproperty int SoundEffect::loops + \since 1.0 + + This property provides a way to control the number of times to repeat the sound on each play(). + + Set to -1 (infinite) to enable infinite loop. +*/ + +/*! + \qmlproperty qreal SoundEffect::volume + \since 1.0 + + This property holds the volume of the playback, from 0.0 (silent) to 1.0 (maximum volume). + Note: Currently this has no effect on Mac OS X. +*/ + +/*! + \qmlproperty bool SoundEffect::muted + \since 1.0 + + This property provides a way to control muting. +*/ + +/*! + \qmlproperty bool SoundEffect::playing + \since 1.1 + + This property indicates if the soundeffect is playing or not. +*/ + +/*! + \qmlproperty int SoundEffect::status + \since 1.0 + + This property indicates the following status of the soundeffect. + + Null: no source has been set or is null. + Loading: the soundeffect is trying to load the source. + Ready: the source is loaded and ready for play. + Error: some error happened during operation, such as failure of loading the source. +*/ + +/*! + \qmlsignal SoundEffect::sourceChanged() + \since 1.0 + + This handler is called when the source has changed. +*/ + +/*! + \qmlsignal SoundEffect::loopsChanged() + \since 1.0 + + This handler is called when the number of loops has changed. +*/ + +/*! + \qmlsignal SoundEffect::volumeChanged() + \since 1.0 + + This handler is called when the volume has changed. +*/ + +/*! + \qmlsignal SoundEffect::mutedChanged() + \since 1.0 + + This handler is called when the mute state has changed. +*/ + +/*! + \qmlsignal SoundEffect::playingChanged() + \since 1.0 + + This handler is called when the playing property has changed. +*/ + +/*! + \qmlsignal SoundEffect::statusChanged() + + This handler is called when the status property has changed. + \since 1.0 +*/ + + +/*! + \internal + \since 1.0 +*/ + +QSoundEffect::QSoundEffect(QObject *parent) : + QObject(parent) +{ + d = new QSoundEffectPrivate(this); + connect(d, SIGNAL(volumeChanged()), SIGNAL(volumeChanged())); + connect(d, SIGNAL(mutedChanged()), SIGNAL(mutedChanged())); + connect(d, SIGNAL(loadedChanged()), SIGNAL(loadedChanged())); + connect(d, SIGNAL(playingChanged()), SIGNAL(playingChanged())); + connect(d, SIGNAL(statusChanged()), SIGNAL(statusChanged())); +} + +QSoundEffect::~QSoundEffect() +{ + d->deleteLater(); +} + +QStringList QSoundEffect::supportedMimeTypes() +{ + return QSoundEffectPrivate::supportedMimeTypes(); +} + +QUrl QSoundEffect::source() const +{ + return d->source(); +} + +void QSoundEffect::setSource(const QUrl &url) +{ + if (d->source() == url) + return; + + d->setSource(url); + + emit sourceChanged(); +} + +int QSoundEffect::loopCount() const +{ + return d->loopCount(); +} + +void QSoundEffect::setLoopCount(int loopCount) +{ + if (loopCount < 0 && loopCount != Infinite) { + qWarning("SoundEffect: loops should be SoundEffect.Infinite, 0 or positive integer"); + return; + } + if (loopCount == 0) + loopCount = 1; + if (d->loopCount() == loopCount) + return; + + d->setLoopCount(loopCount); + emit loopCountChanged(); +} + +qreal QSoundEffect::volume() const +{ + return qreal(d->volume()) / 100; +} + +void QSoundEffect::setVolume(qreal volume) +{ + if (volume < 0 || volume > 1) { + qWarning("SoundEffect: volume should be between 0.0 and 1.0"); + return; + } + int iVolume = qRound(volume * 100); + if (d->volume() == iVolume) + return; + + d->setVolume(iVolume); +} + +bool QSoundEffect::isMuted() const +{ + return d->isMuted(); +} + +void QSoundEffect::setMuted(bool muted) +{ + if (d->isMuted() == muted) + return; + + d->setMuted(muted); +} + +bool QSoundEffect::isLoaded() const +{ + return d->isLoaded(); +} + +/*! + \qmlmethod SoundEffect::play() + + Start playback of the sound effect, looping the effect for the number of + times as specificed in the loops property. + + This is the default method for SoundEffect. + + \snippet doc/src/snippets/multimedia-snippets/soundeffect.qml play sound on click + \since 1.0 +*/ +void QSoundEffect::play() +{ + d->play(); +} + +bool QSoundEffect::isPlaying() const +{ + return d->isPlaying(); +} + +QSoundEffect::Status QSoundEffect::status() const +{ + return d->status(); +} + + +/*! + \qmlmethod SoundEffect::stop() + + Stop current playback. + Note that if the backend is PulseAudio, due to the limitation of the underlying API, + tis stop will only prevent next looping but will not be able to stop current playback immediately. + + \since 1.0 + */ +void QSoundEffect::stop() +{ + d->stop(); +} + +QT_END_NAMESPACE + +#include "moc_qsoundeffect_p.cpp" diff --git a/src/multimedia/effects/qsoundeffect_p.h b/src/multimedia/effects/qsoundeffect_p.h new file mode 100644 index 000000000..93248184a --- /dev/null +++ b/src/multimedia/effects/qsoundeffect_p.h @@ -0,0 +1,143 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSOUNDEFFECT_P_H +#define QSOUNDEFFECT_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <qtmultimediadefs.h> +#include <QtCore/qobject.h> +#include <QtCore/qurl.h> +#include <QtCore/qstringlist.h> + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + +class QSoundEffectPrivate; + +class Q_MULTIMEDIA_EXPORT QSoundEffect : public QObject +{ + Q_OBJECT + Q_CLASSINFO("DefaultMethod", "play()") + Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged) + Q_PROPERTY(int loops READ loopCount WRITE setLoopCount NOTIFY loopCountChanged) + Q_PROPERTY(qreal volume READ volume WRITE setVolume NOTIFY volumeChanged) + Q_PROPERTY(bool muted READ isMuted WRITE setMuted NOTIFY mutedChanged) + Q_PROPERTY(bool playing READ isPlaying NOTIFY playingChanged) + Q_PROPERTY(Status status READ status NOTIFY statusChanged) + Q_ENUMS(Loop) + Q_ENUMS(Status) + +public: + enum Loop + { + Infinite = -2, + }; + + enum Status + { + Null, + Loading, + Ready, + Error + }; + + explicit QSoundEffect(QObject *parent = 0); + ~QSoundEffect(); + + static QStringList supportedMimeTypes(); + + QUrl source() const; + void setSource(const QUrl &url); + + int loopCount() const; + void setLoopCount(int loopCount); + + qreal volume() const; + void setVolume(qreal volume); + + bool isMuted() const; + void setMuted(bool muted); + + bool isLoaded() const; + + bool isPlaying() const; + Status status() const; + +Q_SIGNALS: + void sourceChanged(); + void loopCountChanged(); + void volumeChanged(); + void mutedChanged(); + void loadedChanged(); + void playingChanged(); + void statusChanged(); + +public Q_SLOTS: + void play(); + void stop(); + +private: + Q_DISABLE_COPY(QSoundEffect) + QSoundEffectPrivate* d; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + + +#endif // QSOUNDEFFECT_H diff --git a/src/multimedia/effects/qsoundeffect_pulse_p.cpp b/src/multimedia/effects/qsoundeffect_pulse_p.cpp new file mode 100644 index 000000000..4570f8fd5 --- /dev/null +++ b/src/multimedia/effects/qsoundeffect_pulse_p.cpp @@ -0,0 +1,957 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// INTERNAL USE ONLY: Do NOT use for any other purpose. +// + +#include <QtCore/qcoreapplication.h> +#include <qaudioformat.h> +#include <QtNetwork> +#include <QTime> + +#include "qsoundeffect_pulse_p.h" + +#if defined(Q_WS_MAEMO_6) +#include <pulse/ext-stream-restore.h> +#endif + +#include <unistd.h> + +//#define QT_PA_DEBUG +#ifndef QTM_PULSEAUDIO_DEFAULTBUFFER +#define QT_PA_STREAM_BUFFER_SIZE_MAX (1024 * 64) //64KB is a trade-off for balancing control latency and uploading overhead +#endif + +QT_BEGIN_NAMESPACE + +namespace +{ +inline pa_sample_spec audioFormatToSampleSpec(const QAudioFormat &format) +{ + pa_sample_spec spec; + + spec.rate = format.frequency(); + spec.channels = format.channels(); + + if (format.sampleSize() == 8) + spec.format = PA_SAMPLE_U8; + else if (format.sampleSize() == 16) { + switch (format.byteOrder()) { + case QAudioFormat::BigEndian: spec.format = PA_SAMPLE_S16BE; break; + case QAudioFormat::LittleEndian: spec.format = PA_SAMPLE_S16LE; break; + } + } + else if (format.sampleSize() == 32) { + switch (format.byteOrder()) { + case QAudioFormat::BigEndian: spec.format = PA_SAMPLE_S32BE; break; + case QAudioFormat::LittleEndian: spec.format = PA_SAMPLE_S32LE; break; + } + } + + return spec; +} + +class PulseDaemon : public QObject +{ + Q_OBJECT +public: + PulseDaemon(): m_prepared(false) + { + prepare(); + } + + ~PulseDaemon() + { + if (m_prepared) + release(); + } + + inline void lock() + { + pa_threaded_mainloop_lock(m_mainLoop); + } + + inline void unlock() + { + pa_threaded_mainloop_unlock(m_mainLoop); + } + + inline pa_context *context() const + { + return m_context; + } + + inline pa_cvolume * calcVolume(pa_cvolume *dest, int soundEffectVolume) + { + dest->channels = 2; + dest->values[0] = dest->values[1] = m_vol * soundEffectVolume / 100; + return dest; + } + + void updateStatus(const pa_cvolume& volume) + { + if (m_vol != pa_cvolume_max(&volume)) { + m_vol = pa_cvolume_max(&volume); + emit volumeChanged(); + } + } + +Q_SIGNALS: + void contextReady(); + void volumeChanged(); + +private: + void prepare() + { + m_vol = PA_VOLUME_NORM; + + m_mainLoop = pa_threaded_mainloop_new(); + if (m_mainLoop == 0) { + qWarning("PulseAudioService: unable to create pulseaudio mainloop"); + return; + } + + if (pa_threaded_mainloop_start(m_mainLoop) != 0) { + qWarning("PulseAudioService: unable to start pulseaudio mainloop"); + pa_threaded_mainloop_free(m_mainLoop); + return; + } + + m_mainLoopApi = pa_threaded_mainloop_get_api(m_mainLoop); + + lock(); + m_context = pa_context_new(m_mainLoopApi, QString(QLatin1String("QtPulseAudio:%1")).arg(::getpid()).toAscii().constData()); + + pa_context_set_state_callback(m_context, context_state_callback, this); + + if (m_context == 0) { + qWarning("PulseAudioService: Unable to create new pulseaudio context"); + pa_threaded_mainloop_free(m_mainLoop); + return; + } + + if (pa_context_connect(m_context, 0, (pa_context_flags_t)0, 0) < 0) { + qWarning("PulseAudioService: pa_context_connect() failed"); + pa_context_unref(m_context); + pa_threaded_mainloop_free(m_mainLoop); + return; + } + unlock(); + + m_prepared = true; + } + + void release() + { + if (!m_prepared) return; + pa_threaded_mainloop_stop(m_mainLoop); + pa_threaded_mainloop_free(m_mainLoop); + m_prepared = false; + } + + static void context_state_callback(pa_context *c, void *userdata) + { + PulseDaemon *self = reinterpret_cast<PulseDaemon*>(userdata); + switch (pa_context_get_state(c)) { + case PA_CONTEXT_CONNECTING: + case PA_CONTEXT_AUTHORIZING: + case PA_CONTEXT_SETTING_NAME: + break; + case PA_CONTEXT_READY: + #if defined(Q_WS_MAEMO_6) + pa_ext_stream_restore_read(c, &stream_restore_info_callback, self); + pa_ext_stream_restore_set_subscribe_cb(c, &stream_restore_monitor_callback, self); + pa_ext_stream_restore_subscribe(c, 1, 0, self); + #endif + QMetaObject::invokeMethod(self, "contextReady", Qt::QueuedConnection); + break; + default: + break; + } + } + +#if defined(Q_WS_MAEMO_6) + + static void stream_restore_monitor_callback(pa_context *c, void *userdata) + { + PulseDaemon *self = reinterpret_cast<PulseDaemon*>(userdata); + pa_ext_stream_restore_read(c, &stream_restore_info_callback, self); + } + + static void stream_restore_info_callback(pa_context *c, + const pa_ext_stream_restore_info *info, + int eol, void *userdata) + { + Q_UNUSED(c) + + PulseDaemon *self = reinterpret_cast<PulseDaemon*>(userdata); + + if (!eol) { + if (QString(info->name).startsWith(QLatin1String("sink-input-by-media-role:x-maemo"))) { +#ifdef QT_PA_DEBUG + qDebug() << "x-maemo volume =(" << info->volume.values[0] * 100 / PA_VOLUME_NORM << "," + << info->volume.values[1] * 100 / PA_VOLUME_NORM << "), " + << "mute = " << info->mute; +#endif + self->updateStatus(info->volume); + } + } + } +#endif + + pa_volume_t m_vol; + + bool m_prepared; + pa_context *m_context; + pa_threaded_mainloop *m_mainLoop; + pa_mainloop_api *m_mainLoopApi; +}; + +} + +Q_GLOBAL_STATIC(PulseDaemon, daemon) +Q_GLOBAL_STATIC(QSampleCache, sampleCache) + +namespace +{ +class PulseDaemonLocker +{ +public: + PulseDaemonLocker() + { + daemon()->lock(); + } + + ~PulseDaemonLocker() + { + daemon()->unlock(); + } +}; +} + +QSoundEffectPrivate::QSoundEffectPrivate(QObject* parent): + QObject(parent), + m_pulseStream(0), + m_sinkInputId(-1), + m_emptying(false), + m_sampleReady(false), + m_playing(false), + m_status(QSoundEffect::Null), + m_muted(false), + m_playQueued(false), + m_stopping(false), + m_volume(100), + m_loopCount(1), + m_runningCount(0), + m_sample(0) , + m_position(0) +{ + pa_sample_spec_init(&m_pulseSpec); +} + +QSoundEffectPrivate::~QSoundEffectPrivate() +{ + unloadPulseStream(); + + if (m_sample) + m_sample->release(); +} + +QStringList QSoundEffectPrivate::supportedMimeTypes() +{ + QStringList supportedTypes; + supportedTypes << QLatin1String("audio/x-wav") << QLatin1String("audio/vnd.wave") ; + return supportedTypes; +} + +QUrl QSoundEffectPrivate::source() const +{ + return m_source; +} + +void QSoundEffectPrivate::setSource(const QUrl &url) +{ + Q_ASSERT(m_source != url); +#ifdef QT_PA_DEBUG + qDebug() << this << "setSource =" << url; +#endif + stop(); + if (m_sample) { + if (!m_sampleReady) { + disconnect(m_sample, SIGNAL(error()), this, SLOT(decoderError())); + disconnect(m_sample, SIGNAL(ready()), this, SLOT(sampleReady())); + } + m_sample->release(); + m_sample = 0; + } + + m_source = url; + m_sampleReady = false; + + PulseDaemonLocker locker; + m_runningCount = 0; + if (m_pulseStream && !pa_stream_is_corked(m_pulseStream)) { + pa_stream_set_write_callback(m_pulseStream, 0, 0); + pa_stream_set_underflow_callback(m_pulseStream, 0, 0); + pa_operation_unref(pa_stream_cork(m_pulseStream, 1, 0, 0)); + } + setPlaying(false); + + if (url.isEmpty()) { + setStatus(QSoundEffect::Null); + return; + } + + setStatus(QSoundEffect::Loading); + m_sample = sampleCache()->requestSample(url); + connect(m_sample, SIGNAL(error()), this, SLOT(decoderError())); + connect(m_sample, SIGNAL(ready()), this, SLOT(sampleReady())); + switch(m_sample->state()) { + case QSample::Ready: + sampleReady(); + break; + case QSample::Error: + decoderError(); + break; + default: + break; + } +} + +int QSoundEffectPrivate::loopCount() const +{ + return m_loopCount; +} + +void QSoundEffectPrivate::setLoopCount(int loopCount) +{ + if (loopCount == 0) + loopCount = 1; + m_loopCount = loopCount; +} + +int QSoundEffectPrivate::volume() const +{ + return m_volume; +} + +void QSoundEffectPrivate::setVolume(int volume) +{ + m_volume = volume; + emit volumeChanged(); + updateVolume(); +} + +void QSoundEffectPrivate::updateVolume() +{ + if (m_sinkInputId < 0) + return; + PulseDaemonLocker locker; + pa_cvolume volume; + pa_operation_unref(pa_context_set_sink_input_volume(daemon()->context(), m_sinkInputId, daemon()->calcVolume(&volume, m_volume), setvolume_callback, this)); + Q_ASSERT(pa_cvolume_valid(&volume)); +#ifdef QT_PA_DEBUG + qDebug() << this << "updateVolume =" << pa_cvolume_max(&volume); +#endif +} + +bool QSoundEffectPrivate::isMuted() const +{ + return m_muted; +} + +void QSoundEffectPrivate::setMuted(bool muted) +{ + m_muted = muted; + emit mutedChanged(); + updateMuted(); +} + +void QSoundEffectPrivate::updateMuted() +{ + if (m_sinkInputId < 0) + return; + PulseDaemonLocker locker; + pa_operation_unref(pa_context_set_sink_input_mute(daemon()->context(), m_sinkInputId, m_muted, setmuted_callback, this)); +#ifdef QT_PA_DEBUG + qDebug() << this << "updateMuted = " << daemon()->calcMuted(m_muted); +#endif +} + +bool QSoundEffectPrivate::isLoaded() const +{ + return m_status == QSoundEffect::Ready; +} + +bool QSoundEffectPrivate::isPlaying() const +{ + return m_playing; +} + +QSoundEffect::Status QSoundEffectPrivate::status() const +{ + return m_status; +} + +void QSoundEffectPrivate::setPlaying(bool playing) +{ +#ifdef QT_PA_DEBUG + qDebug() << this << "setPlaying(" << playing << ")"; +#endif + if (m_playing == playing) + return; + if (!playing) + m_playQueued = false; + m_playing = playing; + emit playingChanged(); +} + +void QSoundEffectPrivate::setStatus(QSoundEffect::Status status) +{ +#ifdef QT_PA_DEBUG + qDebug() << this << "setStatus" << status; +#endif + if (m_status == status) + return; + bool oldLoaded = isLoaded(); + m_status = status; + emit statusChanged(); + if (oldLoaded != isLoaded()) + emit loadedChanged(); +} + +void QSoundEffectPrivate::play() +{ +#ifdef QT_PA_DEBUG + qDebug() << this << "play"; +#endif + if (m_status == QSoundEffect::Null || m_status == QSoundEffect::Error || m_playQueued) + return; + + PulseDaemonLocker locker; + if (!m_sampleReady || m_stopping || m_emptying) { +#ifdef QT_PA_DEBUG + qDebug() << this << "play deferred"; +#endif + m_playQueued = true; + } else { + if (m_playing) { //restart playing from the beginning +#ifdef QT_PA_DEBUG + qDebug() << this << "restart playing"; +#endif + m_runningCount = 0; + m_playQueued = true; + Q_ASSERT(m_pulseStream); + emptyStream(); + return; + } + m_runningCount = m_loopCount; + playSample(); + } + + setPlaying(true); +} + +void QSoundEffectPrivate::emptyStream() +{ + m_emptying = true; + pa_stream_set_write_callback(m_pulseStream, 0, this); + pa_stream_set_underflow_callback(m_pulseStream, 0, this); + pa_operation_unref(pa_stream_flush(m_pulseStream, stream_flush_callback, this)); +} + +void QSoundEffectPrivate::emptyComplete() +{ + PulseDaemonLocker locker; + m_emptying = false; + pa_operation_unref(pa_stream_cork(m_pulseStream, 1, stream_cork_callback, this)); +} + +void QSoundEffectPrivate::sampleReady() +{ +#ifdef QT_PA_DEBUG + qDebug() << this << "sampleReady"; +#endif + disconnect(m_sample, SIGNAL(error()), this, SLOT(decoderError())); + disconnect(m_sample, SIGNAL(ready()), this, SLOT(sampleReady())); + pa_sample_spec newFormatSpec = audioFormatToSampleSpec(m_sample->format()); + + if (m_pulseStream && (memcmp(&m_pulseSpec, &newFormatSpec, sizeof(m_pulseSpec)) != 0)) { + unloadPulseStream(); + } + m_pulseSpec = newFormatSpec; + + m_sampleReady = true; + m_position = 0; + + if (m_name.isNull()) + m_name = QString(QLatin1String("QtPulseSample-%1-%2")).arg(::getpid()).arg(quintptr(this)).toUtf8(); + + PulseDaemonLocker locker; + if (m_pulseStream) { +#ifdef QT_PA_DEBUG + qDebug() << this << "reuse existing pulsestream"; +#endif +#ifdef QTM_PULSEAUDIO_DEFAULTBUFFER + const pa_buffer_attr *bufferAttr = pa_stream_get_buffer_attr(m_pulseStream); + if (bufferAttr->prebuf > uint32_t(m_sample->data().size())) { + pa_buffer_attr newBufferAttr; + newBufferAttr = *bufferAttr; + newBufferAttr.prebuf = m_sample->data().size(); + pa_stream_set_buffer_attr(m_pulseStream, &newBufferAttr, stream_adjust_prebuffer_callback, this); + } else { + streamReady(); + } +#else + const pa_buffer_attr *bufferAttr = pa_stream_get_buffer_attr(m_pulseStream); + if (bufferAttr->tlength < m_sample->data().size() && bufferAttr->tlength < QT_PA_STREAM_BUFFER_SIZE_MAX) { + pa_buffer_attr newBufferAttr; + newBufferAttr.maxlength = -1; + newBufferAttr.tlength = qMin(m_sample->data().size(), QT_PA_STREAM_BUFFER_SIZE_MAX); + newBufferAttr.minreq = bufferAttr->tlength / 2; + newBufferAttr.prebuf = -1; + newBufferAttr.fragsize = -1; + pa_stream_set_buffer_attr(m_pulseStream, &newBufferAttr, stream_reset_buffer_callback, this); + } else if (bufferAttr->prebuf > uint32_t(m_sample->data().size())) { + pa_buffer_attr newBufferAttr; + newBufferAttr = *bufferAttr; + newBufferAttr.prebuf = m_sample->data().size(); + pa_stream_set_buffer_attr(m_pulseStream, &newBufferAttr, stream_adjust_prebuffer_callback, this); + } else { + streamReady(); + } +#endif + } else { + if (pa_context_get_state(daemon()->context()) != PA_CONTEXT_READY) { + connect(daemon(), SIGNAL(contextReady()), SLOT(contextReady())); + return; + } + createPulseStream(); + } +} + +void QSoundEffectPrivate::decoderError() +{ + qWarning("QSoundEffect(pulseaudio): Error decoding source"); + disconnect(m_sample, SIGNAL(error()), this, SLOT(decoderError())); + bool playingDirty = false; + if (m_playing) { + m_playing = false; + playingDirty = true; + } + setStatus(QSoundEffect::Error); + if (playingDirty) + emit playingChanged(); +} + +void QSoundEffectPrivate::unloadPulseStream() +{ +#ifdef QT_PA_DEBUG + qDebug() << this << "unloadPulseStream"; +#endif + m_sinkInputId = -1; + PulseDaemonLocker locker; + if (m_pulseStream) { + pa_stream_set_state_callback(m_pulseStream, 0, 0); + pa_stream_set_write_callback(m_pulseStream, 0, 0); + pa_stream_set_underflow_callback(m_pulseStream, 0, 0); + pa_stream_disconnect(m_pulseStream); + pa_stream_unref(m_pulseStream); + disconnect(daemon(), SIGNAL(volumeChanged()), this, SLOT(updateVolume())); + m_pulseStream = 0; + } +} + +void QSoundEffectPrivate::prepare() +{ + if (!m_pulseStream || !m_sampleReady) + return; + PulseDaemonLocker locker; + pa_stream_set_write_callback(m_pulseStream, stream_write_callback, this); + pa_stream_set_underflow_callback(m_pulseStream, stream_underrun_callback, this); + m_stopping = false; + size_t writeBytes = size_t(qMin(m_pulseBufferSize, m_sample->data().size())); +#ifdef QT_PA_DEBUG + qDebug() << this << "prepare(): writable size =" << pa_stream_writable_size(m_pulseStream) + << "actual writeBytes =" << writeBytes + << "m_playQueued =" << m_playQueued; +#endif + m_position = int(writeBytes); + if (pa_stream_write(m_pulseStream, reinterpret_cast<void *>(const_cast<char*>(m_sample->data().data())), writeBytes, + stream_write_done_callback, 0, PA_SEEK_RELATIVE) != 0) { + qWarning("QSoundEffect(pulseaudio): pa_stream_write, error = %s", pa_strerror(pa_context_errno(daemon()->context()))); + } + if (m_playQueued) { + m_playQueued = false; + m_runningCount = m_loopCount; + playSample(); + } +} + +void QSoundEffectPrivate::uploadSample() +{ + if (m_runningCount == 0) { +#ifdef QT_PA_DEBUG + qDebug() << this << "uploadSample: return due to 0 m_runningCount"; +#endif + return; + } +#ifdef QT_PA_DEBUG + qDebug() << this << "uploadSample: m_runningCount =" << m_runningCount; +#endif + if (m_position == m_sample->data().size()) { + m_position = 0; + if (m_runningCount > 0) + m_runningCount--; + if (m_runningCount == 0) { + return; + } + } + + int writtenBytes = 0; + int writableSize = int(pa_stream_writable_size(m_pulseStream)); + int firstPartLength = qMin(m_sample->data().size() - m_position, writableSize); + if (pa_stream_write(m_pulseStream, reinterpret_cast<void *>(const_cast<char*>(m_sample->data().data()) + m_position), + firstPartLength, stream_write_done_callback, 0, PA_SEEK_RELATIVE) != 0) { + qWarning("QSoundEffect(pulseaudio): pa_stream_write, error = %s", pa_strerror(pa_context_errno(daemon()->context()))); + } + writtenBytes = firstPartLength; + m_position += firstPartLength; + if (m_position == m_sample->data().size()) { + m_position = 0; + if (m_runningCount > 0) + m_runningCount--; + if (m_runningCount != 0 && firstPartLength < writableSize) + { + while (writtenBytes < writableSize) { + int writeSize = qMin(writableSize - writtenBytes, m_sample->data().size()); + if (pa_stream_write(m_pulseStream, reinterpret_cast<void *>(const_cast<char*>(m_sample->data().data())), + writeSize, stream_write_done_callback, 0, PA_SEEK_RELATIVE) != 0) { + qWarning("QSoundEffect(pulseaudio): pa_stream_write, error = %s", pa_strerror(pa_context_errno(daemon()->context()))); + } + writtenBytes += writeSize; + if (writeSize < m_sample->data().size()) { + m_position = writeSize; + break; + } + if (m_runningCount > 0) + m_runningCount--; + if (m_runningCount == 0) + break; + } + } + } +#ifdef QT_PA_DEBUG + qDebug() << this << "uploadSample: use direct write, writeable size =" << writableSize + << "actual writtenBytes =" << writtenBytes; +#endif +} + +void QSoundEffectPrivate::playSample() +{ +#ifdef QT_PA_DEBUG + qDebug() << this << "playSample"; +#endif + Q_ASSERT(m_pulseStream); + pa_operation_unref(pa_stream_cork(m_pulseStream, 0, 0, 0)); +} + +void QSoundEffectPrivate::stop() +{ +#ifdef QT_PA_DEBUG + qDebug() << this << "stop"; +#endif + if (!m_playing) + return; + setPlaying(false); + PulseDaemonLocker locker; + m_stopping = true; + if (m_pulseStream) + emptyStream(); + m_runningCount = 0; + m_position = 0; + m_playQueued = false; +} + +void QSoundEffectPrivate::underRun() +{ + stop(); +} + +void QSoundEffectPrivate::streamReady() +{ +#ifdef QT_PA_DEBUG + qDebug() << this << "streamReady"; +#endif + PulseDaemonLocker locker; + m_sinkInputId = pa_stream_get_index(m_pulseStream); + updateMuted(); + updateVolume(); +#ifdef QT_PA_DEBUG + const pa_buffer_attr *realBufAttr = pa_stream_get_buffer_attr(m_pulseStream); + qDebug() << this << "m_sinkInputId =" << m_sinkInputId + << "tlength =" << realBufAttr->tlength << "maxlength =" << realBufAttr->maxlength + << "minreq = " << realBufAttr->minreq << "prebuf =" << realBufAttr->prebuf; +#endif + prepare(); + setStatus(QSoundEffect::Ready); +} + +void QSoundEffectPrivate::createPulseStream() +{ +#ifdef QT_PA_DEBUG + qDebug() << this << "createPulseStream"; +#endif + + pa_proplist *propList = pa_proplist_new(); + pa_proplist_sets(propList, PA_PROP_MEDIA_ROLE, "soundeffect"); + pa_stream *stream = pa_stream_new_with_proplist(daemon()->context(), m_name.constData(), &m_pulseSpec, 0, propList); + pa_proplist_free(propList); + + connect(daemon(), SIGNAL(volumeChanged()), this, SLOT(updateVolume())); + + if (stream == 0) { + qWarning("QSoundEffect(pulseaudio): Failed to create stream"); + m_pulseStream = 0; + setStatus(QSoundEffect::Error); + setPlaying(false); + return; + } + else { + pa_stream_set_state_callback(stream, stream_state_callback, this); + pa_stream_set_write_callback(stream, stream_write_callback, this); + pa_stream_set_underflow_callback(stream, stream_underrun_callback, this); + } + m_pulseStream = stream; + +#ifndef QTM_PULSEAUDIO_DEFAULTBUFFER + pa_buffer_attr bufferAttr; + bufferAttr.tlength = qMin(m_sample->data().size(), QT_PA_STREAM_BUFFER_SIZE_MAX); + bufferAttr.maxlength = -1; + bufferAttr.minreq = bufferAttr.tlength / 2; + bufferAttr.prebuf = -1; + bufferAttr.fragsize = -1; + if (pa_stream_connect_playback(m_pulseStream, 0, &bufferAttr, +#else + if (pa_stream_connect_playback(m_pulseStream, 0, 0, +#endif + m_muted ? pa_stream_flags_t(PA_STREAM_START_MUTED | PA_STREAM_START_CORKED) + : pa_stream_flags_t(PA_STREAM_START_UNMUTED | PA_STREAM_START_CORKED), + 0, 0) < 0) { + qWarning("QSoundEffect(pulseaudio): Failed to connect stream, error = %s", + pa_strerror(pa_context_errno(daemon()->context()))); + } +} + +void QSoundEffectPrivate::contextReady() +{ + disconnect(daemon(), SIGNAL(contextReady()), this, SLOT(contextReady())); + PulseDaemonLocker locker; + createPulseStream(); +} + +void QSoundEffectPrivate::stream_write_callback(pa_stream *s, size_t length, void *userdata) +{ + Q_UNUSED(length); + Q_UNUSED(s) + + QSoundEffectPrivate *self = reinterpret_cast<QSoundEffectPrivate*>(userdata); +#ifdef QT_PA_DEBUG + qDebug() << self << "stream_write_callback"; +#endif + self->uploadSample(); +} + +void QSoundEffectPrivate::stream_state_callback(pa_stream *s, void *userdata) +{ + QSoundEffectPrivate *self = reinterpret_cast<QSoundEffectPrivate*>(userdata); + switch (pa_stream_get_state(s)) { + case PA_STREAM_READY: + { +#ifdef QT_PA_DEBUG + qDebug() << self << "pulse stream ready"; +#endif + const pa_buffer_attr *bufferAttr = pa_stream_get_buffer_attr(self->m_pulseStream); + self->m_pulseBufferSize = bufferAttr->tlength; + if (bufferAttr->prebuf > uint32_t(self->m_sample->data().size())) { + pa_buffer_attr newBufferAttr; + newBufferAttr = *bufferAttr; + newBufferAttr.prebuf = self->m_sample->data().size(); + pa_stream_set_buffer_attr(self->m_pulseStream, &newBufferAttr, stream_adjust_prebuffer_callback, userdata); + } else { + QMetaObject::invokeMethod(self, "streamReady", Qt::QueuedConnection); + } + break; + } + case PA_STREAM_CREATING: +#ifdef QT_PA_DEBUG + qDebug() << self << "pulse stream creating"; +#endif + break; + case PA_STREAM_TERMINATED: +#ifdef QT_PA_DEBUG + qDebug() << self << "pulse stream terminated"; +#endif + break; + + case PA_STREAM_FAILED: + default: + qWarning("QSoundEffect(pulseaudio): Error in pulse audio stream"); + break; + } +} + +void QSoundEffectPrivate::stream_reset_buffer_callback(pa_stream *s, int success, void *userdata) +{ + Q_UNUSED(s); + if (!success) + qWarning("QSoundEffect(pulseaudio): faild to reset buffer attribute"); + QSoundEffectPrivate *self = reinterpret_cast<QSoundEffectPrivate*>(userdata); +#ifdef QT_PA_DEBUG + qDebug() << self << "stream_reset_buffer_callback"; +#endif + const pa_buffer_attr *bufferAttr = pa_stream_get_buffer_attr(self->m_pulseStream); + self->m_pulseBufferSize = bufferAttr->tlength; + if (bufferAttr->prebuf > uint32_t(self->m_sample->data().size())) { + pa_buffer_attr newBufferAttr; + newBufferAttr = *bufferAttr; + newBufferAttr.prebuf = self->m_sample->data().size(); + pa_stream_set_buffer_attr(self->m_pulseStream, &newBufferAttr, stream_adjust_prebuffer_callback, userdata); + } else { + QMetaObject::invokeMethod(self, "streamReady", Qt::QueuedConnection); + } +} + +void QSoundEffectPrivate::stream_adjust_prebuffer_callback(pa_stream *s, int success, void *userdata) +{ + Q_UNUSED(s); + if (!success) + qWarning("QSoundEffect(pulseaudio): faild to adjust pre-buffer attribute"); + QSoundEffectPrivate *self = reinterpret_cast<QSoundEffectPrivate*>(userdata); +#ifdef QT_PA_DEBUG + qDebug() << self << "stream_adjust_prebuffer_callback"; +#endif + QMetaObject::invokeMethod(self, "streamReady", Qt::QueuedConnection); +} + +void QSoundEffectPrivate::setvolume_callback(pa_context *c, int success, void *userdata) +{ + Q_UNUSED(c); + Q_UNUSED(userdata); +#ifdef QT_PA_DEBUG + qDebug() << reinterpret_cast<QSoundEffectPrivate*>(userdata) << "setvolume_callback"; +#endif + if (!success) { + qWarning("QSoundEffect(pulseaudio): faild to set volume"); + } +} + +void QSoundEffectPrivate::setmuted_callback(pa_context *c, int success, void *userdata) +{ + Q_UNUSED(c); + Q_UNUSED(userdata); +#ifdef QT_PA_DEBUG + qDebug() << reinterpret_cast<QSoundEffectPrivate*>(userdata) << "setmuted_callback"; +#endif + if (!success) { + qWarning("QSoundEffect(pulseaudio): faild to set muted"); + } +} + +void QSoundEffectPrivate::stream_underrun_callback(pa_stream *s, void *userdata) +{ + Q_UNUSED(s); + QSoundEffectPrivate *self = reinterpret_cast<QSoundEffectPrivate*>(userdata); +#ifdef QT_PA_DEBUG + qDebug() << self << "stream_underrun_callback"; +#endif + if (self->m_runningCount == 0 && !self->m_playQueued) + QMetaObject::invokeMethod(self, "underRun", Qt::QueuedConnection); +#ifdef QT_PA_DEBUG + else + qDebug() << "underun corked =" << pa_stream_is_corked(s); +#endif +} + +void QSoundEffectPrivate::stream_cork_callback(pa_stream *s, int success, void *userdata) +{ + Q_UNUSED(s); + if (!success) + qWarning("QSoundEffect(pulseaudio): faild to stop"); + QSoundEffectPrivate *self = reinterpret_cast<QSoundEffectPrivate*>(userdata); +#ifdef QT_PA_DEBUG + qDebug() << self << "stream_cork_callback"; +#endif + QMetaObject::invokeMethod(self, "prepare", Qt::QueuedConnection); +} + +void QSoundEffectPrivate::stream_flush_callback(pa_stream *s, int success, void *userdata) +{ + Q_UNUSED(s); + if (!success) + qWarning("QSoundEffect(pulseaudio): faild to drain"); + QSoundEffectPrivate *self = reinterpret_cast<QSoundEffectPrivate*>(userdata); +#ifdef QT_PA_DEBUG + qDebug() << self << "stream_flush_callback"; +#endif + QMetaObject::invokeMethod(self, "emptyComplete", Qt::QueuedConnection); +} + +void QSoundEffectPrivate::stream_write_done_callback(void *p) +{ + Q_UNUSED(p); +#ifdef QT_PA_DEBUG + qDebug() << "stream_write_done_callback"; +#endif +} + +QT_END_NAMESPACE + +#include "moc_qsoundeffect_pulse_p.cpp" +#include "qsoundeffect_pulse_p.moc" diff --git a/src/multimedia/effects/qsoundeffect_pulse_p.h b/src/multimedia/effects/qsoundeffect_pulse_p.h new file mode 100644 index 000000000..c78bcdec5 --- /dev/null +++ b/src/multimedia/effects/qsoundeffect_pulse_p.h @@ -0,0 +1,163 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSOUNDEFFECT_PULSE_H +#define QSOUNDEFFECT_PULSE_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + + +#include "qsoundeffect_p.h" + +#include <QtCore/qobject.h> +#include <QtCore/qdatetime.h> +#include <qmediaplayer.h> +#include <pulse/pulseaudio.h> +#include "qsamplecache_p.h" + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + +class QSoundEffectPrivate : public QObject +{ + Q_OBJECT +public: + explicit QSoundEffectPrivate(QObject* parent); + ~QSoundEffectPrivate(); + + static QStringList supportedMimeTypes(); + + QUrl source() const; + void setSource(const QUrl &url); + int loopCount() const; + void setLoopCount(int loopCount); + int volume() const; + void setVolume(int volume); + bool isMuted() const; + void setMuted(bool muted); + bool isLoaded() const; + bool isPlaying() const; + QSoundEffect::Status status() const; + +public Q_SLOTS: + void play(); + void stop(); + +Q_SIGNALS: + void volumeChanged(); + void mutedChanged(); + void loadedChanged(); + void playingChanged(); + void statusChanged(); + +private Q_SLOTS: + void decoderError(); + void sampleReady(); + void uploadSample(); + void contextReady(); + void underRun(); + void prepare(); + void streamReady(); + void emptyComplete(); + void updateVolume(); + void updateMuted(); + +private: + void playSample(); + + void emptyStream(); + void createPulseStream(); + void unloadPulseStream(); + + void setPlaying(bool playing); + void setStatus(QSoundEffect::Status status); + + static void stream_write_callback(pa_stream *s, size_t length, void *userdata); + static void stream_state_callback(pa_stream *s, void *userdata); + static void stream_underrun_callback(pa_stream *s, void *userdata); + static void stream_cork_callback(pa_stream *s, int success, void *userdata); + static void stream_flush_callback(pa_stream *s, int success, void *userdata); + static void stream_write_done_callback(void *p); + static void stream_adjust_prebuffer_callback(pa_stream *s, int success, void *userdata); + static void stream_reset_buffer_callback(pa_stream *s, int success, void *userdata); + static void setvolume_callback(pa_context *c, int success, void *userdata); + static void setmuted_callback(pa_context *c, int success, void *userdata); + + pa_stream *m_pulseStream; + int m_sinkInputId; + pa_sample_spec m_pulseSpec; + int m_pulseBufferSize; + + bool m_emptying; + bool m_sampleReady; + bool m_playing; + QSoundEffect::Status m_status; + bool m_muted; + bool m_playQueued; + bool m_stopping; + int m_volume; + int m_loopCount; + int m_runningCount; + QUrl m_source; + QByteArray m_name; + + QSample *m_sample; + int m_position; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QSOUNDEFFECT_PULSE_H diff --git a/src/multimedia/effects/qsoundeffect_qmedia_p.cpp b/src/multimedia/effects/qsoundeffect_qmedia_p.cpp new file mode 100644 index 000000000..dfd56b09c --- /dev/null +++ b/src/multimedia/effects/qsoundeffect_qmedia_p.cpp @@ -0,0 +1,233 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// INTERNAL USE ONLY: Do NOT use for any other purpose. +// + +#include "qsoundeffect_qmedia_p.h" + +#include <QtCore/qcoreapplication.h> + +#include "qmediacontent.h" +#include "qmediaplayer.h" + + +QT_BEGIN_NAMESPACE + +QSoundEffectPrivate::QSoundEffectPrivate(QObject* parent): + QObject(parent), + m_loopCount(1), + m_runningCount(0), + m_player(0), + m_status(QSoundEffect::Null), + m_playing(false) +{ + m_player = new QMediaPlayer(this, QMediaPlayer::LowLatency); + connect(m_player, SIGNAL(stateChanged(QMediaPlayer::State)), SLOT(stateChanged(QMediaPlayer::State))); + connect(m_player, SIGNAL(mediaStatusChanged(QMediaPlayer::MediaStatus)), SLOT(mediaStatusChanged(QMediaPlayer::MediaStatus))); + connect(m_player, SIGNAL(error(QMediaPlayer::Error)), SLOT(error(QMediaPlayer::Error))); + connect(m_player, SIGNAL(mutedChanged(bool)), SIGNAL(mutedChanged())); + connect(m_player, SIGNAL(volumeChanged(int)), SIGNAL(volumeChanged())); +} + +QSoundEffectPrivate::~QSoundEffectPrivate() +{ +} + +QStringList QSoundEffectPrivate::supportedMimeTypes() +{ + return QMediaPlayer::supportedMimeTypes(); +} + +QUrl QSoundEffectPrivate::source() const +{ + return m_player->media().canonicalUrl(); +} + +void QSoundEffectPrivate::setSource(const QUrl &url) +{ + m_player->setMedia(url); +} + +int QSoundEffectPrivate::loopCount() const +{ + return m_loopCount; +} + +void QSoundEffectPrivate::setLoopCount(int loopCount) +{ + m_loopCount = loopCount; +} + +int QSoundEffectPrivate::volume() const +{ + return m_player->volume(); +} + +void QSoundEffectPrivate::setVolume(int volume) +{ + m_player->setVolume(volume); +} + +bool QSoundEffectPrivate::isMuted() const +{ + return m_player->isMuted(); +} + +void QSoundEffectPrivate::setMuted(bool muted) +{ + m_player->setMuted(muted); +} + +bool QSoundEffectPrivate::isLoaded() const +{ + return m_status == QSoundEffect::Ready; +} + +bool QSoundEffectPrivate::isPlaying() const +{ + return m_playing; +} + +QSoundEffect::Status QSoundEffectPrivate::status() const +{ + return m_status; +} + +void QSoundEffectPrivate::play() +{ + if (m_status == QSoundEffect::Null || m_status == QSoundEffect::Error) + return; + if (m_loopCount < 0) { + m_runningCount = -1; + } + else { + if (m_runningCount < 0) + m_runningCount = 0; + m_runningCount += m_loopCount; + } + m_player->play(); +} + +void QSoundEffectPrivate::stop() +{ + m_runningCount = 0; + m_player->stop(); +} + +void QSoundEffectPrivate::stateChanged(QMediaPlayer::State state) +{ + if (state == QMediaPlayer::StoppedState) { + if (m_runningCount < 0) { + m_player->play(); + } else if (m_runningCount == 0) { + setPlaying(false); + return; + } else if (--m_runningCount > 0) { + m_player->play(); + } else { + setPlaying(false); + } + } else { + setPlaying(true); + } +} + +void QSoundEffectPrivate::mediaStatusChanged(QMediaPlayer::MediaStatus status) +{ + switch(status) { + case QMediaPlayer::LoadingMedia: + setStatus(QSoundEffect::Loading); + break; + case QMediaPlayer::NoMedia: + setStatus(QSoundEffect::Null); + break; + case QMediaPlayer::InvalidMedia: + setStatus(QSoundEffect::Error); + break; + default: + setStatus(QSoundEffect::Ready); + break; + } +} + +void QSoundEffectPrivate::error(QMediaPlayer::Error err) +{ + bool playingDirty = false; + if (m_playing) { + m_playing = false; + playingDirty = true; + } + setStatus(QSoundEffect::Error); + if (playingDirty) + emit playingChanged(); +} + +void QSoundEffectPrivate::setStatus(QSoundEffect::Status status) +{ + if (m_status == status) + return; + bool oldLoaded = isLoaded(); + m_status = status; + emit statusChanged(); + if (oldLoaded != isLoaded()) + emit loadedChanged(); +} + +void QSoundEffectPrivate::setPlaying(bool playing) +{ + if (m_playing == playing) + return; + m_playing = playing; + emit playingChanged(); +} + +QT_END_NAMESPACE + +#include "moc_qsoundeffect_qmedia_p.cpp" diff --git a/src/multimedia/effects/qsoundeffect_qmedia_p.h b/src/multimedia/effects/qsoundeffect_qmedia_p.h new file mode 100644 index 000000000..adafa04a2 --- /dev/null +++ b/src/multimedia/effects/qsoundeffect_qmedia_p.h @@ -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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSOUNDEFFECT_QMEDIA_H +#define QSOUNDEFFECT_QMEDIA_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtCore/qobject.h> +#include <QtCore/qurl.h> +#include "qmediaplayer.h" +#include "qsoundeffect_p.h" + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + + +class QSoundEffectPrivate : public QObject +{ + Q_OBJECT +public: + + explicit QSoundEffectPrivate(QObject* parent); + ~QSoundEffectPrivate(); + + static QStringList supportedMimeTypes(); + + QUrl source() const; + void setSource(const QUrl &url); + int loopCount() const; + void setLoopCount(int loopCount); + int volume() const; + void setVolume(int volume); + bool isMuted() const; + void setMuted(bool muted); + bool isLoaded() const; + bool isPlaying() const; + QSoundEffect::Status status() const; + +public Q_SLOTS: + void play(); + void stop(); + +Q_SIGNALS: + void volumeChanged(); + void mutedChanged(); + void loadedChanged(); + void playingChanged(); + void statusChanged(); + +private Q_SLOTS: + void stateChanged(QMediaPlayer::State); + void mediaStatusChanged(QMediaPlayer::MediaStatus); + void error(QMediaPlayer::Error); + +private: + void setStatus(QSoundEffect::Status status); + void setPlaying(bool playing); + + int m_loopCount; + int m_runningCount; + bool m_playing; + QSoundEffect::Status m_status; + QMediaPlayer *m_player; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QSOUNDEFFECT_QMEDIA_H diff --git a/src/multimedia/effects/qsoundeffect_qsound_p.cpp b/src/multimedia/effects/qsoundeffect_qsound_p.cpp new file mode 100644 index 000000000..0b9082eb5 --- /dev/null +++ b/src/multimedia/effects/qsoundeffect_qsound_p.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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// INTERNAL USE ONLY: Do NOT use for any other purpose. +// + +#include "qsoundeffect_qsound_p.h" + +#include <QtCore/qcoreapplication.h> +#include <QtWidgets/qsound.h> +#include <QtCore/qstringlist.h> + + +QT_BEGIN_NAMESPACE + +QSoundEffectPrivate::QSoundEffectPrivate(QObject* parent): + QObject(parent), + m_playing(false), + m_timerID(0), + m_muted(false), + m_loopCount(1), + m_volume(100), + m_status(QSoundEffect::Null), + m_sound(0) +{ + if (!QSound::isAvailable()) + qWarning("SoundEffect(qsound) : not available"); +} + +QSoundEffectPrivate::~QSoundEffectPrivate() +{ +} + +QStringList QSoundEffectPrivate::supportedMimeTypes() +{ + QStringList supportedTypes; + supportedTypes << QLatin1String("audio/x-wav") << QLatin1String("audio/vnd.wave") ; + return supportedTypes; +} + +QUrl QSoundEffectPrivate::source() const +{ + return m_source; +} + +void QSoundEffectPrivate::setSource(const QUrl &url) +{ + if (url.isEmpty()) { + m_source = QUrl(); + setStatus(QSoundEffect::Null); + return; + } + + if (url.scheme() != QLatin1String("file")) { + m_source = url; + setStatus(QSoundEffect::Error); + return; + } + + if (m_sound != 0) + delete m_sound; + + m_source = url; + m_sound = new QSound(m_source.toLocalFile(), this); + m_sound->setLoops(m_loopCount); + m_status = QSoundEffect::Ready; + emit statusChanged(); + emit loadedChanged(); +} + +int QSoundEffectPrivate::loopCount() const +{ + return m_loopCount; +} + +void QSoundEffectPrivate::setLoopCount(int lc) +{ + m_loopCount = lc; + if (m_sound) + m_sound->setLoops(lc); +} + +int QSoundEffectPrivate::volume() const +{ + return m_volume; +} + +void QSoundEffectPrivate::setVolume(int v) +{ + m_volume = v; +} + +bool QSoundEffectPrivate::isMuted() const +{ + return m_muted; +} + +void QSoundEffectPrivate::setMuted(bool muted) +{ + m_muted = muted; +} + +bool QSoundEffectPrivate::isLoaded() const +{ + return m_status == QSoundEffect::Ready; +} + +void QSoundEffectPrivate::play() +{ + if (m_status == QSoundEffect::Null || m_status == QSoundEffect::Error) + return; + if (m_timerID != 0) + killTimer(m_timerID); + m_timerID = startTimer(500); + m_sound->play(); + setPlaying(true); +} + + +void QSoundEffectPrivate::stop() +{ + if (m_timerID != 0) + killTimer(m_timerID); + m_timerID = 0; + m_sound->stop(); + setPlaying(false); +} + +bool QSoundEffectPrivate::isPlaying() +{ + if (m_playing && m_sound && m_sound->isFinished()) { + if (m_timerID != 0) + killTimer(m_timerID); + m_timerID = 0; + setPlaying(false); + } + return m_playing; +} + +QSoundEffect::Status QSoundEffectPrivate::status() const +{ + return m_status; +} + +void QSoundEffectPrivate::timerEvent(QTimerEvent *event) +{ + Q_UNUSED(event); + setPlaying(!m_sound->isFinished()); + if (isPlaying()) + return; + killTimer(m_timerID); + m_timerID = 0; +} + +void QSoundEffectPrivate::setStatus(QSoundEffect::Status status) +{ + if (m_status == status) + return; + bool oldLoaded = isLoaded(); + m_status = status; + emit statusChanged(); + if (oldLoaded != isLoaded()) + emit loadedChanged(); +} + +void QSoundEffectPrivate::setPlaying(bool playing) +{ + if (m_playing == playing) + return; + m_playing = playing; + emit playingChanged(); +} + +QT_END_NAMESPACE + +#include "moc_qsoundeffect_qsound_p.cpp" diff --git a/src/multimedia/effects/qsoundeffect_qsound_p.h b/src/multimedia/effects/qsoundeffect_qsound_p.h new file mode 100644 index 000000000..c98ad79ce --- /dev/null +++ b/src/multimedia/effects/qsoundeffect_qsound_p.h @@ -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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSOUNDEFFECT_QSOUND_H +#define QSOUNDEFFECT_QSOUND_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + + +#include <QtCore/qobject.h> +#include <QtCore/qurl.h> +#include "qsoundeffect_p.h" + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + +class QSound; + +class QSoundEffectPrivate : public QObject +{ + Q_OBJECT +public: + explicit QSoundEffectPrivate(QObject* parent); + ~QSoundEffectPrivate(); + + static QStringList supportedMimeTypes(); + + QUrl source() const; + void setSource(const QUrl &url); + int loopCount() const; + void setLoopCount(int loopCount); + int volume() const; + void setVolume(int volume); + bool isMuted() const; + void setMuted(bool muted); + bool isLoaded() const; + bool isPlaying(); + QSoundEffect::Status status() const; + +public Q_SLOTS: + void play(); + void stop(); + +Q_SIGNALS: + void volumeChanged(); + void mutedChanged(); + void loadedChanged(); + void playingChanged(); + void statusChanged(); + +private: + void setStatus(QSoundEffect::Status status); + void setPlaying(bool playing); + void timerEvent(QTimerEvent *event); + + bool m_playing; + int m_timerID; + bool m_muted; + int m_loopCount; + int m_volume; + QSoundEffect::Status m_status; + QSound *m_sound; + QUrl m_source; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QSOUNDEFFECT_QSOUND_H diff --git a/src/multimedia/effects/qwavedecoder_p.cpp b/src/multimedia/effects/qwavedecoder_p.cpp new file mode 100644 index 000000000..19b262adc --- /dev/null +++ b/src/multimedia/effects/qwavedecoder_p.cpp @@ -0,0 +1,232 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwavedecoder_p.h" + +#include <QtCore/qtimer.h> +#include <QtCore/qendian.h> + +QT_BEGIN_NAMESPACE + +QWaveDecoder::QWaveDecoder(QIODevice *s, QObject *parent): + QIODevice(parent), + haveFormat(false), + dataSize(0), + remaining(0), + source(s), + state(QWaveDecoder::InitialState) +{ + open(QIODevice::ReadOnly | QIODevice::Unbuffered); + + if (enoughDataAvailable()) + QTimer::singleShot(0, this, SLOT(handleData())); + else + connect(source, SIGNAL(readyRead()), SLOT(handleData())); +} + +QWaveDecoder::~QWaveDecoder() +{ +} + +QAudioFormat QWaveDecoder::audioFormat() const +{ + return format; +} + +int QWaveDecoder::duration() const +{ + return size() * 1000 / (format.sampleSize() / 8) / format.channels() / format.frequency(); +} + +qint64 QWaveDecoder::size() const +{ + return haveFormat ? dataSize : 0; +} + +bool QWaveDecoder::isSequential() const +{ + return source->isSequential(); +} + +qint64 QWaveDecoder::bytesAvailable() const +{ + return haveFormat ? source->bytesAvailable() : 0; +} + +qint64 QWaveDecoder::readData(char *data, qint64 maxlen) +{ + return haveFormat ? source->read(data, maxlen) : 0; +} + +qint64 QWaveDecoder::writeData(const char *data, qint64 len) +{ + Q_UNUSED(data); + Q_UNUSED(len); + + return -1; +} + +void QWaveDecoder::handleData() +{ + if (state == QWaveDecoder::InitialState) { + if (source->bytesAvailable() < qint64(sizeof(RIFFHeader))) + return; + + RIFFHeader riff; + source->read(reinterpret_cast<char *>(&riff), sizeof(RIFFHeader)); + + if (qstrncmp(riff.descriptor.id, "RIFF", 4) != 0 || + qstrncmp(riff.type, "WAVE", 4) != 0) { + source->disconnect(SIGNAL(readyRead()), this, SLOT(handleData())); + emit invalidFormat(); + + return; + } else { + state = QWaveDecoder::WaitingForFormatState; + } + } + + if (state == QWaveDecoder::WaitingForFormatState) { + if (findChunk("fmt ")) { + chunk descriptor; + source->peek(reinterpret_cast<char *>(&descriptor), sizeof(chunk)); + + if (source->bytesAvailable() < qint64(descriptor.size + sizeof(chunk))) + return; + + WAVEHeader wave; + source->read(reinterpret_cast<char *>(&wave), sizeof(WAVEHeader)); + if (descriptor.size > sizeof(WAVEHeader)) + discardBytes(descriptor.size - sizeof(WAVEHeader)); + + if (wave.audioFormat != 0 && wave.audioFormat != 1) { + source->disconnect(SIGNAL(readyRead()), this, SLOT(handleData())); + emit invalidFormat(); + + return; + } else { + int bps = qFromLittleEndian<quint16>(wave.bitsPerSample); + + format.setCodec(QLatin1String("audio/pcm")); + format.setSampleType(bps == 8 ? QAudioFormat::UnSignedInt : QAudioFormat::SignedInt); + format.setByteOrder(QAudioFormat::LittleEndian); + format.setFrequency(qFromLittleEndian<quint32>(wave.sampleRate)); + format.setSampleSize(bps); + format.setChannels(qFromLittleEndian<quint16>(wave.numChannels)); + + state = QWaveDecoder::WaitingForDataState; + } + } + } + + if (state == QWaveDecoder::WaitingForDataState) { + if (findChunk("data")) { + source->disconnect(SIGNAL(readyRead()), this, SLOT(handleData())); + + chunk descriptor; + source->read(reinterpret_cast<char *>(&descriptor), sizeof(chunk)); + dataSize = descriptor.size; + + haveFormat = true; + connect(source, SIGNAL(readyRead()), SIGNAL(readyRead())); + emit formatKnown(); + + return; + } + } + + if (source->atEnd()) { + source->disconnect(SIGNAL(readyRead()), this, SLOT(handleData())); + emit invalidFormat(); + + return; + } + +} + +bool QWaveDecoder::enoughDataAvailable() +{ + if (source->bytesAvailable() < qint64(sizeof(chunk))) + return false; + + chunk descriptor; + source->peek(reinterpret_cast<char *>(&descriptor), sizeof(chunk)); + + if (source->bytesAvailable() < qint64(sizeof(chunk) + descriptor.size)) + return false; + + return true; +} + +bool QWaveDecoder::findChunk(const char *chunkId) +{ + if (source->bytesAvailable() < qint64(sizeof(chunk))) + return false; + + chunk descriptor; + source->peek(reinterpret_cast<char *>(&descriptor), sizeof(chunk)); + + if (qstrncmp(descriptor.id, chunkId, 4) == 0) + return true; + + while (source->bytesAvailable() >= qint64(sizeof(chunk) + descriptor.size)) { + discardBytes(sizeof(chunk) + descriptor.size); + + source->peek(reinterpret_cast<char *>(&descriptor), sizeof(chunk)); + + if (qstrncmp(descriptor.id, chunkId, 4) == 0) + return true; + } + + return false; +} + +void QWaveDecoder::discardBytes(qint64 numBytes) +{ + if (source->isSequential()) + source->read(numBytes); + else + source->seek(source->pos() + numBytes); +} + +QT_END_NAMESPACE + +#include "moc_qwavedecoder_p.cpp" diff --git a/src/multimedia/effects/qwavedecoder_p.h b/src/multimedia/effects/qwavedecoder_p.h new file mode 100644 index 000000000..6c4c00c25 --- /dev/null +++ b/src/multimedia/effects/qwavedecoder_p.h @@ -0,0 +1,137 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef WAVEDECODER_H +#define WAVEDECODER_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtCore/qiodevice.h> +#include <qaudioformat.h> + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + + +class QWaveDecoder : public QIODevice +{ + Q_OBJECT + +public: + explicit QWaveDecoder(QIODevice *source, QObject *parent = 0); + ~QWaveDecoder(); + + QAudioFormat audioFormat() const; + int duration() const; + + qint64 size() const; + bool isSequential() const; + qint64 bytesAvailable() const; + +Q_SIGNALS: + void formatKnown(); + void invalidFormat(); + +private Q_SLOTS: + void handleData(); + +private: + qint64 readData(char *data, qint64 maxlen); + qint64 writeData(const char *data, qint64 len); + + bool enoughDataAvailable(); + bool findChunk(const char *chunkId); + void discardBytes(qint64 numBytes); + + enum State { + InitialState, + WaitingForFormatState, + WaitingForDataState + }; + + struct chunk + { + char id[4]; + quint32 size; + }; + struct RIFFHeader + { + chunk descriptor; + char type[4]; + }; + struct WAVEHeader + { + chunk descriptor; + quint16 audioFormat; + quint16 numChannels; + quint32 sampleRate; + quint32 byteRate; + quint16 blockAlign; + quint16 bitsPerSample; + }; + + bool haveFormat; + qint64 dataSize; + qint64 remaining; + QAudioFormat format; + QIODevice *source; + State state; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // WAVEDECODER_H diff --git a/src/multimedia/multimedia.pro b/src/multimedia/multimedia.pro new file mode 100644 index 000000000..b955e71a0 --- /dev/null +++ b/src/multimedia/multimedia.pro @@ -0,0 +1,156 @@ +load(qt_module) + +TARGET = QtMultimedia +QPRO_PWD = $$PWD +QT = core network gui + +CONFIG += module +MODULE_PRI += ../../modules/qt_multimedia.pri + +contains(QT_CONFIG, opengl) | contains(QT_CONFIG, opengles2) { +} else { + DEFINES += QT_NO_OPENGL +} + +!static:DEFINES += QT_MAKEDLL +DEFINES += QT_BUILD_MULTIMEDIA_LIB + +load(qt_module_config) + +HEADERS += qtmultimediaversion.h + + +PRIVATE_HEADERS += \ + qmediacontrol_p.h \ + qmediaobject_p.h \ + qmediaservice_p.h \ + qmediaplaylist_p.h \ + qmediaplaylistprovider_p.h \ + qmediaimageviewerservice_p.h \ + qmediapluginloader_p.h \ + qvideosurfaceoutput_p.h + +PUBLIC_HEADERS += \ + qmediacontrol.h \ + qmediaobject.h \ + qmediaservice.h \ + qmediabindableinterface.h \ + qlocalmediaplaylistprovider.h \ + qmediaimageviewer.h \ + qmediaplayer.h \ + qmediaplayercontrol.h \ + qmediaplaylist.h \ + qmediaplaylistnavigator.h \ + qmediaplaylistprovider.h \ + qmediaplaylistioplugin.h \ + qmediabackgroundplaybackcontrol.h \ + qmediacontent.h \ + qmediaresource.h \ + qmediarecorder.h \ + qmediaencodersettings.h \ + qmediarecordercontrol.h \ + qmediaserviceprovider.h \ + qmediaserviceproviderplugin.h \ + qmetadatareadercontrol.h \ + qmetadatawritercontrol.h \ + qmediastreamscontrol.h \ + qradiotuner.h \ + qradiotunercontrol.h \ + qtmedianamespace.h \ + qaudioencodercontrol.h \ + qvideoencodercontrol.h \ + qimageencodercontrol.h \ + qaudiocapturesource.h \ + qmediacontainercontrol.h \ + qmediaplaylistcontrol.h \ + qmediaplaylistsourcecontrol.h \ + qaudioendpointselector.h \ + qvideodevicecontrol.h \ + qvideorenderercontrol.h \ + qmediatimerange.h \ + qmedianetworkaccesscontrol.h \ + qmediaenumdebug.h \ + qtmultimediadefs.h + +SOURCES += qmediacontrol.cpp \ + qmediaobject.cpp \ + qmediaservice.cpp \ + qmediabindableinterface.cpp \ + qlocalmediaplaylistprovider.cpp \ + qmediaimageviewer.cpp \ + qmediaimageviewerservice.cpp \ + qmediaplayer.cpp \ + qmediaplayercontrol.cpp \ + qmediaplaylist.cpp \ + qmediaplaylistioplugin.cpp \ + qmediaplaylistnavigator.cpp \ + qmediaplaylistprovider.cpp \ + qmediarecorder.cpp \ + qmediaencodersettings.cpp \ + qmediarecordercontrol.cpp \ + qmediacontent.cpp \ + qmediaresource.cpp \ + qmediaserviceprovider.cpp \ + qmetadatareadercontrol.cpp \ + qmetadatawritercontrol.cpp \ + qmediastreamscontrol.cpp \ + qradiotuner.cpp \ + qradiotunercontrol.cpp \ + qaudioencodercontrol.cpp \ + qvideoencodercontrol.cpp \ + qimageencodercontrol.cpp \ + qaudiocapturesource.cpp \ + qmediacontainercontrol.cpp \ + qmediaplaylistcontrol.cpp \ + qmediaplaylistsourcecontrol.cpp \ + qaudioendpointselector.cpp \ + qvideodevicecontrol.cpp \ + qmediapluginloader.cpp \ + qvideorenderercontrol.cpp \ + qmediatimerange.cpp \ + qmedianetworkaccesscontrol.cpp \ + qvideosurfaceoutput.cpp \ + qmediabackgroundplaybackcontrol.cpp + +#Camera +PUBLIC_HEADERS += \ + qcamera.h \ + qcameraimagecapture.h \ + qcameraimagecapturecontrol.h \ + qcameraexposure.h \ + qcamerafocus.h \ + qcameraimageprocessing.h \ + qcameracontrol.h \ + qcameralockscontrol.h \ + qcameraexposurecontrol.h \ + qcamerafocuscontrol.h \ + qcameraflashcontrol.h \ + qcameraimageprocessingcontrol.h \ + qcameracapturedestinationcontrol.h \ + qcameracapturebufferformatcontrol.h + +SOURCES += \ + qcamera.cpp \ + qcameraexposure.cpp \ + qcamerafocus.cpp \ + qcameraimageprocessing.cpp \ + qcameraimagecapture.cpp \ + qcameraimagecapturecontrol.cpp \ + qcameracontrol.cpp \ + qcameralockscontrol.cpp \ + qcameraexposurecontrol.cpp \ + qcamerafocuscontrol.cpp \ + qcameraflashcontrol.cpp \ + qcameraimageprocessingcontrol.cpp \ + qcameracapturedestinationcontrol.cpp \ + qcameracapturebufferformatcontrol.cpp + +include(audio/audio.pri) +include(video/video.pri) +include(effects/effects.pri) + +mac:!qpa { + LIBS += -framework AppKit -framework QuartzCore -framework QTKit +} + +HEADERS += $$PUBLIC_HEADERS $$PRIVATE_HEADERS diff --git a/src/multimedia/qaudiocapturesource.cpp b/src/multimedia/qaudiocapturesource.cpp new file mode 100644 index 000000000..469617123 --- /dev/null +++ b/src/multimedia/qaudiocapturesource.cpp @@ -0,0 +1,275 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmediaobject_p.h" +#include <qaudiocapturesource.h> +#include "qaudioendpointselector.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QAudioCaptureSource + \brief The QAudioCaptureSource class provides an interface to query and select an audio input endpoint. + \inmodule QtMultimedia + \ingroup multimedia + \since 1.0 + + QAudioCaptureSource provides access to the audio inputs available on your system. + + You can query these inputs and select one to use. + + A typical implementation example: + \snippet doc/src/snippets/multimedia-snippets/media.cpp Audio capture source + + The audiocapturesource interface is then used to: + + - Get and Set the audio input to use. + + The capture interface is then used to: + + - Set the destination using setOutputLocation() + + - Set the format parameters using setAudioCodec(), + + - Control the recording using record(),stop() + + \sa QMediaRecorder +*/ + +class QAudioCaptureSourcePrivate : public QMediaObjectPrivate +{ +public: + Q_DECLARE_PUBLIC(QAudioCaptureSource) + + void initControls() + { + Q_Q(QAudioCaptureSource); + + if (service != 0) + audioEndpointSelector = qobject_cast<QAudioEndpointSelector*>(service->requestControl(QAudioEndpointSelector_iid)); + + if (audioEndpointSelector) { + q->connect(audioEndpointSelector, SIGNAL(activeEndpointChanged(const QString&)), + SIGNAL(activeAudioInputChanged(const QString&))); + q->connect(audioEndpointSelector, SIGNAL(availableEndpointsChanged()), + SIGNAL(availableAudioInputsChanged())); + q->connect(audioEndpointSelector, SIGNAL(availableEndpointsChanged()), + SLOT(statusChanged())); + errorState = QtMultimedia::NoError; + } + } + + QAudioCaptureSourcePrivate():provider(0), audioEndpointSelector(0), errorState(QtMultimedia::ServiceMissingError) {} + QMediaServiceProvider *provider; + QAudioEndpointSelector *audioEndpointSelector; + QtMultimedia::AvailabilityError errorState; +}; + +/*! + Construct a QAudioCaptureSource using the QMediaService from \a provider, with \a parent. + \since 1.0 +*/ + +QAudioCaptureSource::QAudioCaptureSource(QObject *parent, QMediaServiceProvider *provider): + QMediaObject(*new QAudioCaptureSourcePrivate, parent, provider->requestService(Q_MEDIASERVICE_AUDIOSOURCE)) +{ + Q_D(QAudioCaptureSource); + + d->provider = provider; + d->initControls(); +} + +/*! + Destroys the audiocapturesource object. +*/ + +QAudioCaptureSource::~QAudioCaptureSource() +{ + Q_D(QAudioCaptureSource); + + if (d->service && d->audioEndpointSelector) + d->service->releaseControl(d->audioEndpointSelector); + + if (d->provider) + d->provider->releaseService(d->service); +} + +/*! + Returns the error state of the audio capture service. + \since 1.0 +*/ + +QtMultimedia::AvailabilityError QAudioCaptureSource::availabilityError() const +{ + Q_D(const QAudioCaptureSource); + + return d->errorState; +} + +/*! + Returns true if the audio capture service is available, otherwise returns false. + \since 1.0 +*/ +bool QAudioCaptureSource::isAvailable() const +{ + Q_D(const QAudioCaptureSource); + + if (d->service != NULL) { + if (d->audioEndpointSelector && d->audioEndpointSelector->availableEndpoints().size() > 0) + return true; + } + return false; +} + + +/*! + Returns a list of available audio inputs + \since 1.0 +*/ + +QList<QString> QAudioCaptureSource::audioInputs() const +{ + Q_D(const QAudioCaptureSource); + + QList<QString> list; + if (d && d->audioEndpointSelector) + list <<d->audioEndpointSelector->availableEndpoints(); + + return list; +} + +/*! + Returns the description of the audio input device with \a name. + \since 1.0 +*/ + +QString QAudioCaptureSource::audioDescription(const QString& name) const +{ + Q_D(const QAudioCaptureSource); + + if(d->audioEndpointSelector) + return d->audioEndpointSelector->endpointDescription(name); + else + return QString(); +} + +/*! + Returns the default audio input name. + \since 1.0 +*/ + +QString QAudioCaptureSource::defaultAudioInput() const +{ + Q_D(const QAudioCaptureSource); + + if(d->audioEndpointSelector) + return d->audioEndpointSelector->defaultEndpoint(); + else + return QString(); +} + +/*! + Returns the active audio input name. + \since 1.0 +*/ + +QString QAudioCaptureSource::activeAudioInput() const +{ + Q_D(const QAudioCaptureSource); + + if(d->audioEndpointSelector) + return d->audioEndpointSelector->activeEndpoint(); + else + return QString(); +} + +/*! + Set the active audio input to \a name. + \since 1.0 +*/ + +void QAudioCaptureSource::setAudioInput(const QString& name) +{ + Q_D(const QAudioCaptureSource); + + if(d->audioEndpointSelector) + return d->audioEndpointSelector->setActiveEndpoint(name); +} + +/*! + \fn QAudioCaptureSource::activeAudioInputChanged(const QString& name) + + Signal emitted when active audio input changes to \a name. + \since 1.0 +*/ + +/*! + \fn QAudioCaptureSource::availableAudioInputsChanged() + + Signal is emitted when the available audio inputs change. + \since 1.0 +*/ + +/*! + \internal + \since 1.0 +*/ +void QAudioCaptureSource::statusChanged() +{ + Q_D(QAudioCaptureSource); + + if (d->audioEndpointSelector) { + if (d->audioEndpointSelector->availableEndpoints().size() > 0) { + d->errorState = QtMultimedia::NoError; + emit availabilityChanged(true); + } else { + d->errorState = QtMultimedia::BusyError; + emit availabilityChanged(false); + } + } else { + d->errorState = QtMultimedia::ServiceMissingError; + emit availabilityChanged(false); + } +} + +#include "moc_qaudiocapturesource.cpp" +QT_END_NAMESPACE + diff --git a/src/multimedia/qaudiocapturesource.h b/src/multimedia/qaudiocapturesource.h new file mode 100644 index 000000000..1571b4e8a --- /dev/null +++ b/src/multimedia/qaudiocapturesource.h @@ -0,0 +1,103 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QAUDIOCAPTURESOURCE_H +#define QAUDIOCAPTURESOURCE_H + +#include <QtCore/qstringlist.h> +#include <QtCore/qpair.h> +#include <QtCore/qsize.h> + +#include <qaudioformat.h> + +#include "qmediarecorder.h" +#include "qmediacontrol.h" +#include "qmediaobject.h" +#include "qmediaservice.h" + +#include "qmediaserviceprovider.h" + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + +class QAudioCaptureSourcePrivate; + +class Q_MULTIMEDIA_EXPORT QAudioCaptureSource : public QMediaObject +{ + Q_OBJECT + +public: + QAudioCaptureSource(QObject *parent = 0, QMediaServiceProvider *service = QMediaServiceProvider::defaultServiceProvider()); + ~QAudioCaptureSource(); + + bool isAvailable() const; + QtMultimedia::AvailabilityError availabilityError() const; + + QList<QString> audioInputs() const; + + QString audioDescription(const QString& name) const; + QString defaultAudioInput() const; + QString activeAudioInput() const; + +public Q_SLOTS: + void setAudioInput(const QString& name); + +Q_SIGNALS: + void activeAudioInputChanged(const QString& name); + void availableAudioInputsChanged(); + +private Q_SLOTS: + void statusChanged(); + +private: + Q_DECLARE_PRIVATE(QAudioCaptureSource) +}; + +QT_END_NAMESPACE + +QT_END_HEADER + + +#endif // QAUDIOCAPTURESOURCE_H diff --git a/src/multimedia/qaudioencodercontrol.cpp b/src/multimedia/qaudioencodercontrol.cpp new file mode 100644 index 000000000..62fa89371 --- /dev/null +++ b/src/multimedia/qaudioencodercontrol.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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qaudioencodercontrol.h" +#include <QtCore/qstringlist.h> + +QT_BEGIN_NAMESPACE + + +/*! + \class QAudioEncoderControl + \inmodule QtMultimedia + \ingroup multimedia-serv + \since 1.0 + + \brief The QAudioEncoderControl class provides access to the settings of a + media service that performs audio encoding. + + If a QMediaService supports encoding audio data it will implement + QAudioEncoderControl. This control provides information about the limits + of restricted audio encoder options and allows the selection of a set of + audio encoder settings as specified in a QAudioEncoderSettings object. + + The functionality provided by this control is exposed to application code through the + QMediaRecorder class. + + The interface name of QAudioEncoderControl is \c com.nokia.Qt.QAudioEncoderControl/1.0 as + defined in QAudioEncoderControl_iid. + + \sa QMediaService::requestControl(), QMediaRecorder +*/ + +/*! + \macro QAudioEncoderControl_iid + + \c com.nokia.Qt.AudioEncoderControl/1.0 + + Defines the interface name of the QAudioEncoderControl class. + + \relates QAudioEncoderControl +*/ + +/*! + Create a new audio encode control object with the given \a parent. +*/ +QAudioEncoderControl::QAudioEncoderControl(QObject *parent) + :QMediaControl(parent) +{ +} + +/*! + Destroys the audio encode control. +*/ +QAudioEncoderControl::~QAudioEncoderControl() +{ +} + +/*! + \fn QAudioEncoderControl::supportedAudioCodecs() const + + Returns the list of supported audio codec names. + \since 1.0 +*/ + +/*! + \fn QAudioEncoderControl::codecDescription(const QString &codec) const + + Returns description of audio \a codec. + \since 1.0 +*/ + +/*! + \fn QAudioEncoderControl::supportedSampleRates(const QAudioEncoderSettings &settings = QAudioEncoderSettings(), + bool *continuous) const + + Returns the list of supported audio sample rates, if known. + + If non null audio \a settings parameter is passed, + the returned list is reduced to sample rates supported with partial settings applied. + + It can be used for example to query the list of sample rates, supported by specific audio codec. + + If the encoder supports arbitrary sample rates within the supported rates range, + *\a continuous is set to true, otherwise *\a continuous is set to false. + \since 1.0 +*/ + +/*! + \fn QAudioEncoderControl::supportedEncodingOptions(const QString &codec) const + + Returns the list of \a codec specific audio encoding options. + \since 1.0 +*/ + +/*! + \fn QAudioEncoderControl::encodingOption(const QString &codec, const QString &option) const + + Returns the value of audio encoding \a option for \a codec. + \since 1.0 +*/ + +/*! + \fn QAudioEncoderControl::setEncodingOption(const QString &codec, const QString &option, const QVariant &value) + + Set the \a codec specific \a option to \a value. + \since 1.0 +*/ + +/*! + \fn QAudioEncoderControl::audioSettings() const + + Returns the audio encoder settings. + + The returned value may be different tha passed to QAudioEncoderControl::setAudioSettings() + if the settings contains the default or undefined parameters. + In this case if the undefined parameters are already resolved, they should be returned. + \since 1.0 +*/ + +/*! + \fn QAudioEncoderControl::setAudioSettings(const QAudioEncoderSettings &settings) + + Sets the selected audio \a settings. + \since 1.0 +*/ + +#include "moc_qaudioencodercontrol.cpp" +QT_END_NAMESPACE + diff --git a/src/multimedia/qaudioencodercontrol.h b/src/multimedia/qaudioencodercontrol.h new file mode 100644 index 000000000..2e3a4bf87 --- /dev/null +++ b/src/multimedia/qaudioencodercontrol.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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QAUDIOENCODERCONTROL_H +#define QAUDIOENCODERCONTROL_H + +#include "qmediacontrol.h" +#include "qmediarecorder.h" +#include <QtCore/qlist.h> +#include <QtCore/qpair.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + +class QStringList; +class QAudioFormat; +QT_END_NAMESPACE + +QT_BEGIN_NAMESPACE + +class Q_MULTIMEDIA_EXPORT QAudioEncoderControl : public QMediaControl +{ + Q_OBJECT + +public: + virtual ~QAudioEncoderControl(); + + virtual QStringList supportedAudioCodecs() const = 0; + virtual QString codecDescription(const QString &codecName) const = 0; + + virtual QList<int> supportedSampleRates(const QAudioEncoderSettings &settings, + bool *continuous = 0) const = 0; + + virtual QAudioEncoderSettings audioSettings() const = 0; + virtual void setAudioSettings(const QAudioEncoderSettings&) = 0; + + virtual QStringList supportedEncodingOptions(const QString &codec) const = 0; + virtual QVariant encodingOption(const QString &codec, const QString &name) const = 0; + virtual void setEncodingOption( + const QString &codec, const QString &name, const QVariant &value) = 0; + +protected: + QAudioEncoderControl(QObject *parent = 0); +}; + +#define QAudioEncoderControl_iid "com.nokia.Qt.QAudioEncoderControl/1.0" +Q_MEDIA_DECLARE_CONTROL(QAudioEncoderControl, QAudioEncoderControl_iid) + +QT_END_NAMESPACE + +QT_END_HEADER + + +#endif // QAUDIOCAPTUREPROPERTIESCONTROL_H diff --git a/src/multimedia/qaudioendpointselector.cpp b/src/multimedia/qaudioendpointselector.cpp new file mode 100644 index 000000000..ba02c8d15 --- /dev/null +++ b/src/multimedia/qaudioendpointselector.cpp @@ -0,0 +1,140 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qaudioendpointselector.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QAudioEndpointSelector + + \brief The QAudioEndpointSelector class provides an audio endpoint selector media control. + \inmodule QtMultimedia + \ingroup multimedia + \since 1.0 + + The QAudioEndpointSelector class provides descriptions of the audio + endpoints available on a system and allows one to be selected as the audio + of a media service. + + The interface name of QAudioEndpointSelector is \c com.nokia.Qt.QAudioEndpointSelector/1.0 as + defined in QAudioEndpointSelector_iid. + + \sa QMediaService::requestControl() +*/ + +/*! + \macro QAudioEndpointSelector_iid + + \c com.nokia.Qt.QAudioEndpointSelector/1.0 + + Defines the interface name of the QAudioEndpointSelector class. + + \relates QAudioEndpointSelector +*/ + +/*! + Constructs a new audio endpoint selector with the given \a parent. +*/ +QAudioEndpointSelector::QAudioEndpointSelector(QObject *parent) + :QMediaControl(parent) +{ +} + +/*! + Destroys an audio endpoint selector. +*/ +QAudioEndpointSelector::~QAudioEndpointSelector() +{ +} + +/*! + \fn QList<QString> QAudioEndpointSelector::availableEndpoints() const + + Returns a list of the names of the available audio endpoints. + \since 1.0 +*/ + +/*! + \fn QString QAudioEndpointSelector::endpointDescription(const QString& name) const + + Returns the description of the endpoint \a name. + \since 1.0 +*/ + +/*! + \fn QString QAudioEndpointSelector::defaultEndpoint() const + + Returns the name of the default audio endpoint. + \since 1.0 +*/ + +/*! + \fn QString QAudioEndpointSelector::activeEndpoint() const + + Returns the name of the currently selected audio endpoint. + \since 1.0 +*/ + +/*! + \fn QAudioEndpointSelector::setActiveEndpoint(const QString& name) + + Set the active audio endpoint to \a name. + \since 1.0 +*/ + +/*! + \fn QAudioEndpointSelector::activeEndpointChanged(const QString& name) + + Signals that the audio endpoint has changed to \a name. + \since 1.0 +*/ + +/*! + \fn QAudioEndpointSelector::availableEndpointsChanged() + + Signals that list of available endpoints has changed. + \since 1.0 +*/ + +#include "moc_qaudioendpointselector.cpp" +QT_END_NAMESPACE + diff --git a/src/multimedia/qaudioendpointselector.h b/src/multimedia/qaudioendpointselector.h new file mode 100644 index 000000000..00250bc54 --- /dev/null +++ b/src/multimedia/qaudioendpointselector.h @@ -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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QAUDIOENDPOINTSELECTOR_H +#define QAUDIOENDPOINTSELECTOR_H + +#include <qaudio.h> +#include <qmediacontrol.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + +class Q_MULTIMEDIA_EXPORT QAudioEndpointSelector : public QMediaControl +{ + Q_OBJECT + +public: + virtual ~QAudioEndpointSelector(); + + virtual QList<QString> availableEndpoints() const = 0; + virtual QString endpointDescription(const QString& name) const = 0; + virtual QString defaultEndpoint() const = 0; + virtual QString activeEndpoint() const = 0; + +public Q_SLOTS: + virtual void setActiveEndpoint(const QString& name) = 0; + +Q_SIGNALS: + void activeEndpointChanged(const QString& name); + void availableEndpointsChanged(); + +protected: + QAudioEndpointSelector(QObject *parent = 0); +}; + +#define QAudioEndpointSelector_iid "com.nokia.Qt.QAudioEndpointSelector/1.0" +Q_MEDIA_DECLARE_CONTROL(QAudioEndpointSelector, QAudioEndpointSelector_iid) + +QT_END_NAMESPACE + +QT_END_HEADER + + +#endif // QAUDIOENDPOINTSELECTOR_H diff --git a/src/multimedia/qaudionamespace.qdoc b/src/multimedia/qaudionamespace.qdoc new file mode 100644 index 000000000..86300b065 --- /dev/null +++ b/src/multimedia/qaudionamespace.qdoc @@ -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 documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** GNU Free Documentation License +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms +** and conditions contained in a signed written agreement between you +** and Nokia. +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + + +/*! + \namespace QAudio + \brief The QAudio namespace contains enums used by the audio classes. + \inmodule QtMultimedia + \ingroup multimedia +*/ + +/* + \enum QAudio::Error + + Error states + + \value NoError No errors have occurred + \value OpenError An error opening the audio device + \value IOError An error occurred during read/write of audio device + \value UnderrunError Audio data is not being fed to the audio device at a fast enough rate + \value FatalError A non-recoverable error has occurred, the audio device is not usable at this time. +*/ + +/* + \enum QAudio::State + + Audio processing states + + \value ActiveState Audio data is being processed, this state is set after start() is called + and while audio data is available to be processed. + \value SuspendedState The audio device is in a suspended state, this state will only be entered + after suspend() is called. + \value StoppedState The audio device is closed, not processing any audio data + \value IdleState The QIODevice passed in has no data and audio system's buffer is empty, this state + is set after start() is called and while no audio data is available to be processed. +*/ + +/* + \enum QAudio::Mode + + Audio I/O modes + + \value AudioOutput audio output device + \value AudioInput audio input device +*/ diff --git a/src/multimedia/qcamera.cpp b/src/multimedia/qcamera.cpp new file mode 100644 index 000000000..2b187262b --- /dev/null +++ b/src/multimedia/qcamera.cpp @@ -0,0 +1,1035 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QDebug> + +#include <qcamera.h> + +#include <qmediaobject_p.h> +#include <qcameracontrol.h> +#include <qcameralockscontrol.h> +#include <qcameraexposurecontrol.h> +#include <qcamerafocuscontrol.h> +#include <qmediarecordercontrol.h> +#include <qcameraimageprocessingcontrol.h> +#include <qcameraimagecapturecontrol.h> +#include <qvideodevicecontrol.h> +#include <qvideosurfaceoutput_p.h> + +QT_USE_NAMESPACE + +namespace +{ +class CameraRegisterMetaTypes +{ +public: + CameraRegisterMetaTypes() + { + qRegisterMetaType<QCamera::Error>("QCamera::Error"); + qRegisterMetaType<QCamera::State>("QCamera::State"); + qRegisterMetaType<QCamera::Status>("QCamera::Status"); + qRegisterMetaType<QCamera::CaptureMode>("QCamera::CaptureMode"); + qRegisterMetaType<QCamera::LockType>("QCamera::LockType"); + qRegisterMetaType<QCamera::LockStatus>("QCamera::LockStatus"); + qRegisterMetaType<QCamera::LockChangeReason>("QCamera::LockChangeReason"); + } +} _registerCameraMetaTypes; +} + + +/*! + \class QCamera + + + \brief The QCamera class provides interface for system camera devices. + + \inmodule QtMultimedia + \ingroup camera + \since 1.1 + + QCamera can be used with QVideoWidget for viewfinder display, + QMediaRecorder for video recording and QCameraImageCapture for image taking. + + \snippet doc/src/snippets/multimedia-snippets/media.cpp Request control + +*/ + + +class QCameraPrivate : public QMediaObjectPrivate +{ + Q_DECLARE_NON_CONST_PUBLIC(QCamera) +public: + QCameraPrivate(): + QMediaObjectPrivate(), + provider(0), + control(0), + deviceControl(0), + viewfinder(0), + capture(0), + state(QCamera::UnloadedState), + error(QCamera::NoError), + supportedLocks(QCamera::NoLock), + requestedLocks(QCamera::NoLock), + lockStatus(QCamera::Unlocked), + lockChangeReason(QCamera::UserRequest), + supressLockChangedSignal(false), + restartPending(false) + { + } + + void initControls(); + + QMediaServiceProvider *provider; + + QCameraControl *control; + QVideoDeviceControl *deviceControl; + QCameraLocksControl *locksControl; + + QCameraExposure *cameraExposure; + QCameraFocus *cameraFocus; + QCameraImageProcessing *imageProcessing; + + QObject *viewfinder; + QObject *capture; + + QCamera::State state; + + QCamera::Error error; + QString errorString; + + QCamera::LockTypes supportedLocks; + QCamera::LockTypes requestedLocks; + + QCamera::LockStatus lockStatus; + QCamera::LockChangeReason lockChangeReason; + bool supressLockChangedSignal; + + bool restartPending; + + QVideoSurfaceOutput surfaceViewfinder; + + void _q_error(int error, const QString &errorString); + void unsetError() { error = QCamera::NoError; errorString.clear(); } + + void setState(QCamera::State); + + void _q_updateLockStatus(QCamera::LockType, QCamera::LockStatus, QCamera::LockChangeReason); + void _q_updateState(QCamera::State newState); + void _q_preparePropertyChange(int changeType); + void _q_restartCamera(); + void updateLockStatus(); +}; + + +void QCameraPrivate::_q_error(int error, const QString &errorString) +{ + Q_Q(QCamera); + + this->error = QCamera::Error(error); + this->errorString = errorString; + + qWarning() << "Camera error:" << errorString; + + emit q->error(this->error); +} + +void QCameraPrivate::setState(QCamera::State newState) +{ + Q_Q(QCamera); + + unsetError(); + + if (!control) { + _q_error(QCamera::ServiceMissingError, q_ptr->tr("The camera service is missing")); + return; + } + + if (state == newState) + return; + + restartPending = false; + state = newState; + control->setState(state); + emit q->stateChanged(state); +} + +void QCameraPrivate::_q_updateState(QCamera::State newState) +{ + Q_Q(QCamera); + + //omit changins state to Loaded when the camera is temporarily + //stopped to apply shanges + if (restartPending) + return; + + if (newState != state) { + qDebug() << "Camera state changed:" << newState; + state = newState; + emit q->stateChanged(state); + } +} + +void QCameraPrivate::_q_preparePropertyChange(int changeType) +{ + if (!control) + return; + + QCamera::Status status = control->status(); + + //all the changes are allowed until the camera is starting + if (control->state() != QCamera::ActiveState) + return; + + if (control->canChangeProperty(QCameraControl::PropertyChangeType(changeType), status)) + return; + + restartPending = true; + control->setState(QCamera::LoadedState); + QMetaObject::invokeMethod(q_ptr, "_q_restartCamera", Qt::QueuedConnection); +} + +void QCameraPrivate::_q_restartCamera() +{ + if (restartPending) { + restartPending = false; + control->setState(QCamera::ActiveState); + } +} + +void QCameraPrivate::initControls() +{ + Q_Q(QCamera); + + supportedLocks = 0; + + if (service) { + control = qobject_cast<QCameraControl *>(service->requestControl(QCameraControl_iid)); + locksControl = qobject_cast<QCameraLocksControl *>(service->requestControl(QCameraLocksControl_iid)); + deviceControl = qobject_cast<QVideoDeviceControl*>(service->requestControl(QVideoDeviceControl_iid)); + + if (control) { + q->connect(control, SIGNAL(stateChanged(QCamera::State)), q, SLOT(_q_updateState(QCamera::State))); + q->connect(control, SIGNAL(statusChanged(QCamera::Status)), q, SIGNAL(statusChanged(QCamera::Status))); + q->connect(control, SIGNAL(captureModeChanged(QCamera::CaptureMode)), + q, SIGNAL(captureModeChanged(QCamera::CaptureMode))); + q->connect(control, SIGNAL(error(int,QString)), q, SLOT(_q_error(int,QString))); + + } + + if (locksControl) { + q->connect(locksControl, SIGNAL(lockStatusChanged(QCamera::LockType,QCamera::LockStatus,QCamera::LockChangeReason)), + q, SLOT(_q_updateLockStatus(QCamera::LockType,QCamera::LockStatus,QCamera::LockChangeReason))); + supportedLocks = locksControl->supportedLocks(); + } + + error = QCamera::NoError; + } else { + control = 0; + locksControl = 0; + deviceControl = 0; + + error = QCamera::ServiceMissingError; + errorString = QCamera::tr("The camera service is missing"); + } +} + +void QCameraPrivate::updateLockStatus() +{ + Q_Q(QCamera); + + QCamera::LockStatus oldStatus = lockStatus; + + QMap<QCamera::LockStatus, int> lockStatusPriority; + lockStatusPriority.insert(QCamera::Locked, 1); + lockStatusPriority.insert(QCamera::Searching, 2); + lockStatusPriority.insert(QCamera::Unlocked, 3); + + lockStatus = requestedLocks ? QCamera::Locked : QCamera::Unlocked; + int priority = 0; + + QList<QCamera::LockStatus> lockStatuses; + + if (requestedLocks & QCamera::LockFocus) + lockStatuses << q->lockStatus(QCamera::LockFocus); + + if (requestedLocks & QCamera::LockExposure) + lockStatuses << q->lockStatus(QCamera::LockExposure); + + if (requestedLocks & QCamera::LockWhiteBalance) + lockStatuses << q->lockStatus(QCamera::LockWhiteBalance); + + + foreach (QCamera::LockStatus currentStatus, lockStatuses) { + int currentPriority = lockStatusPriority.value(currentStatus, -1); + if (currentPriority > priority) { + priority = currentPriority; + lockStatus = currentStatus; + } + } + + if (!supressLockChangedSignal && oldStatus != lockStatus) { + emit q->lockStatusChanged(lockStatus, lockChangeReason); + + if (lockStatus == QCamera::Locked) + emit q->locked(); + else if (lockStatus == QCamera::Unlocked && lockChangeReason == QCamera::LockFailed) + emit q->lockFailed(); + } +/* + qDebug() << "Requested locks:" << (requestedLocks & QCamera::LockExposure ? 'e' : ' ') + << (requestedLocks & QCamera::LockFocus ? 'f' : ' ') + << (requestedLocks & QCamera::LockWhiteBalance ? 'w' : ' '); + qDebug() << "Lock status: f:" << q->lockStatus(QCamera::LockFocus) + << " e:" << q->lockStatus(QCamera::LockExposure) + << " w:" << q->lockStatus(QCamera::LockWhiteBalance) + << " composite:" << lockStatus; +*/ +} + +void QCameraPrivate::_q_updateLockStatus(QCamera::LockType type, QCamera::LockStatus status, QCamera::LockChangeReason reason) +{ + Q_Q(QCamera); + lockChangeReason = reason; + updateLockStatus(); + emit q->lockStatusChanged(type, status, reason); +} + + +/*! + Construct a QCamera from service \a provider and \a parent. +*/ + +QCamera::QCamera(QObject *parent, QMediaServiceProvider *provider): + QMediaObject(*new QCameraPrivate, parent, provider->requestService(Q_MEDIASERVICE_CAMERA)) +{ + Q_D(QCamera); + d->provider = provider; + d->initControls(); + d->cameraExposure = new QCameraExposure(this); + d->cameraFocus = new QCameraFocus(this); + d->imageProcessing = new QCameraImageProcessing(this); +} + +/*! + Construct a QCamera from device name \a device and \a parent. +*/ + +QCamera::QCamera(const QByteArray& device, QObject *parent): + QMediaObject(*new QCameraPrivate, parent, + QMediaServiceProvider::defaultServiceProvider()->requestService(Q_MEDIASERVICE_CAMERA, QMediaServiceProviderHint(device))) +{ + Q_D(QCamera); + d->provider = QMediaServiceProvider::defaultServiceProvider(); + d->initControls(); + + if (d->service != 0) { + //pass device name to service + if (d->deviceControl) { + QString deviceName = QString::fromLatin1(device); + + for (int i=0; i<d->deviceControl->deviceCount(); i++) { + if (d->deviceControl->deviceName(i) == deviceName) { + d->deviceControl->setSelectedDevice(i); + break; + } + } + } + } + + d->cameraExposure = new QCameraExposure(this); + d->cameraFocus = new QCameraFocus(this); + d->imageProcessing = new QCameraImageProcessing(this); +} + +/*! + Destroys the camera object. +*/ + +QCamera::~QCamera() +{ + Q_D(QCamera); + delete d->cameraExposure; + d->cameraExposure = 0; + delete d->cameraFocus; + d->cameraFocus = 0; + delete d->imageProcessing; + d->imageProcessing = 0; + + if (d->service) { + if (d->control) + d->service->releaseControl(d->control); + if (d->locksControl) + d->service->releaseControl(d->locksControl); + if (d->deviceControl) + d->service->releaseControl(d->deviceControl); + + d->provider->releaseService(d->service); + } +} + + +/*! + Return true if the camera service is ready to use. + \since 1.1 +*/ +bool QCamera::isAvailable() const +{ + return availabilityError() == QtMultimedia::NoError; +} + +/*! + Returns the error state of the camera service. + \since 1.1 +*/ + +QtMultimedia::AvailabilityError QCamera::availabilityError() const +{ + Q_D(const QCamera); + if (d->control == NULL) + return QtMultimedia::ServiceMissingError; + + if (d->deviceControl && d->deviceControl->deviceCount() == 0) + return QtMultimedia::ResourceError; + + if (d->error != QCamera::NoError) + return QtMultimedia::ResourceError; + + return QtMultimedia::NoError; +} + + +/*! + Returns the camera exposure control object. + \since 1.1 +*/ +QCameraExposure *QCamera::exposure() const +{ + return d_func()->cameraExposure; +} + +/*! + Returns the camera focus control object. + \since 1.1 +*/ +QCameraFocus *QCamera::focus() const +{ + return d_func()->cameraFocus; +} + +/*! + Returns the camera image processing control object. + \since 1.1 +*/ +QCameraImageProcessing *QCamera::imageProcessing() const +{ + return d_func()->imageProcessing; +} + +/*! + Sets the QVideoWidget based camera \a viewfinder. + The previously set viewfinder is detached. + \since 1.1 +*/ + +// QVideoWidget is forward declared +void QCamera::setViewfinder(QVideoWidget *viewfinder) +{ + Q_D(QCamera); + d->_q_preparePropertyChange(QCameraControl::Viewfinder); + + if (d->viewfinder) + unbind(d->viewfinder); + + // We don't know (in this library) that QVideoWidget inherits QObject + QObject *viewFinderObject = reinterpret_cast<QObject*>(viewfinder); + + d->viewfinder = viewFinderObject && bind(viewFinderObject) ? viewFinderObject : 0; +} + +/*! + Sets the QGraphicsVideoItem based camera \a viewfinder. + The previously set viewfinder is detached. + \since 1.1 +*/ +// QGraphicsVideoItem is forward declared +void QCamera::setViewfinder(QGraphicsVideoItem *viewfinder) +{ + Q_D(QCamera); + d->_q_preparePropertyChange(QCameraControl::Viewfinder); + + if (d->viewfinder) + unbind(d->viewfinder); + + // We don't know (in this library) that QGraphicsVideoItem (multiply) inherits QObject + // but QObject inheritance depends on QObject coming first, so try this out. + QObject *viewFinderObject = reinterpret_cast<QObject*>(viewfinder); + + d->viewfinder = viewFinderObject && bind(viewFinderObject) ? viewFinderObject : 0; +} + +/*! + Sets a video \a surface as the viewfinder of a camera. + + If a viewfinder has already been set on the camera the new surface + will replace it. + \since 1.2 +*/ + +void QCamera::setViewfinder(QAbstractVideoSurface *surface) +{ + Q_D(QCamera); + + d->surfaceViewfinder.setVideoSurface(surface); + + if (d->viewfinder != &d->surfaceViewfinder) { + if (d->viewfinder) + unbind(d->viewfinder); + + d->viewfinder = bind(&d->surfaceViewfinder) ? &d->surfaceViewfinder : 0; + } +} + +/*! + Returns the error state of the object. + \since 1.1 +*/ + +QCamera::Error QCamera::error() const +{ + return d_func()->error; +} + +/*! + Returns a string describing a camera's error state. + \since 1.1 +*/ +QString QCamera::errorString() const +{ + return d_func()->errorString; +} + + +/*! + Returns true if the capture \a mode is suported. + \since 1.1 +*/ +bool QCamera::isCaptureModeSupported(QCamera::CaptureMode mode) const +{ + return d_func()->control ? d_func()->control->isCaptureModeSupported(mode) : false; +} + +/*! + \property QCamera::captureMode + + The type of media (video or still images), + the camera is configured to capture. + + It's allowed to change capture mode in any camera state, + but if the camera is currently active, + chaging capture mode is likely to lead to camera status + chaged to QCamera::LoadedStatus, QCamera::LoadingStatus, + and when the camera is ready to QCamera::ActiveStatus. + \since 1.1 +*/ + +QCamera::CaptureMode QCamera::captureMode() const +{ + return d_func()->control ? d_func()->control->captureMode() : QCamera::CaptureStillImage; +} + +void QCamera::setCaptureMode(QCamera::CaptureMode mode) +{ + Q_D(QCamera); + + if (mode != captureMode()) { + if (d->control) { + d->_q_preparePropertyChange(QCameraControl::CaptureMode); + d->control->setCaptureMode(mode); + } + } +} + + +/*! + Starts the camera. + + State is changed to QCamera::ActiveState if camera is started + successfully, otherwise error() signal is emitted. + + While the camera state is changed to QCamera::ActiveState, + starting the camera service can be asynchronous with the actual + status reported with QCamera::status property. + \since 1.1 +*/ +void QCamera::start() +{ + Q_D(QCamera); + d->setState(QCamera::ActiveState); +} + +/*! + Stops the camera. + The camera state is changed from QCamera::ActiveState to QCamera::LoadedState. + \since 1.1 +*/ +void QCamera::stop() +{ + Q_D(QCamera); + d->setState(QCamera::LoadedState); +} + +/*! + Open the camera device. + The camera state is changed to QCamera::LoadedStatus. + + It's not necessary to explcitly load the camera, + unless unless the application have to read the supported camera + settings and change the default depending on the camera capabilities. + + In all the other cases it's possible to start the camera directly + from unloaded state. + \since 1.1 +*/ +void QCamera::load() +{ + Q_D(QCamera); + d->setState(QCamera::LoadedState); +} + +/*! + Close the camera device and deallocate the related resources. + The camera state is changed to QCamera::UnloadedStatus. + \since 1.1 +*/ +void QCamera::unload() +{ + Q_D(QCamera); + d->setState(QCamera::UnloadedState); +} + + +/*! + Returns a list of camera device's available from the default service provider. + \since 1.1 +*/ + +QList<QByteArray> QCamera::availableDevices() +{ + return QMediaServiceProvider::defaultServiceProvider()->devices(QByteArray(Q_MEDIASERVICE_CAMERA)); +} + +/*! + Returns the description of the \a device. + \since 1.1 +*/ + +QString QCamera::deviceDescription(const QByteArray &device) +{ + return QMediaServiceProvider::defaultServiceProvider()->deviceDescription(QByteArray(Q_MEDIASERVICE_CAMERA), device); +} + +QCamera::State QCamera::state() const +{ + return d_func()->state; +} + +QCamera::Status QCamera::status() const +{ + if(d_func()->control) + return (QCamera::Status)d_func()->control->status(); + + return QCamera::UnavailableStatus; +} + + +/*! + Returns the lock types, camera supports. + \since 1.1 +*/ +QCamera::LockTypes QCamera::supportedLocks() const +{ + return d_func()->supportedLocks; +} + +/*! + Returns the requested lock types. + \since 1.1 +*/ +QCamera::LockTypes QCamera::requestedLocks() const +{ + return d_func()->requestedLocks; +} + +/*! + Returns the status of requested camera settings locks. + \since 1.1 +*/ +QCamera::LockStatus QCamera::lockStatus() const +{ + return d_func()->lockStatus; +} + +/*! + Returns the status of camera settings \a lock. + \since 1.1 +*/ +QCamera::LockStatus QCamera::lockStatus(QCamera::LockType lockType) const +{ + const QCameraPrivate *d = d_func(); + + if (!(lockType & d->supportedLocks)) + return lockType & d->requestedLocks ? QCamera::Locked : QCamera::Unlocked; + + if (!(lockType & d->requestedLocks)) + return QCamera::Unlocked; + + if (d->locksControl) + return d->locksControl->lockStatus(lockType); + + return QCamera::Unlocked; +} + +/*! + \fn void QCamera::searchAndLock(QCamera::LockTypes locks) + + Locks the camera settings with the requested \a locks, including focusing in the single autofocus mode, + exposure and white balance if the exposure and white balance modes are not manual. + + The camera settings are usually locked before taking one or multiple still images, + in responce to the shutter button being half pressed. + + The QCamera::locked() signal is emitted when camera settings are successfully locked, + otherwise QCamera::lockFailed() is emitted. + + QCamera also emits lockStatusChanged(QCamera::LockType, QCamera::LockStatus) + on individual lock status changes and lockStatusChanged(QCamera::LockStatus) signal on composite status changes. + + Locking serves two roles: it initializes calculation of automatic parameter + (focusing, calculating the correct exposure and white balance) and allows + to keep some or all of those parameters during number of shots. + + If the camera doesn't support keeping one of parameters between shots, the related + lock state changes to QCamera::Unlocked. + + It's also acceptable to relock already locked settings, + depending on the lock parameter this initiates new focusing, exposure or white balance calculation. + \since 1.1 + */ +void QCamera::searchAndLock(QCamera::LockTypes locks) +{ + Q_D(QCamera); + + QCamera::LockStatus oldStatus = d->lockStatus; + d->supressLockChangedSignal = true; + + d->requestedLocks |= locks; + + locks &= d->supportedLocks; + + if (d->locksControl) + d->locksControl->searchAndLock(locks); + + d->supressLockChangedSignal = false; + + d->lockStatus = oldStatus; + d->updateLockStatus(); +} + +/*! + Lock all the supported camera settings. + \since 1.1 + */ +void QCamera::searchAndLock() +{ + searchAndLock(LockExposure | LockWhiteBalance | LockFocus); +} + +/*! + Unlocks the camera settings specified with \a locks or cancel the current locking if one is active. + \since 1.1 + */ +void QCamera::unlock(QCamera::LockTypes locks) +{ + Q_D(QCamera); + + QCamera::LockStatus oldStatus = d->lockStatus; + d->supressLockChangedSignal = true; + + d->requestedLocks &= ~locks; + + locks &= d->supportedLocks; + + if (d->locksControl) + d->locksControl->unlock(locks); + + d->supressLockChangedSignal = false; + + d->lockStatus = oldStatus; + d->updateLockStatus(); +} + +/*! + Unlock all the requested camera locks. + \since 1.1 + */ +void QCamera::unlock() +{ + unlock(d_func()->requestedLocks); +} + + +/*! + \enum QCamera::State + \value UnloadedState + The initial camera state, with camera not loaded, + the camera capabilities except of supported capture modes + are unknown. + + While the supported settings are unknown in this state, + it's allowed to set the camera capture settings like codec, + resolution, or frame rate. + + \value LoadedState + The camera is loaded and ready to be configured. + + In the Idle state it's allowed to query camera capabilities, + set capture resolution, codecs, etc. + + The viewfinder is not active in the loaded state. + + \value ActiveState + In the active state as soon as camera is started + the viewfinder displays video frames and the + camera is ready for capture. +*/ + + +/*! + \property QCamera::state + \brief The current state of the camera object. + \since 1.1 +*/ + +/*! + \enum QCamera::Status + \value ActiveStatus + The camera has been started and can produce data. + The viewfinder displays video frames in active state. + + Depending on backend, changing some camera settings like + capture mode, codecs or resolution in ActiveState may lead + to changing the camera status to LoadedStatus and StartingStatus while + the settings are applied and back to ActiveStatus when the camera is ready. + + \value StartingStatus + The camera is starting in result of state transition to QCamera::ActiveState. + The camera service is not ready to capture yet. + + \value StandbyStatus + The camera is in the power saving standby mode. + The camera may come to the standby mode after some time of inactivity + in the QCamera::LoadedState state. + + \value LoadedStatus + The camera is loaded and ready to be configured. + This status indicates the camera device is opened and + it's possible to query for supported image and video capture settings, + like resolution, framerate and codecs. + + \value LoadingStatus + The camera device loading in result of state transition from + QCamera::UnloadedState to QCamera::LoadedState or QCamera::ActiveState. + + \value UnloadedStatus + The initial camera status, with camera not loaded. + The camera capabilities including supported capture settings may be unknown. + + \value UnavailableStatus + The camera or camera backend is not available. +*/ + + +/*! + \property QCamera::status + \brief The current status of the camera object. + \since 1.1 +*/ + + +/*! + \enum QCamera::CaptureMode + \value CaptureStillImage Camera is configured for still frames capture. + \value CaptureVideo Camera is configured for video capture. + \since 1.1 +*/ + +/*! + \enum QCamera::LockType + + \value NoLock + \value LockExposure + Lock camera exposure. + \value LockWhiteBalance + Lock the white balance. + \value LockFocus + Lock camera focus. +*/ + + +/*! + \property QCamera::lockStatus + \brief The overall status for all the requested camera locks. + \since 1.1 +*/ + +/*! + \fn void QCamera::locked() + + Signals all the requested camera settings are locked. + \since 1.1 +*/ + +/*! + \fn void QCamera::lockFailed() + + Signals locking of at least one requested camera settings failed. + \since 1.1 +*/ + +/*! + \fn QCamera::lockStatusChanged(QCamera::LockStatus status, QCamera::LockChangeReason reason) + + Signals the overall \a status for all the requested camera locks was changed with specified \a reason. + \since 1.1 +*/ + +/*! + \fn QCamera::lockStatusChanged(QCamera::LockType lock, QCamera::LockStatus status, QCamera::LockChangeReason reason) + Signals the \a lock \a status was changed with specified \a reason. + \since 1.1 +*/ + +/*! + \enum QCamera::LockStatus + \value Unlocked + The application is not interested in camera settings value. + The camera may keep this parameter without changes, this is common with camera focus, + or adjust exposure and white balance constantly to keep the viewfinder image nice. + + \value Searching + The application has requested the camera focus, exposure or white balance lock with + QCamera::searchAndLock(). This state indicates the camera is focusing or calculating exposure and white balance. + + \value Locked + The camera focus, exposure or white balance is locked. + The camera is ready to capture, application may check the exposure parameters. + + The locked state usually means the requested parameter stays the same, + except of the cases when the parameter is requested to be constantly updated. + For example in continuous focusing mode, the focus is considered locked as long + and the object is in focus, even while the actual focusing distance may be constantly changing. +*/ + +/*! + \enum QCamera::LockChangeReason + + \value UserRequest + The lock status changed in result of user request, usually to unlock camera settings. + \value LockAcquired + The lock status successfuly changed to QCamera::Locked. + \value LockFailed + The camera failed to acquire the requested lock in result of + autofocus failure, exposure out of supported range, etc. + \value LockLost + The camera is not able to maintain the requested lock any more. + Lock status is changed to QCamera::Unlocked. + \value LockTemporaryLost + The lock is lost, but the camera is working hard to reacquire it. + This value may be used in continuous focusing mode, + when the camera loses the focus, the focus lock state is changed to Qcamera::Searching + with LockTemporaryLost reason. +*/ + +/*! + \enum QCamera::Error + + \value NoError No errors have occurred. + \value CameraError An error has occurred. + \value InvalidRequestError System resource doesn't support requested functionality. + \value ServiceMissingError No camera service available. + \value NotSupportedFeatureError The feature is not supported. +*/ + +/*! + \fn void QCamera::error(QCamera::Error value) + + Signal emitted when error state changes to \a value. + \since 1.1 +*/ + +/*! + \fn void QCamera::captureModeChanged(QCamera::CaptureMode mode) + + Signals the capture \a mode has changed. + \since 1.1 +*/ + +/*! + \fn QCamera::stateChanged(QCamera::State state) + + Signals the camera \a state has changed. + + Usually the state changes is caused by calling + load(), unload(), start() and stop(), + but the state can also be changed change as a result of camera error. + \since 1.1 +*/ + +/*! + \fn QCamera::statusChanged(QCamera::Status status) + + Signals the camera \a status has changed. + + \since 1.1 +*/ + + +#include "moc_qcamera.cpp" diff --git a/src/multimedia/qcamera.h b/src/multimedia/qcamera.h new file mode 100644 index 000000000..da009e161 --- /dev/null +++ b/src/multimedia/qcamera.h @@ -0,0 +1,238 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QCAMERA_H +#define QCAMERA_H + +#include <QtCore/qstringlist.h> +#include <QtCore/qpair.h> +#include <QtCore/qsize.h> +#include <QtCore/qpoint.h> +#include <QtCore/qrect.h> + +#include <qmediacontrol.h> +#include <qmediaobject.h> +#include <qmediaservice.h> + +#include <qcameraexposure.h> +#include <qcamerafocus.h> +#include <qcameraimageprocessing.h> + +#include <qmediaserviceprovider.h> +#include <qmediaenumdebug.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + +class QAbstractVideoSurface; +class QVideoWidget; +class QGraphicsVideoItem; + +class QCameraPrivate; +class Q_MULTIMEDIA_EXPORT QCamera : public QMediaObject +{ + Q_OBJECT + Q_PROPERTY(QCamera::State state READ state NOTIFY stateChanged) + Q_PROPERTY(QCamera::Status status READ status NOTIFY statusChanged) + Q_PROPERTY(QCamera::CaptureMode captureMode READ captureMode WRITE setCaptureMode NOTIFY captureModeChanged) + Q_PROPERTY(QCamera::LockStatus lockStatus READ lockStatus NOTIFY lockStatusChanged) + + Q_ENUMS(Status) + Q_ENUMS(State) + Q_ENUMS(CaptureMode) + Q_ENUMS(Error) + Q_ENUMS(LockStatus) + Q_ENUMS(LockChangeReason) + Q_ENUMS(LockType) +public: + enum Status { + UnavailableStatus, + UnloadedStatus, + LoadingStatus, + LoadedStatus, + StandbyStatus, + StartingStatus, + ActiveStatus + }; + + enum State { + UnloadedState, + LoadedState, + ActiveState + }; + + enum CaptureMode + { + CaptureStillImage, + CaptureVideo + }; + + enum Error + { + NoError, + CameraError, + InvalidRequestError, + ServiceMissingError, + NotSupportedFeatureError + }; + + enum LockStatus + { + Unlocked, + Searching, + Locked + }; + + enum LockChangeReason { + UserRequest, + LockAcquired, + LockFailed, + LockLost, + LockTemporaryLost + }; + + enum LockType + { + NoLock = 0, + LockExposure = 0x01, + LockWhiteBalance = 0x02, + LockFocus = 0x04 + }; + Q_DECLARE_FLAGS(LockTypes, LockType) + + QCamera(QObject *parent = 0, QMediaServiceProvider *provider = QMediaServiceProvider::defaultServiceProvider()); + QCamera(const QByteArray& device, QObject *parent = 0); + ~QCamera(); + + static QList<QByteArray> availableDevices(); + static QString deviceDescription(const QByteArray &device); + + bool isAvailable() const; + QtMultimedia::AvailabilityError availabilityError() const; + + State state() const; + Status status() const; + + CaptureMode captureMode() const; + bool isCaptureModeSupported(CaptureMode mode) const; + + QCameraExposure *exposure() const; + QCameraFocus *focus() const; + QCameraImageProcessing *imageProcessing() const; + + void setViewfinder(QVideoWidget *viewfinder); + void setViewfinder(QGraphicsVideoItem *viewfinder); + void setViewfinder(QAbstractVideoSurface *surface); + + Error error() const; + QString errorString() const; + + QCamera::LockTypes supportedLocks() const; + QCamera::LockTypes requestedLocks() const; + + QCamera::LockStatus lockStatus() const; + QCamera::LockStatus lockStatus(QCamera::LockType lock) const; + +public Q_SLOTS: + void setCaptureMode(QCamera::CaptureMode mode); + + void load(); + void unload(); + + void start(); + void stop(); + + void searchAndLock(); + void unlock(); + + void searchAndLock(QCamera::LockTypes locks); + void unlock(QCamera::LockTypes locks); + +Q_SIGNALS: + void stateChanged(QCamera::State); + void captureModeChanged(QCamera::CaptureMode); + void statusChanged(QCamera::Status); + + void locked(); + void lockFailed(); + + void lockStatusChanged(QCamera::LockStatus, QCamera::LockChangeReason); + void lockStatusChanged(QCamera::LockType, QCamera::LockStatus, QCamera::LockChangeReason); + + void error(QCamera::Error); + +private: + Q_DISABLE_COPY(QCamera) + Q_DECLARE_PRIVATE(QCamera) + Q_PRIVATE_SLOT(d_func(), void _q_preparePropertyChange(int)) + Q_PRIVATE_SLOT(d_func(), void _q_restartCamera()) + Q_PRIVATE_SLOT(d_func(), void _q_error(int, const QString &)) + Q_PRIVATE_SLOT(d_func(), void _q_updateLockStatus(QCamera::LockType, QCamera::LockStatus, QCamera::LockChangeReason)) + Q_PRIVATE_SLOT(d_func(), void _q_updateState(QCamera::State)) +}; + +Q_DECLARE_OPERATORS_FOR_FLAGS(QCamera::LockTypes) + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(QCamera::State) +Q_DECLARE_METATYPE(QCamera::Status) +Q_DECLARE_METATYPE(QCamera::Error) +Q_DECLARE_METATYPE(QCamera::CaptureMode) +Q_DECLARE_METATYPE(QCamera::LockType) +Q_DECLARE_METATYPE(QCamera::LockStatus) +Q_DECLARE_METATYPE(QCamera::LockChangeReason) + +Q_MEDIA_ENUM_DEBUG(QCamera, State) +Q_MEDIA_ENUM_DEBUG(QCamera, Status) +Q_MEDIA_ENUM_DEBUG(QCamera, Error) +Q_MEDIA_ENUM_DEBUG(QCamera, CaptureMode) +Q_MEDIA_ENUM_DEBUG(QCamera, LockType) +Q_MEDIA_ENUM_DEBUG(QCamera, LockStatus) +Q_MEDIA_ENUM_DEBUG(QCamera, LockChangeReason) + +QT_END_HEADER + +#endif // QCAMERA_H diff --git a/src/multimedia/qcameracapturebufferformatcontrol.cpp b/src/multimedia/qcameracapturebufferformatcontrol.cpp new file mode 100644 index 000000000..536c8b329 --- /dev/null +++ b/src/multimedia/qcameracapturebufferformatcontrol.cpp @@ -0,0 +1,117 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <qcameracapturebufferformatcontrol.h> + +QT_BEGIN_NAMESPACE + +/*! + \class QCameraCaptureBufferFormatControl + + \brief The QCameraCaptureBufferFormatControl class provides a control for setting the capture buffer format. + + The format is of type QVideoFrame::PixelFormat. + + \inmodule QtMultimedia + \ingroup multimedia-serv + + The interface name of QCameraCaptureBufferFormatControl is \c com.nokia.Qt.QCameraCaptureBufferFormatControl/1.0 as + defined in QCameraCaptureBufferFormatControl_iid. + + \sa QMediaService::requestControl() +*/ + +/*! + \macro QCameraCaptureBufferFormatControl_iid + + \c com.nokia.Qt.QCameraCaptureBufferFormatControl/1.0 + + Defines the interface name of the QCameraCaptureBufferFormatControl class. + + \relates QCameraCaptureBufferFormatControl +*/ + +/*! + Constructs a new image buffer capture format control object with the given \a parent +*/ +QCameraCaptureBufferFormatControl::QCameraCaptureBufferFormatControl(QObject *parent) + :QMediaControl(parent) +{ +} + +/*! + Destroys an image buffer capture format control. +*/ +QCameraCaptureBufferFormatControl::~QCameraCaptureBufferFormatControl() +{ +} + +/*! + \fn QCameraCaptureBufferFormatControl::supportedBufferFormats() const + + Returns the list of the supported buffer capture formats. + \since 1.2 +*/ + +/*! + \fn QCameraCaptureBufferFormatControl::bufferFormat() const + + Returns the current buffer capture format. + \since 1.2 +*/ + +/*! + \fn QCameraCaptureBufferFormatControl::setBufferFormat(QVideoFrame::PixelFormat format) + + Sets the buffer capture \a format. + \since 1.2 +*/ + +/*! + \fn QCameraCaptureBufferFormatControl::bufferFormatChanged(QVideoFrame::PixelFormat format) + + Signals the buffer image capture format changed to \a format. + \since 1.2 +*/ + +#include "moc_qcameracapturebufferformatcontrol.cpp" +QT_END_NAMESPACE + diff --git a/src/multimedia/qcameracapturebufferformatcontrol.h b/src/multimedia/qcameracapturebufferformatcontrol.h new file mode 100644 index 000000000..81079a77d --- /dev/null +++ b/src/multimedia/qcameracapturebufferformatcontrol.h @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QCAMERACAPTUREBUFFERFORMATCONTROL_H +#define QCAMERACAPTUREBUFFERFORMATCONTROL_H + +#include <qmediacontrol.h> +#include <qcameraimagecapture.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + +class Q_MULTIMEDIA_EXPORT QCameraCaptureBufferFormatControl : public QMediaControl +{ + Q_OBJECT +public: + ~QCameraCaptureBufferFormatControl(); + + virtual QList<QVideoFrame::PixelFormat> supportedBufferFormats() const = 0; + virtual QVideoFrame::PixelFormat bufferFormat() const = 0; + virtual void setBufferFormat(QVideoFrame::PixelFormat format) = 0; + +Q_SIGNALS: + void bufferFormatChanged(QVideoFrame::PixelFormat); + +protected: + QCameraCaptureBufferFormatControl(QObject* parent = 0); +}; + +#define QCameraCaptureBufferFormatControl_iid "com.nokia.Qt.QCameraCaptureBufferFormatControl/1.0" +Q_MEDIA_DECLARE_CONTROL(QCameraCaptureBufferFormatControl, QCameraCaptureBufferFormatControl_iid) + +QT_END_NAMESPACE + +QT_END_HEADER + + +#endif + diff --git a/src/multimedia/qcameracapturedestinationcontrol.cpp b/src/multimedia/qcameracapturedestinationcontrol.cpp new file mode 100644 index 000000000..5072ae774 --- /dev/null +++ b/src/multimedia/qcameracapturedestinationcontrol.cpp @@ -0,0 +1,121 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <qcameracapturedestinationcontrol.h> +#include <QtCore/qstringlist.h> + +QT_BEGIN_NAMESPACE + +/*! + \class QCameraCaptureDestinationControl + + \brief The QCameraCaptureDestinationControl class provides a control for setting capture destination. + + Depending on backend capabilities capture to file, buffer or both can be supported. + + \inmodule QtMultimedia + \ingroup multimedia-serv + + + + The interface name of QCameraCaptureDestinationControl is \c com.nokia.Qt.QCameraCaptureDestinationControl/1.0 as + defined in QCameraCaptureDestinationControl_iid. + + + \sa QMediaService::requestControl() +*/ + +/*! + \macro QCameraCaptureDestinationControl_iid + + \c com.nokia.Qt.QCameraCaptureDestinationControl/1.0 + + Defines the interface name of the QCameraCaptureDestinationControl class. + + \relates QCameraCaptureDestinationControl +*/ + +/*! + Constructs a new image capture destination control object with the given \a parent +*/ +QCameraCaptureDestinationControl::QCameraCaptureDestinationControl(QObject *parent) + :QMediaControl(parent) +{ +} + +/*! + Destroys an image capture destination control. +*/ +QCameraCaptureDestinationControl::~QCameraCaptureDestinationControl() +{ +} + +/*! + \fn QCameraCaptureDestinationControl::isCaptureDestinationSupported(QCameraImageCapture::CaptureDestinations destination) const + + Returns true if the capture \a destination is supported; and false if it is not. + \since 1.2 +*/ + +/*! + \fn QCameraCaptureDestinationControl::captureDestination() const + + Returns the current capture \a destination. The default destination is QCameraImageCapture::CaptureToFile. + \since 1.2 +*/ + +/*! + \fn QCameraCaptureDestinationControl::setCaptureDestination(QCameraImageCapture::CaptureDestinations destination) + + Sets the capture \a destination. + \since 1.2 +*/ + +/*! + \fn QCameraCaptureDestinationControl::captureDestinationChanged(QCameraImageCapture::CaptureDestinations destination) + + Signals the image capture \a destination changed. + \since 1.2 +*/ + +#include "moc_qcameracapturedestinationcontrol.cpp" +QT_END_NAMESPACE + diff --git a/src/multimedia/qcameracapturedestinationcontrol.h b/src/multimedia/qcameracapturedestinationcontrol.h new file mode 100644 index 000000000..cdd769a4d --- /dev/null +++ b/src/multimedia/qcameracapturedestinationcontrol.h @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QCAMERACAPTUREDESTINATIONCONTROL_H +#define QCAMERACAPTUREDESTINATIONCONTROL_H + +#include <qmediacontrol.h> +#include <qcameraimagecapture.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + +class Q_MULTIMEDIA_EXPORT QCameraCaptureDestinationControl : public QMediaControl +{ + Q_OBJECT +public: + ~QCameraCaptureDestinationControl(); + + virtual bool isCaptureDestinationSupported(QCameraImageCapture::CaptureDestinations destination) const = 0; + virtual QCameraImageCapture::CaptureDestinations captureDestination() const = 0; + virtual void setCaptureDestination(QCameraImageCapture::CaptureDestinations destination) = 0; + +Q_SIGNALS: + void captureDestinationChanged(QCameraImageCapture::CaptureDestinations); + +protected: + QCameraCaptureDestinationControl(QObject* parent = 0); +}; + +#define QCameraCaptureDestinationControl_iid "com.nokia.Qt.QCameraCaptureDestinationControl/1.0" +Q_MEDIA_DECLARE_CONTROL(QCameraCaptureDestinationControl, QCameraCaptureDestinationControl_iid) + +QT_END_NAMESPACE + +QT_END_HEADER + + +#endif + diff --git a/src/multimedia/qcameracontrol.cpp b/src/multimedia/qcameracontrol.cpp new file mode 100644 index 000000000..df5c44cc1 --- /dev/null +++ b/src/multimedia/qcameracontrol.cpp @@ -0,0 +1,215 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <qcameracontrol.h> +#include "qmediacontrol_p.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QCameraControl + + + + \brief The QCameraControl class is an abstract base class for + classes that control still cameras or video cameras. + + \inmodule QtMultimedia + \ingroup multimedia-serv + \since 1.1 + + This service is provided by a QMediaService object via + QMediaService::control(). It is used by QCamera. + + The interface name of QCameraControl is \c com.nokia.Qt.QCameraControl/1.0 as + defined in QCameraControl_iid. + + + + \sa QMediaService::requestControl(), QCamera +*/ + +/*! + \macro QCameraControl_iid + + \c com.nokia.Qt.QCameraControl/1.0 + + Defines the interface name of the QCameraControl class. + + \relates QCameraControl +*/ + +/*! + Constructs a camera control object with \a parent. +*/ + +QCameraControl::QCameraControl(QObject *parent): + QMediaControl(*new QMediaControlPrivate, parent) +{ +} + +/*! + Destruct the camera control object. +*/ + +QCameraControl::~QCameraControl() +{ +} + +/*! + \fn QCameraControl::state() const + + Returns the state of the camera service. + + \since 1.1 + \sa QCamera::state +*/ + +/*! + \fn QCameraControl::setState(QCamera::State state) + + Sets the camera \a state. + + State changes are synchronous and indicate user intention, + while camera status is used as a feedback mechanism to inform application about backend status. + Status changes are reported asynchronously with QCameraControl::statusChanged() signal. + + \since 1.1 + \sa QCamera::State +*/ + +/*! + \fn void QCameraControl::stateChanged(QCamera::State state) + + Signal emitted when the camera \a state changes. + + In most cases the state chage is caused by QCameraControl::setState(), + but if critical error has occurred the state changes to QCamera::UnloadedState. + \since 1.1 +*/ + +/*! + \fn QCameraControl::status() const + + Returns the status of the camera service. + + \since 1.1 + \sa QCamera::state +*/ + +/*! + \fn void QCameraControl::statusChanged(QCamera::Status status) + + Signal emitted when the camera \a status changes. + \since 1.1 +*/ + + +/*! + \fn void QCameraControl::error(int error, const QString &errorString) + + Signal emitted when an error occurs with error code \a error and + a description of the error \a errorString. + \since 1.1 +*/ + +/*! + \fn Camera::CaptureMode QCameraControl::captureMode() const = 0 + + Returns the current capture mode. + \since 1.1 +*/ + +/*! + \fn void QCameraControl::setCaptureMode(QCamera::CaptureMode mode) = 0; + + Sets the current capture \a mode. + + The capture mode changes are synchronous and allowed in any camera state. + + If the capture mode is changed while camera is active, + it's recommended to change status to QCamera::LoadedStatus + and start activating the camera in the next event loop + with the status changed to QCamera::StartingStatus. + This allows the capture settings to be applied before camera is started. + Than change the status to QCamera::StartedStatus when the capture mode change is done. + \since 1.1 +*/ + +/*! + \fn bool QCameraControl::isCaptureModeSupported(QCamera::CaptureMode mode) const = 0; + + Returns true if the capture \a mode is suported. + \since 1.1 +*/ + +/*! + \fn QCameraControl::captureModeChanged(QCamera::CaptureMode mode) + + Signal emitted when the camera capture \a mode changes. + \since 1.1 + */ + +/*! + \fn bool QCameraControl::canChangeProperty(PropertyChangeType changeType, QCamera::Status status) const + + Returns true if backend can effectively apply changing camera properties of \a changeType type + while the camera state is QCamera::Active and camera status matches \a status parameter. + + If backend doesn't support applying this change in the active state, it will be stopped + before the settings are changed and restarted after. + Otherwise the backend should apply the change in the current state, + with the camera status indicating the progress, if necessary. + \since 1.1 +*/ + +/*! + \enum QCameraControl::PropertyChangeType + + \value CaptureMode Indicates the capture mode is changed. + \value ImageEncodingSettings Image encoder settings are changed, including resolution. + \value VideoEncodingSettings + Video encoder settings are changed, including audio, video and container settings. + \value Viewfinder Viewfinder is changed. +*/ + +#include "moc_qcameracontrol.cpp" +QT_END_NAMESPACE diff --git a/src/multimedia/qcameracontrol.h b/src/multimedia/qcameracontrol.h new file mode 100644 index 000000000..dfc2b3743 --- /dev/null +++ b/src/multimedia/qcameracontrol.h @@ -0,0 +1,101 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QCAMERACONTROL_H +#define QCAMERACONTROL_H + +#include <qmediacontrol.h> +#include <qmediaobject.h> + +#include <qcamera.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + +class Q_MULTIMEDIA_EXPORT QCameraControl : public QMediaControl +{ + Q_OBJECT + +public: + enum PropertyChangeType { + CaptureMode = 1, + ImageEncodingSettings = 2, + VideoEncodingSettings = 3, + Viewfinder = 4 + }; + + ~QCameraControl(); + + virtual QCamera::State state() const = 0; + virtual void setState(QCamera::State state) = 0; + + virtual QCamera::Status status() const = 0; + + virtual QCamera::CaptureMode captureMode() const = 0; + virtual void setCaptureMode(QCamera::CaptureMode) = 0; + virtual bool isCaptureModeSupported(QCamera::CaptureMode mode) const = 0; + + virtual bool canChangeProperty(PropertyChangeType changeType, QCamera::Status status) const = 0; + +Q_SIGNALS: + void stateChanged(QCamera::State); + void statusChanged(QCamera::Status); + void error(int error, const QString &errorString); + void captureModeChanged(QCamera::CaptureMode); + +protected: + QCameraControl(QObject* parent = 0); +}; + +#define QCameraControl_iid "com.nokia.Qt.QCameraControl/1.0" +Q_MEDIA_DECLARE_CONTROL(QCameraControl, QCameraControl_iid) + +QT_END_NAMESPACE + +QT_END_HEADER + + +#endif // QCAMERACONTROL_H + diff --git a/src/multimedia/qcameraexposure.cpp b/src/multimedia/qcameraexposure.cpp new file mode 100644 index 000000000..580b1cad9 --- /dev/null +++ b/src/multimedia/qcameraexposure.cpp @@ -0,0 +1,646 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QDebug> + +#include <qcameraexposure.h> +#include <qcamera.h> + +#include <qmediaobject_p.h> +#include <qcameraexposurecontrol.h> +#include <qcameraflashcontrol.h> +#include <qmetaobject.h> + +QT_BEGIN_NAMESPACE + +/*! + \class QCameraExposure + + + \brief The QCameraExposure class provides interface for exposure related camera settings. + + \inmodule QtMultimedia + \ingroup camera + \since 1.1 + +*/ + +//#define DEBUG_EXPOSURE_CHANGES 1 + +#ifdef DEBUG_EXPOSURE_CHANGES +#define ENUM_NAME(c,e,v) (c::staticMetaObject.enumerator(c::staticMetaObject.indexOfEnumerator(e)).valueToKey((v))) +#endif + +namespace +{ +class CameraExposureRegisterMetaTypes +{ +public: + CameraExposureRegisterMetaTypes() + { + qRegisterMetaType<QCameraExposure::ExposureMode>("QCameraExposure::ExposureMode"); + qRegisterMetaType<QCameraExposure::FlashModes>("QCameraExposure::FlashModes"); + qRegisterMetaType<QCameraExposure::MeteringMode>("QCameraExposure::MeteringMode"); + } +} _registerCameraExposureMetaTypes; +} + + + +class QCameraExposurePrivate +{ + Q_DECLARE_NON_CONST_PUBLIC(QCameraExposure) +public: + void initControls(); + QCameraExposure *q_ptr; + + QCamera *camera; + QCameraExposureControl *exposureControl; + QCameraFlashControl *flashControl; + + void _q_exposureParameterChanged(int parameter); + void _q_exposureParameterRangeChanged(int parameter); +}; + +void QCameraExposurePrivate::initControls() +{ + Q_Q(QCameraExposure); + + QMediaService *service = camera->service(); + exposureControl = 0; + flashControl = 0; + if (service) { + exposureControl = qobject_cast<QCameraExposureControl *>(service->requestControl(QCameraExposureControl_iid)); + flashControl = qobject_cast<QCameraFlashControl *>(service->requestControl(QCameraFlashControl_iid)); + } + if (exposureControl) { + q->connect(exposureControl, SIGNAL(exposureParameterChanged(int)), + q, SLOT(_q_exposureParameterChanged(int))); + q->connect(exposureControl, SIGNAL(exposureParameterRangeChanged(int)), + q, SLOT(_q_exposureParameterRangeChanged(int))); + } + + if (flashControl) + q->connect(flashControl, SIGNAL(flashReady(bool)), q, SIGNAL(flashReady(bool))); +} + +void QCameraExposurePrivate::_q_exposureParameterChanged(int parameter) +{ + Q_Q(QCameraExposure); + +#if DEBUG_EXPOSURE_CHANGES + qDebug() << "Exposure parameter changed:" + << ENUM_NAME(QCameraExposureControl, "ExposureParameter", parameter) + << exposureControl->exposureParameter(QCameraExposureControl::ExposureParameter(parameter)); +#endif + + switch (parameter) { + case QCameraExposureControl::ISO: + emit q->isoSensitivityChanged(q->isoSensitivity()); + break; + case QCameraExposureControl::Aperture: + emit q->apertureChanged(q->aperture()); + break; + case QCameraExposureControl::ShutterSpeed: + emit q->shutterSpeedChanged(q->shutterSpeed()); + break; + case QCameraExposureControl::ExposureCompensation: + emit q->exposureCompensationChanged(q->exposureCompensation()); + break; + } +} + +void QCameraExposurePrivate::_q_exposureParameterRangeChanged(int parameter) +{ + Q_Q(QCameraExposure); + + switch (parameter) { + case QCameraExposureControl::Aperture: + emit q->apertureRangeChanged(); + break; + case QCameraExposureControl::ShutterSpeed: + emit q->shutterSpeedRangeChanged(); + break; + } +} + +/*! + Construct a QCameraExposure from service \a provider and \a parent. +*/ + +QCameraExposure::QCameraExposure(QCamera *parent): + QObject(parent), d_ptr(new QCameraExposurePrivate) +{ + Q_D(QCameraExposure); + d->camera = parent; + d->q_ptr = this; + d->initControls(); +} + + +/*! + Destroys the camera exposure object. +*/ + +QCameraExposure::~QCameraExposure() +{ + Q_D(QCameraExposure); + if (d->exposureControl) + d->camera->service()->releaseControl(d->exposureControl); +} + +/*! + Returns true if exposure settings are supported by this camera. + \since 1.1 +*/ +bool QCameraExposure::isAvailable() const +{ + return d_func()->exposureControl != 0; +} + + +/*! + \property QCameraExposure::flashMode + \brief The flash mode being used. + + Usually the single QCameraExposure::FlashMode flag is used, + but some non conflicting flags combination are also allowed, + like QCameraExposure::FlashManual | QCameraExposure::FlashSlowSyncRearCurtain. + + \since 1.1 + \sa QCameraExposure::isFlashModeSupported(), QCameraExposure::isFlashReady() +*/ + +QCameraExposure::FlashModes QCameraExposure::flashMode() const +{ + return d_func()->flashControl ? d_func()->flashControl->flashMode() : QCameraExposure::FlashOff; +} + +void QCameraExposure::setFlashMode(QCameraExposure::FlashModes mode) +{ + if (d_func()->flashControl) + d_func()->flashControl->setFlashMode(mode); +} + +/*! + Returns true if the flash \a mode is supported. + \since 1.1 +*/ + +bool QCameraExposure::isFlashModeSupported(QCameraExposure::FlashModes mode) const +{ + return d_func()->flashControl ? d_func()->flashControl->isFlashModeSupported(mode) : false; +} + +/*! + Returns true if flash is charged. +*/ + +bool QCameraExposure::isFlashReady() const +{ + return d_func()->flashControl ? d_func()->flashControl->isFlashReady() : false; +} + + +/*! + \property QCameraExposure::exposureMode + \brief The exposure mode being used. + + \since 1.1 + \sa QCameraExposure::isExposureModeSupported() +*/ + +QCameraExposure::ExposureMode QCameraExposure::exposureMode() const +{ + return d_func()->exposureControl ? d_func()->exposureControl->exposureMode() : QCameraExposure::ExposureAuto; +} + +void QCameraExposure::setExposureMode(QCameraExposure::ExposureMode mode) +{ + if (d_func()->exposureControl) + d_func()->exposureControl->setExposureMode(mode); +} + +/*! + Returns true if the exposure \a mode is supported. + \since 1.1 +*/ + +bool QCameraExposure::isExposureModeSupported(QCameraExposure::ExposureMode mode) const +{ + return d_func()->exposureControl ? + d_func()->exposureControl->isExposureModeSupported(mode) : false; +} + +/*! + \property QCameraExposure::exposureCompensation + \brief Exposure compensation in EV units. + + Exposure compensation property allows to adjust the automatically calculated exposure. + \since 1.1 +*/ + +qreal QCameraExposure::exposureCompensation() const +{ + if (d_func()->exposureControl) + return d_func()->exposureControl->exposureParameter(QCameraExposureControl::ExposureCompensation).toReal(); + else + return 0; +} + +void QCameraExposure::setExposureCompensation(qreal ev) +{ + if (d_func()->exposureControl) + d_func()->exposureControl->setExposureParameter(QCameraExposureControl::ExposureCompensation, QVariant(ev)); +} + +/*! + \property QCameraExposure::meteringMode + \brief The metering mode being used. + + \since 1.1 + \sa QCameraExposure::isMeteringModeSupported() +*/ + +QCameraExposure::MeteringMode QCameraExposure::meteringMode() const +{ + return d_func()->exposureControl ? d_func()->exposureControl->meteringMode() : QCameraExposure::MeteringMatrix; +} + +void QCameraExposure::setMeteringMode(QCameraExposure::MeteringMode mode) +{ + if (d_func()->exposureControl) + d_func()->exposureControl->setMeteringMode(mode); +} + +/*! + Returns true if the metering \a mode is supported. + \since 1.1 +*/ +bool QCameraExposure::isMeteringModeSupported(QCameraExposure::MeteringMode mode) const +{ + return d_func()->exposureControl ? d_func()->exposureControl->isMeteringModeSupported(mode) : false; +} + +int QCameraExposure::isoSensitivity() const +{ + if (d_func()->exposureControl) + return d_func()->exposureControl->exposureParameter(QCameraExposureControl::ISO).toInt(); + + return -1; +} + +/*! + Returns the list of ISO senitivities camera supports. + + If the camera supports arbitrary ISO sensitivities within the supported range, + *\a continuous is set to true, otherwise *\a continuous is set to false. + \since 1.1 +*/ +QList<int> QCameraExposure::supportedIsoSensitivities(bool *continuous) const +{ + QList<int> res; + QCameraExposureControl *control = d_func()->exposureControl; + + if (!control) + return res; + + foreach (const QVariant &value, + control->supportedParameterRange(QCameraExposureControl::ISO)) { + bool ok = false; + int intValue = value.toInt(&ok); + if (ok) + res.append(intValue); + else + qWarning() << "Incompatible ISO value type, int is expected"; + } + + if (continuous) + *continuous = control->exposureParameterFlags(QCameraExposureControl::ISO) & + QCameraExposureControl::ContinuousRange; + + return res; +} + +/*! + \fn QCameraExposure::setManualIsoSensitivity(int iso) + Sets the manual sensitivity to \a iso + \since 1.1 +*/ + +void QCameraExposure::setManualIsoSensitivity(int iso) +{ + if (d_func()->exposureControl) + d_func()->exposureControl->setExposureParameter(QCameraExposureControl::ISO, QVariant(iso)); +} + +/*! + \fn QCameraExposure::setAutoIsoSensitivity() + Turn on auto sensitivity + \since 1.1 +*/ + +void QCameraExposure::setAutoIsoSensitivity() +{ + if (d_func()->exposureControl) + d_func()->exposureControl->setExposureParameter(QCameraExposureControl::ISO, QVariant()); +} + +/*! + \property QCameraExposure::shutterSpeed + \brief Camera's shutter speed in seconds. + + \since 1.1 + \sa supportedShutterSpeeds(), setAutoShutterSpeed(), setManualShutterSpeed() +*/ + +/*! + \fn QCameraExposure::shutterSpeedChanged(qreal speed) + + Signals that a camera's shutter \a speed has changed. + \since 1.1 +*/ + +/*! + \property QCameraExposure::isoSensitivity + \brief The sensor ISO sensitivity. + + \sa supportedIsoSensitivities(), setAutoIsoSensitivity(), setManualIsoSensitivity() + \since 1.1 +*/ + +/*! + \property QCameraExposure::aperture + \brief Lens aperture is specified as an F number, the ratio of the focal length to effective aperture diameter. + + \since 1.1 + \sa supportedApertures(), setAutoAperture(), setManualAperture() +*/ + + +qreal QCameraExposure::aperture() const +{ + if (d_func()->exposureControl) + return d_func()->exposureControl->exposureParameter(QCameraExposureControl::Aperture).toReal(); + + return -1.0; +} + +/*! + Returns the list of aperture values camera supports. + The apertures list can change depending on the focal length, + in such a case the apertureRangeChanged() signal is emitted. + + If the camera supports arbitrary aperture values within the supported range, + *\a continuous is set to true, otherwise *\a continuous is set to false. + \since 1.1 +*/ +QList<qreal> QCameraExposure::supportedApertures(bool * continuous) const +{ + QList<qreal> res; + QCameraExposureControl *control = d_func()->exposureControl; + + if (!control) + return res; + + foreach (const QVariant &value, + control->supportedParameterRange(QCameraExposureControl::Aperture)) { + bool ok = false; + qreal realValue = value.toReal(&ok); + if (ok) + res.append(realValue); + else + qWarning() << "Incompatible aperture value type, qreal is expected"; + } + + if (continuous) + *continuous = control->exposureParameterFlags(QCameraExposureControl::Aperture) & + QCameraExposureControl::ContinuousRange; + + return res; +} + +/*! + \fn QCameraExposure::setManualAperture(qreal aperture) + Sets the manual camera \a aperture value. + \since 1.1 +*/ + +void QCameraExposure::setManualAperture(qreal aperture) +{ + if (d_func()->exposureControl) + d_func()->exposureControl->setExposureParameter(QCameraExposureControl::Aperture, QVariant(aperture)); +} + +/*! + \fn QCameraExposure::setAutoAperture() + Turn on auto aperture + \since 1.1 +*/ + +void QCameraExposure::setAutoAperture() +{ + if (d_func()->exposureControl) + d_func()->exposureControl->setExposureParameter(QCameraExposureControl::Aperture, QVariant()); +} + +/*! + Returns the current shutter speed in seconds. + \since 1.1 +*/ + +qreal QCameraExposure::shutterSpeed() const +{ + if (d_func()->exposureControl) + return d_func()->exposureControl->exposureParameter(QCameraExposureControl::ShutterSpeed).toReal(); + + return -1.0; +} + +/*! + Returns the list of shutter speed values in seconds camera supports. + + If the camera supports arbitrary shutter speed values within the supported range, + *\a continuous is set to true, otherwise *\a continuous is set to false. + \since 1.1 +*/ +QList<qreal> QCameraExposure::supportedShutterSpeeds(bool *continuous) const +{ + QList<qreal> res; + + QCameraExposureControl *control = d_func()->exposureControl; + if (!control) + return res; + + foreach (const QVariant &value, + control->supportedParameterRange(QCameraExposureControl::ShutterSpeed)) { + bool ok = false; + qreal realValue = value.toReal(&ok); + if (ok) + res.append(realValue); + else + qWarning() << "Incompatible shutter speed value type, qreal is expected"; + } + + if (continuous) + *continuous = control->exposureParameterFlags(QCameraExposureControl::ShutterSpeed) & + QCameraExposureControl::ContinuousRange; + + return res; +} + +/*! + Set the manual shutter speed to \a seconds + \since 1.1 +*/ + +void QCameraExposure::setManualShutterSpeed(qreal seconds) +{ + if (d_func()->exposureControl) + d_func()->exposureControl->setExposureParameter(QCameraExposureControl::ShutterSpeed, QVariant(seconds)); +} + +/*! + Turn on auto shutter speed + \since 1.1 +*/ + +void QCameraExposure::setAutoShutterSpeed() +{ + if (d_func()->exposureControl) + d_func()->exposureControl->setExposureParameter(QCameraExposureControl::ShutterSpeed, QVariant()); +} + + +/*! + \enum QCameraExposure::FlashMode + + \value FlashOff Flash is Off. + \value FlashOn Flash is On. + \value FlashAuto Automatic flash. + \value FlashRedEyeReduction Red eye reduction flash. + \value FlashFill Use flash to fillin shadows. + \value FlashTorch Constant light source, useful for focusing and video capture. + \value FlashSlowSyncFrontCurtain + Use the flash in conjunction with a slow shutter speed. + This mode allows better exposure of distant objects and/or motion blur effect. + \value FlashSlowSyncRearCurtain + The similar mode to FlashSlowSyncFrontCurtain but flash is fired at the end of exposure. + \value FlashManual Flash power is manualy set. +*/ + +/*! + \enum QCameraExposure::ExposureMode + + \value ExposureManual Manual mode. + \value ExposureAuto Automatic mode. + \value ExposureNight Night mode. + \value ExposureBacklight Backlight exposure mode. + \value ExposureSpotlight Spotlight exposure mode. + \value ExposureSports Spots exposure mode. + \value ExposureSnow Snow exposure mode. + \value ExposureBeach Beach exposure mode. + \value ExposureLargeAperture Use larger aperture with small depth of field. + \value ExposureSmallAperture Use smaller aperture. + \value ExposurePortrait Portrait exposure mode. + \value ExposureModeVendor The base value for device specific exposure modes. +*/ + +/*! + \enum QCameraExposure::MeteringMode + + \value MeteringAverage Center weighted average metering mode. + \value MeteringSpot Spot metering mode. + \value MeteringMatrix Matrix metering mode. +*/ + +/*! + \property QCameraExposure::flashReady + \brief Indicates if the flash is charged and ready to use. + \since 1.1 +*/ + +/*! + \fn void QCameraExposure::flashReady(bool ready) + + Signal the flash \a ready status has changed. + \since 1.1 +*/ + +/*! + \fn void QCameraExposure::apertureChanged(qreal value) + + Signal emitted when aperature changes to \a value. + \since 1.1 +*/ + +/*! + \fn void QCameraExposure::apertureRangeChanged() + + Signal emitted when aperature range has changed. + \since 1.1 +*/ + + +/*! + \fn void QCameraExposure::shutterSpeedRangeChanged() + + Signal emitted when the shutter speed range has changed. + \since 1.1 +*/ + + +/*! + \fn void QCameraExposure::isoSensitivityChanged(int value) + + Signal emitted when sensitivity changes to \a value. + \since 1.1 +*/ + +/*! + \fn void QCameraExposure::exposureCompensationChanged(qreal value) + + Signal emitted when the exposure compensation changes to \a value. + \since 1.1 +*/ + +#include "moc_qcameraexposure.cpp" +QT_END_NAMESPACE diff --git a/src/multimedia/qcameraexposure.h b/src/multimedia/qcameraexposure.h new file mode 100644 index 000000000..088e7c036 --- /dev/null +++ b/src/multimedia/qcameraexposure.h @@ -0,0 +1,185 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QCAMERAEXPOSURE_H +#define QCAMERAEXPOSURE_H + +#include <qmediaobject.h> +#include <qmediaenumdebug.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + +class QCamera; +class QCameraExposurePrivate; + +class Q_MULTIMEDIA_EXPORT QCameraExposure : public QObject +{ + Q_OBJECT + Q_PROPERTY(qreal aperture READ aperture NOTIFY apertureChanged) + Q_PROPERTY(qreal shutterSpeed READ shutterSpeed NOTIFY shutterSpeedChanged) + Q_PROPERTY(int isoSensitivity READ isoSensitivity NOTIFY isoSensitivityChanged) + Q_PROPERTY(qreal exposureCompensation READ exposureCompensation WRITE setExposureCompensation NOTIFY exposureCompensationChanged) + Q_PROPERTY(bool flashReady READ isFlashReady NOTIFY flashReady) + Q_PROPERTY(QCameraExposure::FlashModes flashMode READ flashMode WRITE setFlashMode) + Q_PROPERTY(QCameraExposure::ExposureMode exposureMode READ exposureMode WRITE setExposureMode) + Q_PROPERTY(QCameraExposure::MeteringMode meteringMode READ meteringMode WRITE setMeteringMode) + + Q_ENUMS(FlashMode) + Q_ENUMS(ExposureMode) + Q_ENUMS(MeteringMode) +public: + enum FlashMode { + FlashAuto = 0x1, + FlashOff = 0x2, + FlashOn = 0x4, + FlashRedEyeReduction = 0x8, + FlashFill = 0x10, + FlashTorch = 0x20, + FlashSlowSyncFrontCurtain = 0x40, + FlashSlowSyncRearCurtain = 0x80, + FlashManual = 0x100 + }; + Q_DECLARE_FLAGS(FlashModes, FlashMode) + + enum ExposureMode { + ExposureAuto = 0, + ExposureManual = 1, + ExposurePortrait = 2, + ExposureNight = 3, + ExposureBacklight = 4, + ExposureSpotlight = 5, + ExposureSports = 6, + ExposureSnow = 7, + ExposureBeach = 8, + ExposureLargeAperture = 9, + ExposureSmallAperture = 10, + ExposureModeVendor = 1000 + }; + + enum MeteringMode { + MeteringMatrix = 1, + MeteringAverage = 2, + MeteringSpot = 3 + }; + + bool isAvailable() const; + + FlashModes flashMode() const; + bool isFlashModeSupported(FlashModes mode) const; + bool isFlashReady() const; + + ExposureMode exposureMode() const; + bool isExposureModeSupported(ExposureMode mode) const; + + qreal exposureCompensation() const; + + MeteringMode meteringMode() const; + + bool isMeteringModeSupported(MeteringMode mode) const; + + int isoSensitivity() const; + QList<int> supportedIsoSensitivities(bool *continuous = 0) const; + + qreal aperture() const; + QList<qreal> supportedApertures(bool *continuous = 0) const; + + qreal shutterSpeed() const; + QList<qreal> supportedShutterSpeeds(bool *continuous = 0) const; + +public Q_SLOTS: + void setFlashMode(FlashModes mode); + void setExposureMode(ExposureMode mode); + + void setExposureCompensation(qreal ev); + + void setMeteringMode(MeteringMode mode); + + void setManualIsoSensitivity(int iso); + void setAutoIsoSensitivity(); + + void setManualAperture(qreal aperture); + void setAutoAperture(); + + void setManualShutterSpeed(qreal seconds); + void setAutoShutterSpeed(); + +Q_SIGNALS: + void flashReady(bool); + + void apertureChanged(qreal); + void apertureRangeChanged(); + void shutterSpeedChanged(qreal); + void shutterSpeedRangeChanged(); + void isoSensitivityChanged(int); + void exposureCompensationChanged(qreal); + +private: + friend class QCamera; + explicit QCameraExposure(QCamera *parent = 0); + virtual ~QCameraExposure(); + + Q_DISABLE_COPY(QCameraExposure) + Q_DECLARE_PRIVATE(QCameraExposure) + Q_PRIVATE_SLOT(d_func(), void _q_exposureParameterChanged(int)) + Q_PRIVATE_SLOT(d_func(), void _q_exposureParameterRangeChanged(int)) + QCameraExposurePrivate *d_ptr; +}; + +Q_DECLARE_OPERATORS_FOR_FLAGS(QCameraExposure::FlashModes) + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(QCameraExposure::ExposureMode) +Q_DECLARE_METATYPE(QCameraExposure::FlashModes) +Q_DECLARE_METATYPE(QCameraExposure::MeteringMode) + +Q_MEDIA_ENUM_DEBUG(QCameraExposure, ExposureMode) +Q_MEDIA_ENUM_DEBUG(QCameraExposure, FlashMode) +Q_MEDIA_ENUM_DEBUG(QCameraExposure, MeteringMode) + +QT_END_HEADER + +#endif // QCAMERAEXPOSURE_H diff --git a/src/multimedia/qcameraexposurecontrol.cpp b/src/multimedia/qcameraexposurecontrol.cpp new file mode 100644 index 000000000..4a6f655f8 --- /dev/null +++ b/src/multimedia/qcameraexposurecontrol.cpp @@ -0,0 +1,252 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <qcameraexposurecontrol.h> +#include "qmediacontrol_p.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QCameraExposureControl + + \brief The QCameraExposureControl class allows controlling camera exposure parameters. + + \inmodule QtMultimedia + \ingroup multimedia-serv + \since 1.1 + + You can adjust a number of parameters that will affect images and video taken with + the corresponding QCamera object. + + There are a number of different parameters that can be adjusted, including: + + \table + \row + \header + \ + + \endtable + + The interface name of QCameraExposureControl is \c com.nokia.Qt.QCameraExposureControl/1.0 as + defined in QCameraExposureControl_iid. + + \sa QCamera +*/ + +/*! + \macro QCameraExposureControl_iid + + \c com.nokia.Qt.QCameraExposureControl/1.0 + + Defines the interface name of the QCameraExposureControl class. + + \relates QCameraExposureControl +*/ + +/*! + Constructs a camera exposure control object with \a parent. +*/ +QCameraExposureControl::QCameraExposureControl(QObject *parent): + QMediaControl(*new QMediaControlPrivate, parent) +{ +} + +/*! + Destroys the camera control object. +*/ +QCameraExposureControl::~QCameraExposureControl() +{ +} + +/*! + \fn QCamera::ExposureMode QCameraExposureControl::exposureMode() const + + Returns the exposure mode. + \since 1.1 +*/ + + +/*! + \fn void QCameraExposureControl::setExposureMode(QCameraExposure::ExposureMode mode) + + Set the exposure mode to \a mode. + \since 1.1 +*/ + + +/*! + \fn bool QCameraExposureControl::isExposureModeSupported(QCameraExposure::ExposureMode mode) const + + Returns true if the exposure \a mode is supported. + \since 1.1 +*/ + + +/*! + \fn QCameraExposure::MeteringMode QCameraExposureControl::meteringMode() const + Returns the current metering mode. + \since 1.1 +*/ + +/*! + \fn void QCameraExposureControl::setMeteringMode(QCameraExposure::MeteringMode mode) + + Set the metering mode to \a mode. + \since 1.1 +*/ + + +/*! + \fn bool QCameraExposureControl::isMeteringModeSupported(QCameraExposure::MeteringMode mode) const + Returns true if the metering \a mode is supported. + \since 1.1 +*/ + +/*! + \enum QCameraExposureControl::ExposureParameter + \value InvalidParameter + Parameter is invalid. + \value ISO + Camera ISO sensitivity, specified as integer value. + \value Aperture + Lens aperture is specified as an qreal F number. + The supported apertures list can change depending on the focal length, + in such a case the exposureParameterRangeChanged() signal is emitted. + \value ShutterSpeed + Shutter speed in seconds, specified as qreal. + \value ExposureCompensation + Exposure compensation, specified as qreal EV value. + \value FlashPower + Manual flash power, specified as qreal value. + Accepted power range is [0..1.0], + with 0 value means no flash and 1.0 corresponds to full flash power. + + This value is only used in the \l{QCameraExposure::FlashManual}{manual flash mode}. + \value FlashCompensation + Flash compensation, specified as qreal EV value. + \value ExtendedExposureParameter + The base value for platform specific extended parameters. + For such parameters the sequential values starting from ExtendedExposureParameter shuld be used. +*/ + +/*! + \enum QCameraExposureControl::ParameterFlag + \value AutomaticValue + Use the automatic values for parameters. + \value ReadOnly + Parameters are read only. + \value ContinuousRange + Parameters are continuous in their range. +*/ + +/*! + \fn QCameraExposureControl::isParameterSupported(ExposureParameter parameter) const + + Returns true is exposure \a parameter is supported by backend. + \since 1.1 +*/ + +/*! + \fn QCameraExposureControl::exposureParameter(ExposureParameter parameter) const + + Returns the exposure \a parameter value, or invalid QVariant() if the value is unknown or not supported. + \since 1.1 +*/ + +/*! + \fn QCameraExposureControl::exposureParameterFlags(ExposureParameter parameter) const + + Returns the properties of exposure \a parameter. + \since 1.1 +*/ + + +/*! + \fn QCameraExposureControl::supportedParameterRange(ExposureParameter parameter) const + + Returns the list of supported \a parameter values; + \since 1.1 +*/ + +/*! + \fn bool QCameraExposureControl::setExposureParameter(ExposureParameter parameter, const QVariant& value) + + Set the exposure \a parameter to \a value. + If a null or invalid QVariant is passed, backend should choose the value automatically, + and if possible report the actual value to user with QCameraExposureControl::exposureParameter(). + + Returns true if parameter is supported and value is correct. + \since 1.1 +*/ + +/*! + \fn QCameraExposureControl::extendedParameterName(ExposureParameter parameter) + + Returns the extended exposure \a parameter name. + \since 1.1 +*/ + +/*! + \fn void QCameraExposureControl::flashReady(bool ready) + + Signal emitted when flash state changes, flash is charged \a ready. + \since 1.1 +*/ + +/*! + \fn void QCameraExposureControl::exposureParameterChanged(int parameter) + + Signal emitted when the exposure \a parameter has changed. + \since 1.1 +*/ + +/*! + + \fn void QCameraExposureControl::exposureParameterRangeChanged(int parameter) + + Signal emitted when the exposure \a parameter range has changed. + \since 1.1 +*/ + + +#include "moc_qcameraexposurecontrol.cpp" +QT_END_NAMESPACE + diff --git a/src/multimedia/qcameraexposurecontrol.h b/src/multimedia/qcameraexposurecontrol.h new file mode 100644 index 000000000..ff60784bf --- /dev/null +++ b/src/multimedia/qcameraexposurecontrol.h @@ -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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QCAMERAEXPOSURECONTROL_H +#define QCAMERAEXPOSURECONTROL_H + +#include <qmediacontrol.h> +#include <qmediaobject.h> + +#include <qcameraexposure.h> +#include <qcamera.h> +#include <qmediaenumdebug.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + +class Q_MULTIMEDIA_EXPORT QCameraExposureControl : public QMediaControl +{ + Q_OBJECT + Q_ENUMS(ExposureParameter) + +public: + ~QCameraExposureControl(); + + enum ExposureParameter { + InvalidParameter = 0, + ISO = 1, + Aperture = 2, + ShutterSpeed = 3, + ExposureCompensation = 4, + FlashPower = 5, + FlashCompensation = 6, + ExtendedExposureParameter = 1000 + }; + + enum ParameterFlag { + AutomaticValue = 0x01, + ReadOnly = 0x02, + ContinuousRange = 0x04 + }; + Q_DECLARE_FLAGS(ParameterFlags, ParameterFlag) + + virtual QCameraExposure::ExposureMode exposureMode() const = 0; + virtual void setExposureMode(QCameraExposure::ExposureMode mode) = 0; + virtual bool isExposureModeSupported(QCameraExposure::ExposureMode mode) const = 0; + + virtual QCameraExposure::MeteringMode meteringMode() const = 0; + virtual void setMeteringMode(QCameraExposure::MeteringMode mode) = 0; + virtual bool isMeteringModeSupported(QCameraExposure::MeteringMode mode) const = 0; + + virtual bool isParameterSupported(ExposureParameter parameter) const = 0; + virtual QVariant exposureParameter(ExposureParameter parameter) const = 0; + virtual ParameterFlags exposureParameterFlags(ExposureParameter parameter) const = 0; + virtual QVariantList supportedParameterRange(ExposureParameter parameter) const = 0; + virtual bool setExposureParameter(ExposureParameter parameter, const QVariant& value) = 0; + + virtual QString extendedParameterName(ExposureParameter parameter) = 0; + +Q_SIGNALS: + void flashReady(bool); + + void exposureParameterChanged(int parameter); + void exposureParameterRangeChanged(int parameter); + +protected: + QCameraExposureControl(QObject* parent = 0); +}; + +#define QCameraExposureControl_iid "com.nokia.Qt.QCameraExposureControl/1.0" +Q_MEDIA_DECLARE_CONTROL(QCameraExposureControl, QCameraExposureControl_iid) + +Q_DECLARE_OPERATORS_FOR_FLAGS(QCameraExposureControl::ParameterFlags) + +Q_MEDIA_ENUM_DEBUG(QCameraExposureControl, ExposureParameter) + +QT_END_NAMESPACE + +QT_END_HEADER + + +#endif // QCAMERAEXPOSURECONTROL_H + diff --git a/src/multimedia/qcameraflashcontrol.cpp b/src/multimedia/qcameraflashcontrol.cpp new file mode 100644 index 000000000..34dcbdeb5 --- /dev/null +++ b/src/multimedia/qcameraflashcontrol.cpp @@ -0,0 +1,141 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <qcameraflashcontrol.h> +#include "qmediacontrol_p.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QCameraFlashControl + + \brief The QCameraFlashControl class allows controlling a camera's flash. + + \ingroup multimedia-serv + \inmodule QtMultimedia + \since 1.1 + + \inmodule QtMultimedia + + You can set the type of flash effect used when an image is captured, and test to see + if the flash hardware is ready to fire. + + You can retrieve this control from the camera object in the usual way: + + Some camera devices may not have flash hardware, or may not be configurable. In that + case, there will be no QCameraFlashControl available. + + The interface name of QCameraFlashControl is \c com.nokia.Qt.QCameraFlashControl/1.0 as + defined in QCameraFlashControl_iid. + + \sa QCamera +*/ + +/*! + \macro QCameraFlashControl_iid + + \c com.nokia.Qt.QCameraFlashControl/1.0 + + Defines the interface name of the QCameraFlashControl class. + + \relates QCameraFlashControl +*/ + +/*! + Constructs a camera flash control object with \a parent. +*/ +QCameraFlashControl::QCameraFlashControl(QObject *parent): + QMediaControl(*new QMediaControlPrivate, parent) +{ +} + +/*! + Destroys the camera control object. +*/ +QCameraFlashControl::~QCameraFlashControl() +{ +} + +/*! + \fn QCamera::FlashModes QCameraFlashControl::flashMode() const + + Returns the current flash mode. + \since 1.1 +*/ + +/*! + \fn void QCameraFlashControl::setFlashMode(QCameraExposure::FlashModes mode) + + Set the current flash \a mode. + + Usually a single QCameraExposure::FlashMode flag is used, + but some non conflicting flags combination are also allowed, + like QCameraExposure::FlashManual | QCameraExposure::FlashSlowSyncRearCurtain. + \since 1.1 +*/ + + +/*! + \fn QCameraFlashControl::isFlashModeSupported(QCameraExposure::FlashModes mode) const + + Return true if the reqested flash \a mode is supported. + Some QCameraExposure::FlashMode values can be combined, + for example QCameraExposure::FlashManual | QCameraExposure::FlashSlowSyncRearCurtain + \since 1.1 +*/ + +/*! + \fn bool QCameraFlashControl::isFlashReady() const + + Returns true if flash is charged. + \since 1.1 +*/ + +/*! + \fn void QCameraFlashControl::flashReady(bool ready) + + Signal emitted when flash state changes to \a ready. + \since 1.1 +*/ + +#include "moc_qcameraflashcontrol.cpp" +QT_END_NAMESPACE + diff --git a/src/multimedia/qcameraflashcontrol.h b/src/multimedia/qcameraflashcontrol.h new file mode 100644 index 000000000..89b3b9d06 --- /dev/null +++ b/src/multimedia/qcameraflashcontrol.h @@ -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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QCAMERAFLASHCONTROL_H +#define QCAMERAFLASHCONTROL_H + +#include <qmediacontrol.h> +#include <qmediaobject.h> + +#include <qcameraexposure.h> +#include <qcamera.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + +class Q_MULTIMEDIA_EXPORT QCameraFlashControl : public QMediaControl +{ + Q_OBJECT + +public: + ~QCameraFlashControl(); + + virtual QCameraExposure::FlashModes flashMode() const = 0; + virtual void setFlashMode(QCameraExposure::FlashModes mode) = 0; + virtual bool isFlashModeSupported(QCameraExposure::FlashModes mode) const = 0; + + virtual bool isFlashReady() const = 0; + +Q_SIGNALS: + void flashReady(bool); + +protected: + QCameraFlashControl(QObject* parent = 0); +}; + +#define QCameraFlashControl_iid "com.nokia.Qt.QCameraFlashControl/1.0" +Q_MEDIA_DECLARE_CONTROL(QCameraFlashControl, QCameraFlashControl_iid) + +QT_END_NAMESPACE + +QT_END_HEADER + + +#endif // QCAMERAFLASHCONTROL_H + diff --git a/src/multimedia/qcamerafocus.cpp b/src/multimedia/qcamerafocus.cpp new file mode 100644 index 000000000..22a0bbcc9 --- /dev/null +++ b/src/multimedia/qcamerafocus.cpp @@ -0,0 +1,478 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QDebug> + +#include <qcamera.h> +#include <qcamerafocus.h> + +#include <qmediaobject_p.h> +#include <qcameracontrol.h> +#include <qcameraexposurecontrol.h> +#include <qcamerafocuscontrol.h> +#include <qmediarecordercontrol.h> +#include <qcameraimagecapturecontrol.h> +#include <qvideodevicecontrol.h> + +QT_BEGIN_NAMESPACE + +namespace +{ +class CameraFocusRegisterMetaTypes +{ +public: + CameraFocusRegisterMetaTypes() + { + qRegisterMetaType<QCameraFocus::FocusModes>("QCameraFocus::FocusModes"); + qRegisterMetaType<QCameraFocus::FocusPointMode>("QCameraFocus::FocusPointMode"); + } +} _registerCameraFocusMetaTypes; +} + + +class QCameraFocusZoneData : public QSharedData +{ +public: + QCameraFocusZoneData(): + status(QCameraFocusZone::Invalid) + { + + } + + QCameraFocusZoneData(const QRectF &_area, QCameraFocusZone::FocusZoneStatus _status): + area(_area), + status(_status) + { + + } + + + QCameraFocusZoneData(const QCameraFocusZoneData &other): + QSharedData(other), + area(other.area), + status(other.status) + { + } + + QCameraFocusZoneData& operator=(const QCameraFocusZoneData &other) + { + area = other.area; + status = other.status; + return *this; + } + + QRectF area; + QCameraFocusZone::FocusZoneStatus status; +}; + +QCameraFocusZone::QCameraFocusZone() + :d(new QCameraFocusZoneData) +{ + +} + +QCameraFocusZone::QCameraFocusZone(const QRectF &area, QCameraFocusZone::FocusZoneStatus status) + :d(new QCameraFocusZoneData(area, status)) +{ +} + +QCameraFocusZone::QCameraFocusZone(const QCameraFocusZone &other) + :d(other.d) +{ + +} + +QCameraFocusZone::~QCameraFocusZone() +{ + +} + +QCameraFocusZone& QCameraFocusZone::operator=(const QCameraFocusZone &other) +{ + d = other.d; + return *this; +} + +bool QCameraFocusZone::operator==(const QCameraFocusZone &other) const +{ + return d == other.d || + (d->area == other.d->area && d->status == other.d->status); +} + +bool QCameraFocusZone::operator!=(const QCameraFocusZone &other) const +{ + return !(*this == other); +} + +bool QCameraFocusZone::isValid() const +{ + return d->status != Invalid && !d->area.isValid(); +} + +QRectF QCameraFocusZone::area() const +{ + return d->area; +} + +QCameraFocusZone::FocusZoneStatus QCameraFocusZone::status() const +{ + return d->status; +} + +void QCameraFocusZone::setStatus(QCameraFocusZone::FocusZoneStatus status) +{ + d->status = status; +} + + +/*! + \class QCameraFocus + + + \brief The QCameraFocus class provides interface for + focus and zoom related camera settings. + + \inmodule QtMultimedia + \ingroup camera + \since 1.1 + +*/ + + +class QCameraFocusPrivate : public QMediaObjectPrivate +{ + Q_DECLARE_NON_CONST_PUBLIC(QCameraFocus) +public: + void initControls(); + + QCameraFocus *q_ptr; + + QCamera *camera; + QCameraFocusControl *focusControl; +}; + + +void QCameraFocusPrivate::initControls() +{ + Q_Q(QCameraFocus); + + focusControl = 0; + + QMediaService *service = camera->service(); + if (service) + focusControl = qobject_cast<QCameraFocusControl *>(service->requestControl(QCameraFocusControl_iid)); + + if (focusControl) { + q->connect(focusControl, SIGNAL(opticalZoomChanged(qreal)), q, SIGNAL(opticalZoomChanged(qreal))); + q->connect(focusControl, SIGNAL(digitalZoomChanged(qreal)), q, SIGNAL(digitalZoomChanged(qreal))); + q->connect(focusControl, SIGNAL(maximumOpticalZoomChanged(qreal)), + q, SIGNAL(maximumOpticalZoomChanged(qreal))); + q->connect(focusControl, SIGNAL(maximumDigitalZoomChanged(qreal)), + q, SIGNAL(maximumDigitalZoomChanged(qreal))); + q->connect(focusControl, SIGNAL(focusZonesChanged()), q, SIGNAL(focusZonesChanged())); + } +} + +/*! + Construct a QCameraFocus for \a camera. +*/ + +QCameraFocus::QCameraFocus(QCamera *camera): + QObject(camera), d_ptr(new QCameraFocusPrivate) +{ + Q_D(QCameraFocus); + d->camera = camera; + d->q_ptr = this; + d->initControls(); +} + + +/*! + Destroys the camera focus object. +*/ + +QCameraFocus::~QCameraFocus() +{ +} + +/*! + Returns true if focus related settings are supported by this camera. + \since 1.1 +*/ +bool QCameraFocus::isAvailable() const +{ + return d_func()->focusControl != 0; +} + +/*! + \property QCameraFocus::focusMode + \brief The current camera focus mode. + + \since 1.1 + \sa QCameraFocus::isFocusModeSupported() +*/ + +QCameraFocus::FocusMode QCameraFocus::focusMode() const +{ + return d_func()->focusControl ? d_func()->focusControl->focusMode() : QCameraFocus::AutoFocus; +} + +void QCameraFocus::setFocusMode(QCameraFocus::FocusMode mode) +{ + if (d_func()->focusControl) + d_func()->focusControl->setFocusMode(mode); +} + +/*! + Returns true if the focus \a mode is supported by camera. + \since 1.1 +*/ + +bool QCameraFocus::isFocusModeSupported(QCameraFocus::FocusMode mode) const +{ + return d_func()->focusControl ? d_func()->focusControl->isFocusModeSupported(mode) : false; +} + +/*! + \property QCameraFocus::focusPointMode + \brief The current camera focus point selection mode. + + \sa QCameraFocus::isFocusPointModeSupported() + \since 1.1 +*/ + +QCameraFocus::FocusPointMode QCameraFocus::focusPointMode() const +{ + return d_func()->focusControl ? + d_func()->focusControl->focusPointMode() : + QCameraFocus::FocusPointAuto; +} + +void QCameraFocus::setFocusPointMode(QCameraFocus::FocusPointMode mode) +{ + if (d_func()->focusControl) + d_func()->focusControl->setFocusPointMode(mode); + else + qWarning("Focus points mode selection is not supported"); +} + +/*! + Returns true if focus point \a mode is supported. + \since 1.1 + */ +bool QCameraFocus::isFocusPointModeSupported(QCameraFocus::FocusPointMode mode) const +{ + return d_func()->focusControl ? + d_func()->focusControl->isFocusPointModeSupported(mode) : + false; + +} + +/*! + \property QCameraFocus::customFocusPoint + + Position of custom focus point, in relative frame coordinates: + QPointF(0,0) points to the left top frame point, QPointF(0.5,0.5) points to the frame center. + + Custom focus point is used only in FocusPointCustom focus mode. + \since 1.1 + */ + +QPointF QCameraFocus::customFocusPoint() const +{ + return d_func()->focusControl ? + d_func()->focusControl->customFocusPoint() : + QPointF(0.5,0.5); +} + +void QCameraFocus::setCustomFocusPoint(const QPointF &point) +{ + if (d_func()->focusControl) + d_func()->focusControl->setCustomFocusPoint(point); + else + qWarning("Focus points selection is not supported"); + +} + +/*! + \property QCameraFocus::focusZones + + Returns the list of active focus zones. + + If QCamera::FocusPointAuto or QCamera::FocusPointFaceDetection focus mode is selected + this method returns the list of zones the camera is actually focused on. + + The coordinates system is the same as for custom focus points: + QPointF(0,0) points to the left top frame point, QPointF(0.5,0.5) points to the frame center. + \since 1.1 + */ +QCameraFocusZoneList QCameraFocus::focusZones() const +{ + return d_func()->focusControl ? + d_func()->focusControl->focusZones() : + QCameraFocusZoneList(); +} + +/*! + Returns the maximum optical zoom + \since 1.1 +*/ + +qreal QCameraFocus::maximumOpticalZoom() const +{ + return d_func()->focusControl ? d_func()->focusControl->maximumOpticalZoom() : 1.0; +} + +/*! + Returns the maximum digital zoom + \since 1.1 +*/ + +qreal QCameraFocus::maximumDigitalZoom() const +{ + return d_func()->focusControl ? d_func()->focusControl->maximumDigitalZoom() : 1.0; +} + +/*! + \property QCameraFocus::opticalZoom + \brief The current optical zoom value. + + \since 1.1 + \sa QCameraFocus::digitalZoom +*/ + +qreal QCameraFocus::opticalZoom() const +{ + return d_func()->focusControl ? d_func()->focusControl->opticalZoom() : 1.0; +} + +/*! + \property QCameraFocus::digitalZoom + \brief The current digital zoom value. + + \since 1.1 + \sa QCameraFocus::opticalZoom +*/ +qreal QCameraFocus::digitalZoom() const +{ + return d_func()->focusControl ? d_func()->focusControl->digitalZoom() : 1.0; +} + + +/*! + Set the camera \a optical and \a digital zoom values. + \since 1.1 +*/ +void QCameraFocus::zoomTo(qreal optical, qreal digital) +{ + if (d_func()->focusControl) + d_func()->focusControl->zoomTo(optical, digital); + else + qWarning("The camera doesn't support zooming."); +} + +/*! + \enum QCameraFocus::FocusMode + + \value ManualFocus Manual or fixed focus mode. + \value AutoFocus One-shot auto focus mode. + \value ContinuousFocus Continuous auto focus mode. + \value InfinityFocus Focus strictly to infinity. + \value HyperfocalFocus Focus to hyperfocal distance, with with the maximum depth of field achieved. + All objects at distances from half of this + distance out to infinity will be acceptably sharp. + \value MacroFocus One shot auto focus to objects close to camera. +*/ + +/*! + \enum QCameraFocus::FocusPointMode + + \value FocusPointAuto Automatically select one or multiple focus points. + \value FocusPointCenter Focus to the frame center. + \value FocusPointFaceDetection Focus on faces in the frame. + \value FocusPointCustom Focus to the custom point, defined by QCameraFocus::customFocusPoint property. +*/ + +/*! + \fn void QCameraFocus::opticalZoomChanged(qreal value) + + Signal emitted when optical zoom value changes to new \a value. + \since 1.1 +*/ + +/*! + \fn void QCameraFocus::digitalZoomChanged(qreal value) + + Signal emitted when digital zoom value changes to new \a value. + \since 1.1 +*/ + +/*! + \fn void QCameraFocus::maximumOpticalZoomChanged(qreal zoom) + + Signal emitted when the maximum supported optical \a zoom value changed. + \since 1.1 +*/ + +/*! + \fn void QCameraFocus::maximumDigitalZoomChanged(qreal zoom) + + Signal emitted when the maximum supported digital \a zoom value changed. + + The maximum supported zoom value can depend on other camera settings, + like capture mode or resolution. + \since 1.1 +*/ + + + +/*! + \fn QCameraFocus::focusZonesChanged() + + Signal is emitted when the set of zones, camera focused on is changed. + + Usually the zones list is changed when the camera is focused. + \since 1.1 +*/ + + +#include "moc_qcamerafocus.cpp" +QT_END_NAMESPACE diff --git a/src/multimedia/qcamerafocus.h b/src/multimedia/qcamerafocus.h new file mode 100644 index 000000000..064af7aa1 --- /dev/null +++ b/src/multimedia/qcamerafocus.h @@ -0,0 +1,183 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QCAMERAFOCUS_H +#define QCAMERAFOCUS_H + +#include <QtCore/qstringlist.h> +#include <QtCore/qpair.h> +#include <QtCore/qsize.h> +#include <QtCore/qpoint.h> +#include <QtCore/qrect.h> +#include <QtCore/qshareddata.h> + +#include <qmediaobject.h> +#include <qmediaenumdebug.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + +class QCamera; + +class QCameraFocusZoneData; + +class Q_MULTIMEDIA_EXPORT QCameraFocusZone { +public: + enum FocusZoneStatus { + Invalid, + Unused, + Selected, + Focused + }; + + QCameraFocusZone(); + QCameraFocusZone(const QRectF &area, FocusZoneStatus status = Selected); + QCameraFocusZone(const QCameraFocusZone &other); + + QCameraFocusZone& operator=(const QCameraFocusZone &other); + bool operator==(const QCameraFocusZone &other) const; + bool operator!=(const QCameraFocusZone &other) const; + + ~QCameraFocusZone(); + + bool isValid() const; + + QRectF area() const; + + FocusZoneStatus status() const; + void setStatus(FocusZoneStatus status); + +private: + QSharedDataPointer<QCameraFocusZoneData> d; +}; + +typedef QList<QCameraFocusZone> QCameraFocusZoneList; + + +class QCameraFocusPrivate; +class Q_MULTIMEDIA_EXPORT QCameraFocus : public QObject +{ + Q_OBJECT + + Q_PROPERTY(FocusMode focusMode READ focusMode WRITE setFocusMode) + Q_PROPERTY(FocusPointMode focusPointMode READ focusPointMode WRITE setFocusPointMode) + Q_PROPERTY(QPointF customFocusPoint READ customFocusPoint WRITE setCustomFocusPoint) + Q_PROPERTY(QCameraFocusZoneList focusZones READ focusZones NOTIFY focusZonesChanged) + Q_PROPERTY(qreal opticalZoom READ opticalZoom NOTIFY opticalZoomChanged) + Q_PROPERTY(qreal digitalZoom READ digitalZoom NOTIFY digitalZoomChanged) + + Q_ENUMS(FocusMode) + Q_ENUMS(FocusPointMode) +public: + enum FocusMode { + ManualFocus = 0x1, + HyperfocalFocus = 0x02, + InfinityFocus = 0x04, + AutoFocus = 0x8, + ContinuousFocus = 0x10, + MacroFocus = 0x20 + }; + Q_DECLARE_FLAGS(FocusModes, FocusMode) + + enum FocusPointMode { + FocusPointAuto, + FocusPointCenter, + FocusPointFaceDetection, + FocusPointCustom + }; + + bool isAvailable() const; + + FocusMode focusMode() const; + void setFocusMode(FocusMode mode); + bool isFocusModeSupported(FocusMode mode) const; + + FocusPointMode focusPointMode() const; + void setFocusPointMode(FocusPointMode mode); + bool isFocusPointModeSupported(FocusPointMode) const; + QPointF customFocusPoint() const; + void setCustomFocusPoint(const QPointF &point); + + QCameraFocusZoneList focusZones() const; + + qreal maximumOpticalZoom() const; + qreal maximumDigitalZoom() const; + qreal opticalZoom() const; + qreal digitalZoom() const; + + void zoomTo(qreal opticalZoom, qreal digitalZoom); + +Q_SIGNALS: + void opticalZoomChanged(qreal); + void digitalZoomChanged(qreal); + + void focusZonesChanged(); + + void maximumOpticalZoomChanged(qreal); + void maximumDigitalZoomChanged(qreal); + +private: + friend class QCamera; + QCameraFocus(QCamera *camera); + ~QCameraFocus(); + + Q_DISABLE_COPY(QCameraFocus) + Q_DECLARE_PRIVATE(QCameraFocus) + QCameraFocusPrivate *d_ptr; +}; + +Q_DECLARE_OPERATORS_FOR_FLAGS(QCameraFocus::FocusModes) + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(QCameraFocus::FocusModes) +Q_DECLARE_METATYPE(QCameraFocus::FocusPointMode) + +Q_MEDIA_ENUM_DEBUG(QCameraFocus, FocusMode) +Q_MEDIA_ENUM_DEBUG(QCameraFocus, FocusPointMode) + +QT_END_HEADER + +#endif // QCAMERAFOCUS_H diff --git a/src/multimedia/qcamerafocuscontrol.cpp b/src/multimedia/qcamerafocuscontrol.cpp new file mode 100644 index 000000000..93c466814 --- /dev/null +++ b/src/multimedia/qcamerafocuscontrol.cpp @@ -0,0 +1,253 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <qcamerafocuscontrol.h> +#include "qmediacontrol_p.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QCameraFocusControl + + + \brief The QCameraFocusControl class supplies control for + focusing related camera parameters. + + \inmodule QtMultimedia + \ingroup multimedia-serv + \since 1.1 + + The interface name of QCameraFocusControl is \c com.nokia.Qt.QCameraFocusControl/1.0 as + defined in QCameraFocusControl_iid. + + + \sa QMediaService::requestControl(), QCamera +*/ + +/*! + \macro QCameraFocusControl_iid + + \c com.nokia.Qt.QCameraFocusControl/1.0 + + Defines the interface name of the QCameraFocusControl class. + + \relates QCameraFocusControl +*/ + +/*! + Constructs a camera control object with \a parent. +*/ + +QCameraFocusControl::QCameraFocusControl(QObject *parent): + QMediaControl(*new QMediaControlPrivate, parent) +{ +} + +/*! + Destruct the camera control object. +*/ + +QCameraFocusControl::~QCameraFocusControl() +{ +} + + +/*! + \fn QCameraFocus::FocusMode QCameraFocusControl::focusMode() const + + Returns the focus mode being used. + \since 1.1 +*/ + + +/*! + \fn void QCameraFocusControl::setFocusMode(QCameraFocus::FocusMode mode) + + Set the focus mode to \a mode. + \since 1.1 +*/ + + +/*! + \fn bool QCameraFocusControl::isFocusModeSupported(QCameraFocus::FocusMode mode) const + + Returns true if focus \a mode is supported. + \since 1.1 +*/ + + +/*! + \fn qreal QCameraFocusControl::maximumOpticalZoom() const + + Returns the maximum optical zoom value, or 1.0 if optical zoom is not supported. + \since 1.1 +*/ + + +/*! + \fn qreal QCameraFocusControl::maximumDigitalZoom() const + + Returns the maximum digital zoom value, or 1.0 if digital zoom is not supported. + \since 1.1 +*/ + + +/*! + \fn qreal QCameraFocusControl::opticalZoom() const + + Return the current optical zoom value. + \since 1.1 +*/ + +/*! + \fn qreal QCameraFocusControl::digitalZoom() const + + Return the current digital zoom value. + \since 1.1 +*/ + + +/*! + \fn void QCameraFocusControl::zoomTo(qreal optical, qreal digital) + + Sets \a optical and \a digital zoom values. + \since 1.1 +*/ + +/*! + \fn QCameraFocusControl::focusPointMode() const + + Returns the camera focus point selection mode. + \since 1.1 +*/ + +/*! + \fn QCameraFocusControl::setFocusPointMode(QCameraFocus::FocusPointMode mode) + + Sets the camera focus point selection \a mode. + \since 1.1 +*/ + +/*! + \fn QCameraFocusControl::isFocusPointModeSupported(QCameraFocus::FocusPointMode mode) const + + Returns true if the camera focus point \a mode is supported. + \since 1.1 +*/ + +/*! + \fn QCameraFocusControl::customFocusPoint() const + + Return the position of custom focus point, in relative frame coordinates: + QPointF(0,0) points to the left top frame point, QPointF(0.5,0.5) points to the frame center. + + Custom focus point is used only in FocusPointCustom focus mode. + \since 1.1 +*/ + +/*! + \fn QCameraFocusControl::setCustomFocusPoint(const QPointF &point) + + Sets the custom focus \a point. + + If camera supports fixed set of focus points, + it should use the nearest supported focus point, + and return the actual focus point with QCameraFocusControl::focusZones(). + + \since 1.1 + \sa QCameraFocusControl::customFocusPoint(), QCameraFocusControl::focusZones() +*/ + +/*! + \fn QCameraFocusControl::focusZones() const + + Returns the list of zones, the camera is using for focusing or focused on. + \since 1.1 +*/ + +/*! + \fn void QCameraFocusControl::opticalZoomChanged(qreal zoom) + + Signal emitted when the optical \a zoom value changed. + \since 1.1 +*/ + +/*! + \fn void QCameraFocusControl::digitalZoomChanged(qreal zoom) + + Signal emitted when the digital \a zoom value changed. + \since 1.1 +*/ + +/*! + \fn void QCameraFocusControl::maximumOpticalZoomChanged(qreal zoom) + + Signal emitted when the maximum supported optical \a zoom value changed. + \since 1.1 +*/ + +/*! + \fn void QCameraFocusControl::maximumDigitalZoomChanged(qreal zoom) + + Signal emitted when the maximum supported digital \a zoom value changed. + + The maximum supported zoom value can depend on other camera settings, + like capture mode or resolution. + \since 1.1 +*/ + + +/*! + \fn QCameraFocusControl::focusZonesChanged() + + Signal is emitted when the set of zones, camera focused on is changed. + + Usually the zones list is changed when the camera is focused. + + \since 1.1 + \sa QCameraFocusControl::focusZones() +*/ + + + +#include "moc_qcamerafocuscontrol.cpp" +QT_END_NAMESPACE + diff --git a/src/multimedia/qcamerafocuscontrol.h b/src/multimedia/qcamerafocuscontrol.h new file mode 100644 index 000000000..20ffe6af1 --- /dev/null +++ b/src/multimedia/qcamerafocuscontrol.h @@ -0,0 +1,103 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QCAMERAFOCUSCONTROL_H +#define QCAMERAFOCUSCONTROL_H + +#include <qmediacontrol.h> +#include <qmediaobject.h> + +#include <qcamerafocus.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + +class Q_MULTIMEDIA_EXPORT QCameraFocusControl : public QMediaControl +{ + Q_OBJECT + +public: + ~QCameraFocusControl(); + + virtual QCameraFocus::FocusMode focusMode() const = 0; + virtual void setFocusMode(QCameraFocus::FocusMode mode) = 0; + virtual bool isFocusModeSupported(QCameraFocus::FocusMode mode) const = 0; + + virtual qreal maximumOpticalZoom() const = 0; + virtual qreal maximumDigitalZoom() const = 0; + virtual qreal opticalZoom() const = 0; + virtual qreal digitalZoom() const = 0; + + virtual void zoomTo(qreal optical, qreal digital) = 0; + + virtual QCameraFocus::FocusPointMode focusPointMode() const = 0; + virtual void setFocusPointMode(QCameraFocus::FocusPointMode mode) = 0; + virtual bool isFocusPointModeSupported(QCameraFocus::FocusPointMode mode) const = 0; + virtual QPointF customFocusPoint() const = 0; + virtual void setCustomFocusPoint(const QPointF &point) = 0; + + virtual QCameraFocusZoneList focusZones() const = 0; + +Q_SIGNALS: + void opticalZoomChanged(qreal opticalZoom); + void digitalZoomChanged(qreal digitalZoom); + void focusZonesChanged(); + void maximumOpticalZoomChanged(qreal); + void maximumDigitalZoomChanged(qreal); + +protected: + QCameraFocusControl(QObject* parent = 0); +}; + +#define QCameraFocusControl_iid "com.nokia.Qt.QCameraFocusingControl/1.0" +Q_MEDIA_DECLARE_CONTROL(QCameraFocusControl, QCameraFocusControl_iid) + +QT_END_NAMESPACE + +QT_END_HEADER + + +#endif // QCAMERAFOCUSCONTROL_H + diff --git a/src/multimedia/qcameraimagecapture.cpp b/src/multimedia/qcameraimagecapture.cpp new file mode 100644 index 000000000..6b399b684 --- /dev/null +++ b/src/multimedia/qcameraimagecapture.cpp @@ -0,0 +1,681 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include <qcameraimagecapture.h> +#include <qcameraimagecapturecontrol.h> +#include <qmediaencodersettings.h> +#include <qcameracapturedestinationcontrol.h> +#include <qcameracapturebufferformatcontrol.h> + +#include <qimageencodercontrol.h> +#include <qmediaobject_p.h> +#include <qmediaservice.h> +#include <qcamera.h> +#include <qcameracontrol.h> +#include <QtCore/qdebug.h> +#include <QtCore/qurl.h> +#include <QtCore/qstringlist.h> +#include <QtCore/qmetaobject.h> + +QT_BEGIN_NAMESPACE + +/*! + \class QCameraImageCapture + \inmodule QtMultimedia + \ingroup camera + \since 1.1 + + + \brief The QCameraImageCapture class is used for the recording of media content. + + The QCameraImageCapture class is a high level images recording class. + It's not intended to be used alone but for accessing the media + recording functions of other media objects, like QCamera. + + \snippet doc/src/snippets/multimedia-snippets/camera.cpp Camera + + \snippet doc/src/snippets/multimedia-snippets/camera.cpp Camera keys + + \sa QCamera +*/ + +namespace +{ +class MediaRecorderRegisterMetaTypes +{ +public: + MediaRecorderRegisterMetaTypes() + { + qRegisterMetaType<QCameraImageCapture::Error>("QCameraImageCapture::Error"); + qRegisterMetaType<QCameraImageCapture::CaptureDestination>("QCameraImageCapture::CaptureDestination"); + qRegisterMetaType<QCameraImageCapture::CaptureDestinations>("QCameraImageCapture::CaptureDestinations"); + } +} _registerRecorderMetaTypes; +} + + +class QCameraImageCapturePrivate +{ + Q_DECLARE_NON_CONST_PUBLIC(QCameraImageCapture) +public: + QCameraImageCapturePrivate(); + + QMediaObject *mediaObject; + + QCameraImageCaptureControl *control; + QImageEncoderControl *encoderControl; + QCameraCaptureDestinationControl *captureDestinationControl; + QCameraCaptureBufferFormatControl *bufferFormatControl; + + QCameraImageCapture::Error error; + QString errorString; + + void _q_error(int id, int error, const QString &errorString); + void _q_readyChanged(bool); + void _q_serviceDestroyed(); + + void unsetError() { error = QCameraImageCapture::NoError; errorString.clear(); } + + QCameraImageCapture *q_ptr; +}; + +QCameraImageCapturePrivate::QCameraImageCapturePrivate(): + mediaObject(0), + control(0), + encoderControl(0), + captureDestinationControl(0), + bufferFormatControl(0), + error(QCameraImageCapture::NoError) +{ +} + +void QCameraImageCapturePrivate::_q_error(int id, int error, const QString &errorString) +{ + Q_Q(QCameraImageCapture); + + this->error = QCameraImageCapture::Error(error); + this->errorString = errorString; + + emit q->error(id, this->error, errorString); +} + +void QCameraImageCapturePrivate::_q_readyChanged(bool ready) +{ + Q_Q(QCameraImageCapture); + emit q->readyForCaptureChanged(ready); +} + +void QCameraImageCapturePrivate::_q_serviceDestroyed() +{ + mediaObject = 0; + control = 0; + encoderControl = 0; + captureDestinationControl = 0; + bufferFormatControl = 0; +} + +/*! + Constructs a media recorder which records the media produced by \a mediaObject. + + The \a parent is passed to QMediaObject. +*/ + +QCameraImageCapture::QCameraImageCapture(QMediaObject *mediaObject, QObject *parent): + QObject(parent), d_ptr(new QCameraImageCapturePrivate) +{ + Q_D(QCameraImageCapture); + + d->q_ptr = this; + + if (mediaObject) + mediaObject->bind(this); +} + +/*! + Destroys images capture object. +*/ + +QCameraImageCapture::~QCameraImageCapture() +{ + Q_D(QCameraImageCapture); + + if (d->mediaObject) + d->mediaObject->unbind(this); +} + +/*! + \reimp + \since 1.1 +*/ +QMediaObject *QCameraImageCapture::mediaObject() const +{ + return d_func()->mediaObject; +} + +/*! + \reimp + \since 1.1 +*/ +bool QCameraImageCapture::setMediaObject(QMediaObject *mediaObject) +{ + Q_D(QCameraImageCapture); + + if (d->mediaObject) { + if (d->control) { + disconnect(d->control, SIGNAL(imageExposed(int)), + this, SIGNAL(imageExposed(int))); + disconnect(d->control, SIGNAL(imageCaptured(int,QImage)), + this, SIGNAL(imageCaptured(int,QImage))); + disconnect(d->control, SIGNAL(imageAvailable(int,QVideoFrame)), + this, SIGNAL(imageAvailable(int,QVideoFrame))); + disconnect(d->control, SIGNAL(imageMetadataAvailable(int,QtMultimedia::MetaData,QVariant)), + this, SIGNAL(imageMetadataAvailable(int,QtMultimedia::MetaData,QVariant))); + disconnect(d->control, SIGNAL(imageMetadataAvailable(int,QString,QVariant)), + this, SIGNAL(imageMetadataAvailable(int,QString,QVariant))); + disconnect(d->control, SIGNAL(imageSaved(int,QString)), + this, SIGNAL(imageSaved(int,QString))); + disconnect(d->control, SIGNAL(readyForCaptureChanged(bool)), + this, SLOT(_q_readyChanged(bool))); + disconnect(d->control, SIGNAL(error(int,int,QString)), + this, SLOT(_q_error(int,int,QString))); + + if (d->captureDestinationControl) { + disconnect(d->captureDestinationControl, SIGNAL(captureDestinationChanged(QCameraImageCapture::CaptureDestinations)), + this, SIGNAL(captureDestinationChanged(QCameraImageCapture::CaptureDestinations))); + } + + if (d->bufferFormatControl) { + disconnect(d->bufferFormatControl, SIGNAL(bufferFormatChanged(QVideoFrame::PixelFormat)), + this, SIGNAL(bufferFormatChanged(QVideoFrame::PixelFormat))); + } + + QMediaService *service = d->mediaObject->service(); + service->releaseControl(d->control); + if (d->encoderControl) + service->releaseControl(d->encoderControl); + if (d->captureDestinationControl) + service->releaseControl(d->captureDestinationControl); + if (d->bufferFormatControl) + service->releaseControl(d->bufferFormatControl); + + disconnect(service, SIGNAL(destroyed()), this, SLOT(_q_serviceDestroyed())); + } + } + + d->mediaObject = mediaObject; + + if (d->mediaObject) { + QMediaService *service = mediaObject->service(); + if (service) { + d->control = qobject_cast<QCameraImageCaptureControl*>(service->requestControl(QCameraImageCaptureControl_iid)); + + if (d->control) { + d->encoderControl = qobject_cast<QImageEncoderControl *>(service->requestControl(QImageEncoderControl_iid)); + d->captureDestinationControl = qobject_cast<QCameraCaptureDestinationControl *>( + service->requestControl(QCameraCaptureDestinationControl_iid)); + d->bufferFormatControl = qobject_cast<QCameraCaptureBufferFormatControl *>( + service->requestControl(QCameraCaptureBufferFormatControl_iid)); + + connect(d->control, SIGNAL(imageExposed(int)), + this, SIGNAL(imageExposed(int))); + connect(d->control, SIGNAL(imageCaptured(int,QImage)), + this, SIGNAL(imageCaptured(int,QImage))); + connect(d->control, SIGNAL(imageMetadataAvailable(int,QtMultimedia::MetaData,QVariant)), + this, SIGNAL(imageMetadataAvailable(int,QtMultimedia::MetaData,QVariant))); + connect(d->control, SIGNAL(imageMetadataAvailable(int,QString,QVariant)), + this, SIGNAL(imageMetadataAvailable(int,QString,QVariant))); + connect(d->control, SIGNAL(imageAvailable(int,QVideoFrame)), + this, SIGNAL(imageAvailable(int,QVideoFrame))); + connect(d->control, SIGNAL(imageSaved(int, QString)), + this, SIGNAL(imageSaved(int, QString))); + connect(d->control, SIGNAL(readyForCaptureChanged(bool)), + this, SLOT(_q_readyChanged(bool))); + connect(d->control, SIGNAL(error(int,int,QString)), + this, SLOT(_q_error(int,int,QString))); + + if (d->captureDestinationControl) { + connect(d->captureDestinationControl, SIGNAL(captureDestinationChanged(QCameraImageCapture::CaptureDestinations)), + this, SIGNAL(captureDestinationChanged(QCameraImageCapture::CaptureDestinations))); + } + + if (d->bufferFormatControl) { + connect(d->bufferFormatControl, SIGNAL(bufferFormatChanged(QVideoFrame::PixelFormat)), + this, SIGNAL(bufferFormatChanged(QVideoFrame::PixelFormat))); + } + + connect(service, SIGNAL(destroyed()), this, SLOT(_q_serviceDestroyed())); + + return true; + } + } + } + + // without QCameraImageCaptureControl discard the media object + d->mediaObject = 0; + d->control = 0; + d->encoderControl = 0; + d->captureDestinationControl = 0; + d->bufferFormatControl = 0; + + return false; +} + +/*! + Returns true if the images capture service ready to use. + \since 1.1 +*/ +bool QCameraImageCapture::isAvailable() const +{ + if (d_func()->control != NULL) + return true; + else + return false; +} + +/*! + Returns the availability error code. + \since 1.1 +*/ +QtMultimedia::AvailabilityError QCameraImageCapture::availabilityError() const +{ + if (d_func()->control != NULL) + return QtMultimedia::NoError; + else + return QtMultimedia::ServiceMissingError; +} + +/*! + Returns the current error state. + + \since 1.1 + \sa errorString() +*/ + +QCameraImageCapture::Error QCameraImageCapture::error() const +{ + return d_func()->error; +} + +/*! + Returns a string describing the current error state. + + \since 1.1 + \sa error() +*/ + +QString QCameraImageCapture::errorString() const +{ + return d_func()->errorString; +} + + +/*! + Returns a list of supported image codecs. + \since 1.1 +*/ +QStringList QCameraImageCapture::supportedImageCodecs() const +{ + return d_func()->encoderControl ? + d_func()->encoderControl->supportedImageCodecs() : QStringList(); +} + +/*! + Returns a description of an image \a codec. + \since 1.1 +*/ +QString QCameraImageCapture::imageCodecDescription(const QString &codec) const +{ + return d_func()->encoderControl ? + d_func()->encoderControl->imageCodecDescription(codec) : QString(); +} + +/*! + Returns a list of resolutions images can be encoded at. + + If non null image \a settings parameter is passed, + the returned list is reduced to resolution supported with partial settings like image codec or quality applied. + + If the encoder supports arbitrary resolutions within the supported range, + *\a continuous is set to true, otherwise *\a continuous is set to false. + + \since 1.1 + \sa QImageEncoderSettings::resolution() +*/ +QList<QSize> QCameraImageCapture::supportedResolutions(const QImageEncoderSettings &settings, bool *continuous) const +{ + if (continuous) + *continuous = false; + + return d_func()->encoderControl ? + d_func()->encoderControl->supportedResolutions(settings, continuous) : QList<QSize>(); +} + +/*! + Returns the image encoder settings being used. + + \since 1.1 + \sa setEncodingSettings() +*/ + +QImageEncoderSettings QCameraImageCapture::encodingSettings() const +{ + return d_func()->encoderControl ? + d_func()->encoderControl->imageSettings() : QImageEncoderSettings(); +} + +/*! + Sets the image encoding \a settings. + + If some parameters are not specified, or null settings are passed, + the encoder choose the default encoding parameters. + + \since 1.1 + \sa encodingSettings() +*/ + +void QCameraImageCapture::setEncodingSettings(const QImageEncoderSettings &settings) +{ + Q_D(QCameraImageCapture); + + if (d->encoderControl) { + QCamera *camera = qobject_cast<QCamera*>(d->mediaObject); + if (camera && camera->captureMode() == QCamera::CaptureStillImage) { + QMetaObject::invokeMethod(camera, + "_q_preparePropertyChange", + Qt::DirectConnection, + Q_ARG(int, QCameraControl::ImageEncodingSettings)); + } + + d->encoderControl->setImageSettings(settings); + } +} + +/*! + Returns the list of supported buffer image capture formats. + + \since 1.1 + \sa bufferFormat() setBufferFormat() +*/ +QList<QVideoFrame::PixelFormat> QCameraImageCapture::supportedBufferFormats() const +{ + if (d_func()->bufferFormatControl) + return d_func()->bufferFormatControl->supportedBufferFormats(); + else + return QList<QVideoFrame::PixelFormat>(); +} + +/*! + Returns the buffer image capture format being used. + + \since 1.2 + \sa supportedBufferCaptureFormats() setBufferCaptureFormat() +*/ +QVideoFrame::PixelFormat QCameraImageCapture::bufferFormat() const +{ + if (d_func()->bufferFormatControl) + return d_func()->bufferFormatControl->bufferFormat(); + else + return QVideoFrame::Format_Invalid; +} + +/*! + Sets the buffer image capture format to be used. + + \since 1.2 + \sa bufferCaptureFormat() supportedBufferCaptureFormats() captureDestination() +*/ +void QCameraImageCapture::setBufferFormat(const QVideoFrame::PixelFormat format) +{ + if (d_func()->bufferFormatControl) + d_func()->bufferFormatControl->setBufferFormat(format); +} + +/*! + Returns true if the image capture \a destination is supported; otherwise returns false. + + \since 1.2 + \sa captureDestination() setCaptureDestination() +*/ +bool QCameraImageCapture::isCaptureDestinationSupported(QCameraImageCapture::CaptureDestinations destination) const +{ + if (d_func()->captureDestinationControl) + return d_func()->captureDestinationControl->isCaptureDestinationSupported(destination); + else + return destination == CaptureToFile; +} + +/*! + Returns the image capture destination being used. + + \since 1.2 + \sa isCaptureDestinationSupported() setCaptureDestination() +*/ +QCameraImageCapture::CaptureDestinations QCameraImageCapture::captureDestination() const +{ + if (d_func()->captureDestinationControl) + return d_func()->captureDestinationControl->captureDestination(); + else + return CaptureToFile; +} + +/*! + Sets the capture \a destination to be used. + + \since 1.2 + \sa isCaptureDestinationSupported() captureDestination() +*/ +void QCameraImageCapture::setCaptureDestination(QCameraImageCapture::CaptureDestinations destination) +{ + Q_D(QCameraImageCapture); + + if (d->captureDestinationControl) + d->captureDestinationControl->setCaptureDestination(destination); +} + +/*! + \property QCameraImageCapture::readyForCapture + Indicates the service is ready to capture a an image immediately. + \since 1.1 +*/ + +bool QCameraImageCapture::isReadyForCapture() const +{ + if (d_func()->control) + return d_func()->control->isReadyForCapture(); + else + return false; +} + +/*! + \fn QCameraImageCapture::readyForCaptureChanged(bool ready) + + Signals that a camera's \a ready for capture state has changed. + \since 1.1 +*/ + + +/*! + Capture the image and save it to \a file. + This operation is asynchronous in majority of cases, + followed by signals QCameraImageCapture::imageCaptured(), QCameraImageCapture::imageSaved() + or QCameraImageCapture::error(). + + If an empty \a file is passed, the camera backend choses + the default location and naming scheme for photos on the system, + if only file name without full path is specified, the image will be saved to + the default directory, with a full path reported with imageCaptured() and imageSaved() signals. + + QCameraImageCapture::capture returns the capture Id parameter, used with + imageExposed(), imageCaptured() and imageSaved() signals. + \since 1.1 +*/ +int QCameraImageCapture::capture(const QString &file) +{ + Q_D(QCameraImageCapture); + + d->unsetError(); + + if (d->control) { + return d->control->capture(file); + } else { + d->error = NotSupportedFeatureError; + d->errorString = tr("Device does not support images capture."); + + emit error(-1, d->error, d->errorString); + } + + return -1; +} + +/*! + Cancel incomplete capture requests. + Already captured and queused for proicessing images may be discarded. + \since 1.1 +*/ +void QCameraImageCapture::cancelCapture() +{ + Q_D(QCameraImageCapture); + + d->unsetError(); + + if (d->control) { + d->control->cancelCapture(); + } else { + d->error = NotSupportedFeatureError; + d->errorString = tr("Device does not support images capture."); + + emit error(-1, d->error, d->errorString); + } +} + + +/*! + \enum QCameraImageCapture::Error + + \value NoError No Errors. + \value NotReadyError The service is not ready for capture yet. + \value ResourceError Device is not ready or not available. + \value NotSupportedFeatureError Device does not support stillimages capture. + \value FormatError Current format is not supported. + \value OutOfSpaceError No space left on device. +*/ + +/*! + \enum QCameraImageCapture::DriveMode + + \value SingleImageCapture Drive mode is capturing a single picture. +*/ + +/*! + \fn QCameraImageCapture::error(int id, QCameraImageCapture::Error error, const QString &errorString) + + Signals that the capture request \a id has failed with an \a error + and \a errorString description. + \since 1.1 +*/ + +/*! + \fn QCameraImageCapture::bufferFormatChanged(QVideoFrame::PixelFormat format) + + Signal emitted when the buffer \a format for the buffer image capture has changed. + \since 1.2 +*/ + +/*! + \fn QCameraImageCapture::captureDestinationChanged(CaptureDestinations destination) + + Signal emitted when the capture \a destination has changed. + \since 1.2 +*/ + +/*! + \fn QCameraImageCapture::imageExposed(int id) + + Signal emitted when the frame with request \a id was exposed. + \since 1.1 +*/ + +/*! + \fn QCameraImageCapture::imageCaptured(int id, const QImage &preview); + + Signal emitted when the frame with request \a id was captured, but not processed and saved yet. + Frame \a preview can be displayed to user. + \since 1.1 +*/ + +/*! + \fn QCameraImageCapture::imageMetadataAvailable(int id, QtMultimedia::MetaData key, const QVariant &value) + + Signals that a metadata for an image with request \a id is available. + This signal is emitted for metadata \a value with a \a key listed in QtMultimedia::MetaData enum. + + This signal is emitted between imageExposed and imageSaved signals. + \since 1.2 +*/ + +/*! + \fn QCameraImageCapture::imageMetadataAvailable(int id, const QString &key, const QVariant &value) + + Signals that a metadata for an image with request \a id is available. + This signal is emitted for extended metadata \a value with a \a key not listed in QtMultimedia::MetaData enum. + + This signal is emitted between imageExposed and imageSaved signals. + \since 1.2 +*/ + + +/*! + \fn QCameraImageCapture::imageAvailable(int id, const QVideoFrame &buffer) + + Signal emitted when the frame with request \a id is available as \a buffer. + \since 1.2 +*/ + +/*! + \fn QCameraImageCapture::imageSaved(int id, const QString &fileName) + + Signal emitted when the frame with request \a id was saved to \a fileName. + \since 1.1 +*/ + + +#include "moc_qcameraimagecapture.cpp" +QT_END_NAMESPACE + diff --git a/src/multimedia/qcameraimagecapture.h b/src/multimedia/qcameraimagecapture.h new file mode 100644 index 000000000..bc4162287 --- /dev/null +++ b/src/multimedia/qcameraimagecapture.h @@ -0,0 +1,170 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QCAMERAIMAGECAPTURE_H +#define QCAMERAIMAGECAPTURE_H + +#include <qmediaobject.h> +#include <qmediaencodersettings.h> +#include <qmediabindableinterface.h> +#include <qvideoframe.h> + +#include <qmediaenumdebug.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + +class QSize; +QT_END_NAMESPACE + +QT_BEGIN_NAMESPACE + +class QImageEncoderSettings; + +class QCameraImageCapturePrivate; +class Q_MULTIMEDIA_EXPORT QCameraImageCapture : public QObject, public QMediaBindableInterface +{ + Q_OBJECT + Q_INTERFACES(QMediaBindableInterface) + Q_ENUMS(Error) + Q_ENUMS(CaptureDestination) + Q_PROPERTY(bool readyForCapture READ isReadyForCapture NOTIFY readyForCaptureChanged) +public: + enum Error + { + NoError, + NotReadyError, + ResourceError, + OutOfSpaceError, + NotSupportedFeatureError, + FormatError + }; + + enum DriveMode + { + SingleImageCapture + }; + + enum CaptureDestination + { + CaptureToFile = 0x01, + CaptureToBuffer = 0x02 + }; + Q_DECLARE_FLAGS(CaptureDestinations, CaptureDestination) + + QCameraImageCapture(QMediaObject *mediaObject, QObject *parent = 0); + ~QCameraImageCapture(); + + bool isAvailable() const; + QtMultimedia::AvailabilityError availabilityError() const; + + QMediaObject *mediaObject() const; + + Error error() const; + QString errorString() const; + + bool isReadyForCapture() const; + + QStringList supportedImageCodecs() const; + QString imageCodecDescription(const QString &codecName) const; + + QList<QSize> supportedResolutions(const QImageEncoderSettings &settings = QImageEncoderSettings(), + bool *continuous = 0) const; + + QImageEncoderSettings encodingSettings() const; + void setEncodingSettings(const QImageEncoderSettings& settings); + + QList<QVideoFrame::PixelFormat> supportedBufferFormats() const; + QVideoFrame::PixelFormat bufferFormat() const; + void setBufferFormat(QVideoFrame::PixelFormat format); + + bool isCaptureDestinationSupported(CaptureDestinations destination) const; + CaptureDestinations captureDestination() const; + void setCaptureDestination(CaptureDestinations destination); + +public Q_SLOTS: + int capture(const QString &location = QString()); + void cancelCapture(); + +Q_SIGNALS: + void error(int id, QCameraImageCapture::Error error, const QString &errorString); + + void readyForCaptureChanged(bool); + void bufferFormatChanged(QVideoFrame::PixelFormat); + void captureDestinationChanged(QCameraImageCapture::CaptureDestinations); + + void imageExposed(int id); + void imageCaptured(int id, const QImage &preview); + void imageMetadataAvailable(int id, QtMultimedia::MetaData key, const QVariant &value); + void imageMetadataAvailable(int id, const QString &key, const QVariant &value); + void imageAvailable(int id, const QVideoFrame &image); + void imageSaved(int id, const QString &fileName); + +protected: + bool setMediaObject(QMediaObject *); + + QCameraImageCapturePrivate *d_ptr; +private: + Q_DISABLE_COPY(QCameraImageCapture) + Q_DECLARE_PRIVATE(QCameraImageCapture) + Q_PRIVATE_SLOT(d_func(), void _q_error(int, int, const QString &)) + Q_PRIVATE_SLOT(d_func(), void _q_readyChanged(bool)) + Q_PRIVATE_SLOT(d_func(), void _q_serviceDestroyed()) +}; + +Q_DECLARE_OPERATORS_FOR_FLAGS(QCameraImageCapture::CaptureDestinations) + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(QCameraImageCapture::Error) +Q_DECLARE_METATYPE(QCameraImageCapture::CaptureDestination) +Q_DECLARE_METATYPE(QCameraImageCapture::CaptureDestinations) + +Q_MEDIA_ENUM_DEBUG(QCameraImageCapture, Error) +Q_MEDIA_ENUM_DEBUG(QCameraImageCapture, CaptureDestination) + +QT_END_HEADER + +#endif + diff --git a/src/multimedia/qcameraimagecapturecontrol.cpp b/src/multimedia/qcameraimagecapturecontrol.cpp new file mode 100644 index 000000000..ad4c55edb --- /dev/null +++ b/src/multimedia/qcameraimagecapturecontrol.cpp @@ -0,0 +1,208 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <qcameraimagecapturecontrol.h> +#include <QtCore/qstringlist.h> + +QT_BEGIN_NAMESPACE + +/*! + \class QCameraImageCaptureControl + + \brief The QCameraImageCaptureControl class provides a control interface + for image capture services. + + \inmodule QtMultimedia + \ingroup multimedia-serv + \since 1.1 + + + + The interface name of QCameraImageCaptureControl is \c com.nokia.Qt.QCameraImageCaptureControl/1.0 as + defined in QCameraImageCaptureControl_iid. + + + \sa QMediaService::requestControl() +*/ + +/*! + \macro QCameraImageCaptureControl_iid + + \c com.nokia.Qt.QCameraImageCaptureControl/1.0 + + Defines the interface name of the QCameraImageCaptureControl class. + + \relates QCameraImageCaptureControl +*/ + +/*! + Constructs a new image capture control object with the given \a parent +*/ +QCameraImageCaptureControl::QCameraImageCaptureControl(QObject *parent) + :QMediaControl(parent) +{ +} + +/*! + Destroys an image capture control. +*/ +QCameraImageCaptureControl::~QCameraImageCaptureControl() +{ +} + +/*! + \fn QCameraImageCaptureControl::isReadyForCapture() const + + Identifies if a capture control is ready to perform a capture + immediately (all the resources necessary for image capture are allocated, + hardware initialized, flash is charged, etc). + + Returns true if the camera is ready for capture; and false if it is not. + \since 1.1 +*/ + +/*! + \fn QCameraImageCaptureControl::readyForCaptureChanged(bool ready) + + Signals that a capture control's \a ready state has changed. + \since 1.1 +*/ + +/*! + \fn QCameraImageCaptureControl::capture(const QString &fileName) + + Initiates the capture of an image to \a fileName. + The \a fileName can be relative or empty, + in this case the service should use the system specific place + and file naming scheme. + + Returns the capture request id number, which is used later + with imageExposed(), imageCaptured() and imageSaved() signals. + \since 1.1 +*/ + +/*! + \fn QCameraImageCaptureControl::cancelCapture() + + Cancel pending capture requests. + \since 1.1 +*/ + +/*! + \fn QCameraImageCaptureControl::imageExposed(int requestId) + + Signals that an image with it \a requestId + has just been exposed. + This signal can be used for the shutter sound or other indicaton. + \since 1.1 +*/ + +/*! + \fn QCameraImageCaptureControl::imageCaptured(int requestId, const QImage &preview) + + Signals that an image with it \a requestId + has been captured and a \a preview is available. + \since 1.1 +*/ + +/*! + \fn QCameraImageCaptureControl::imageMetadataAvailable(int id, QtMultimedia::MetaData key, const QVariant &value) + + Signals that a metadata for an image with request \a id is available. + This signal is emitted for metadata \a value with a \a key listed in QtMultimedia::MetaData enum. + + This signal should be emitted between imageExposed and imageSaved signals. + \since 1.2 +*/ + +/*! + \fn QCameraImageCaptureControl::imageMetadataAvailable(int id, const QString &key, const QVariant &value) + + Signals that a metadata for an image with request \a id is available. + This signal is emitted for extended metadata \a value with a \a key not listed in QtMultimedia::MetaData enum. + + This signal should be emitted between imageExposed and imageSaved signals. + \since 1.2 +*/ + +/*! + \fn QCameraImageCaptureControl::imageAvailable(int requestId, const QVideoFrame &buffer) + + Signals that a captured \a buffer with a \a requestId is available. + \since 1.2 +*/ + +/*! + \fn QCameraImageCaptureControl::imageSaved(int requestId, const QString &fileName) + + Signals that a captured image with a \a requestId has been saved + to \a fileName. + \since 1.1 +*/ + +/*! + \fn QCameraImageCaptureControl::driveMode() const + + Returns the current camera drive mode. + \since 1.1 +*/ + +/*! + \fn QCameraImageCaptureControl::setDriveMode(QCameraImageCapture::DriveMode mode) + + Sets the current camera drive \a mode. + \since 1.1 +*/ + + +/*! + \fn QCameraImageCaptureControl::error(int id, int error, const QString &errorString) + + Signals the capture request \a id failed with \a error code and message \a errorString. + + \since 1.1 + \sa QCameraImageCapture::Error +*/ + + +#include "moc_qcameraimagecapturecontrol.cpp" +QT_END_NAMESPACE + diff --git a/src/multimedia/qcameraimagecapturecontrol.h b/src/multimedia/qcameraimagecapturecontrol.h new file mode 100644 index 000000000..0459c1417 --- /dev/null +++ b/src/multimedia/qcameraimagecapturecontrol.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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QCAMERAIMAGECAPTURECONTROL_H +#define QCAMERAIMAGECAPTURECONTROL_H + +#include <qmediacontrol.h> +#include <qcameraimagecapture.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + +class QImage; +QT_END_NAMESPACE + +QT_BEGIN_NAMESPACE + +class Q_MULTIMEDIA_EXPORT QCameraImageCaptureControl : public QMediaControl +{ + Q_OBJECT + +public: + ~QCameraImageCaptureControl(); + + virtual bool isReadyForCapture() const = 0; + + virtual QCameraImageCapture::DriveMode driveMode() const = 0; + virtual void setDriveMode(QCameraImageCapture::DriveMode mode) = 0; + + virtual int capture(const QString &fileName) = 0; + virtual void cancelCapture() = 0; + +Q_SIGNALS: + void readyForCaptureChanged(bool); + + void imageExposed(int id); + void imageCaptured(int id, const QImage &preview); + void imageMetadataAvailable(int id, QtMultimedia::MetaData key, const QVariant &value); + void imageMetadataAvailable(int id, const QString &key, const QVariant &value); + void imageAvailable(int id, const QVideoFrame &buffer); + void imageSaved(int id, const QString &fileName); + + void error(int id, int error, const QString &errorString); + +protected: + QCameraImageCaptureControl(QObject* parent = 0); +}; + +#define QCameraImageCaptureControl_iid "com.nokia.Qt.QCameraImageCaptureControl/1.0" +Q_MEDIA_DECLARE_CONTROL(QCameraImageCaptureControl, QCameraImageCaptureControl_iid) + +QT_END_NAMESPACE + +QT_END_HEADER + + +#endif // QCAMERAIMAGECAPTURECONTROL_H + diff --git a/src/multimedia/qcameraimageprocessing.cpp b/src/multimedia/qcameraimageprocessing.cpp new file mode 100644 index 000000000..600dfd885 --- /dev/null +++ b/src/multimedia/qcameraimageprocessing.cpp @@ -0,0 +1,352 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QDebug> + +#include <qcameraimageprocessing.h> + +#include <qmediaobject_p.h> +#include <qcameracontrol.h> +#include <qcameraexposurecontrol.h> +#include <qcamerafocuscontrol.h> +#include <qmediarecordercontrol.h> +#include <qcameraimageprocessingcontrol.h> +#include <qcameraimagecapturecontrol.h> +#include <qvideodevicecontrol.h> + +QT_BEGIN_NAMESPACE + +/*! + \class QCameraImageProcessing + + + \brief The QCameraImageProcessing class provides interface for + focus and zoom related camera settings. + + \inmodule QtMultimedia + \ingroup camera + \since 1.1 + +*/ + + +class QCameraImageProcessingPrivate : public QMediaObjectPrivate +{ + Q_DECLARE_NON_CONST_PUBLIC(QCameraImageProcessing) +public: + void initControls(); + + QCameraImageProcessing *q_ptr; + + QCamera *camera; + QCameraImageProcessingControl *imageControl; +}; + + +void QCameraImageProcessingPrivate::initControls() +{ + imageControl = 0; + + QMediaService *service = camera->service(); + if (service) + imageControl = qobject_cast<QCameraImageProcessingControl *>(service->requestControl(QCameraImageProcessingControl_iid)); +} + +/*! + Construct a QCameraImageProcessing for \a camera. +*/ + +QCameraImageProcessing::QCameraImageProcessing(QCamera *camera): + QObject(camera), d_ptr(new QCameraImageProcessingPrivate) +{ + Q_D(QCameraImageProcessing); + d->camera = camera; + d->q_ptr = this; + d->initControls(); +} + + +/*! + Destroys the camera focus object. +*/ + +QCameraImageProcessing::~QCameraImageProcessing() +{ +} + + +/*! + Returns true if image processing related settings are supported by this camera. + \since 1.1 +*/ +bool QCameraImageProcessing::isAvailable() const +{ + return d_func()->imageControl != 0; +} + + +/*! + Returns the white balance mode being used. + \since 1.1 +*/ + +QCameraImageProcessing::WhiteBalanceMode QCameraImageProcessing::whiteBalanceMode() const +{ + return d_func()->imageControl ? d_func()->imageControl->whiteBalanceMode() : QCameraImageProcessing::WhiteBalanceAuto; +} + +/*! + Sets the white balance to \a mode. + \since 1.1 +*/ + +void QCameraImageProcessing::setWhiteBalanceMode(QCameraImageProcessing::WhiteBalanceMode mode) +{ + if (d_func()->imageControl) + d_func()->imageControl->setWhiteBalanceMode(mode); +} + +/*! + Returns true if the white balance \a mode is supported. + \since 1.1 +*/ + +bool QCameraImageProcessing::isWhiteBalanceModeSupported(QCameraImageProcessing::WhiteBalanceMode mode) const +{ + return d_func()->imageControl ? d_func()->imageControl->isWhiteBalanceModeSupported(mode) : false; +} + +/*! + Returns the current color temperature if the + manual white balance is active, otherwise the + return value is undefined. + \since 1.1 +*/ + +int QCameraImageProcessing::manualWhiteBalance() const +{ + QVariant value; + + if (d_func()->imageControl) + value = d_func()->imageControl->processingParameter(QCameraImageProcessingControl::ColorTemperature); + + return value.toInt(); +} + +/*! + Sets manual white balance to \a colorTemperature + \since 1.1 +*/ + +void QCameraImageProcessing::setManualWhiteBalance(int colorTemperature) +{ + if (d_func()->imageControl) { + d_func()->imageControl->setProcessingParameter( + QCameraImageProcessingControl::ColorTemperature, + QVariant(colorTemperature)); + } +} + +/*! + Return the contrast. + \since 1.1 +*/ +int QCameraImageProcessing::contrast() const +{ + QVariant value; + + if (d_func()->imageControl) + value = d_func()->imageControl->processingParameter(QCameraImageProcessingControl::Contrast); + + return value.toInt(); +} + +/*! + Set the contrast to \a value. + + Valid contrast values range between -100 and 100, the default is 0. + \since 1.1 +*/ +void QCameraImageProcessing::setContrast(int value) +{ + if (d_func()->imageControl) + d_func()->imageControl->setProcessingParameter(QCameraImageProcessingControl::Contrast, + QVariant(value)); +} + +/*! + Returns the saturation value. + \since 1.1 +*/ +int QCameraImageProcessing::saturation() const +{ + QVariant value; + + if (d_func()->imageControl) + value = d_func()->imageControl->processingParameter(QCameraImageProcessingControl::Saturation); + + return value.toInt(); +} + +/*! + Sets the saturation value to \a value. + + Valid saturation values range between -100 and 100, the default is 0. + \since 1.1 +*/ + +void QCameraImageProcessing::setSaturation(int value) +{ + if (d_func()->imageControl) + d_func()->imageControl->setProcessingParameter(QCameraImageProcessingControl::Saturation, + QVariant(value)); +} + +/*! + Identifies if sharpening is supported. + + Returns true if sharpening is supported; and false if it is not. + \since 1.1 +*/ +bool QCameraImageProcessing::isSharpeningSupported() const +{ + if (d_func()->imageControl) + return d_func()->imageControl->isProcessingParameterSupported(QCameraImageProcessingControl::Sharpening); + else + return false; +} + +/*! + Returns the sharpening level. + \since 1.1 +*/ +int QCameraImageProcessing::sharpeningLevel() const +{ + QVariant value; + + if (d_func()->imageControl) + value = d_func()->imageControl->processingParameter(QCameraImageProcessingControl::Sharpening); + + if (value.isNull()) + return -1; + else + return value.toInt(); +} + +/*! + Sets the sharpening \a level. + + Valid sharpening level values range between -1 for default sharpening level, + 0 for sharpening disabled and 100 for maximum sharpening applied. + \since 1.1 +*/ + +void QCameraImageProcessing::setSharpeningLevel(int level) +{ + Q_D(QCameraImageProcessing); + if (d->imageControl) + d->imageControl->setProcessingParameter(QCameraImageProcessingControl::Sharpening, + level == -1 ? QVariant() : QVariant(level)); +} + +/*! + Returns true if denoising is supported. + \since 1.1 +*/ +bool QCameraImageProcessing::isDenoisingSupported() const +{ + if (d_func()->imageControl) + return d_func()->imageControl->isProcessingParameterSupported(QCameraImageProcessingControl::Denoising); + else + return false; +} + +/*! + Returns the denoising level. + \since 1.1 +*/ +int QCameraImageProcessing::denoisingLevel() const +{ + QVariant value; + + if (d_func()->imageControl) + value = d_func()->imageControl->processingParameter(QCameraImageProcessingControl::Denoising); + + if (value.isNull()) + return -1; + else + return value.toInt(); +} + +/*! + Sets the denoising \a level. + + Valid denoising level values range between -1 for default denoising level, + 0 for denoising disabled and 100 for maximum denoising applied. + \since 1.1 +*/ +void QCameraImageProcessing::setDenoisingLevel(int level) +{ + Q_D(QCameraImageProcessing); + if (d->imageControl) + d->imageControl->setProcessingParameter(QCameraImageProcessingControl::Denoising, + level == -1 ? QVariant() : QVariant(level)); +} + + +/*! + \enum QCameraImageProcessing::WhiteBalanceMode + + \value WhiteBalanceManual Manual white balance. In this mode the white balance should be set with + setManualWhiteBalance() + \value WhiteBalanceAuto Auto white balance mode. + \value WhiteBalanceSunlight Sunlight white balance mode. + \value WhiteBalanceCloudy Cloudy white balance mode. + \value WhiteBalanceShade Shade white balance mode. + \value WhiteBalanceTungsten Tungsten white balance mode. + \value WhiteBalanceFluorescent Fluorescent white balance mode. + \value WhiteBalanceFlash Flash white balance mode. + \value WhiteBalanceSunset Sunset white balance mode. + \value WhiteBalanceVendor Vendor defined white balance mode. +*/ + +#include "moc_qcameraimageprocessing.cpp" +QT_END_NAMESPACE diff --git a/src/multimedia/qcameraimageprocessing.h b/src/multimedia/qcameraimageprocessing.h new file mode 100644 index 000000000..42a7eb589 --- /dev/null +++ b/src/multimedia/qcameraimageprocessing.h @@ -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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QCAMERAIMAGEPROCESSING_H +#define QCAMERAIMAGEPROCESSING_H + +#include <QtCore/qstringlist.h> +#include <QtCore/qpair.h> +#include <QtCore/qsize.h> +#include <QtCore/qpoint.h> +#include <QtCore/qrect.h> + +#include <qmediacontrol.h> +#include <qmediaobject.h> +#include <qmediaservice.h> +#include <qmediaenumdebug.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + +class QCamera; + +class QCameraImageProcessingPrivate; +class Q_MULTIMEDIA_EXPORT QCameraImageProcessing : public QObject +{ + Q_OBJECT + Q_ENUMS(WhiteBalanceMode) +public: + enum WhiteBalanceMode { + WhiteBalanceAuto = 0, + WhiteBalanceManual = 1, + WhiteBalanceSunlight = 2, + WhiteBalanceCloudy = 3, + WhiteBalanceShade = 4, + WhiteBalanceTungsten = 5, + WhiteBalanceFluorescent = 6, + WhiteBalanceFlash = 7, + WhiteBalanceSunset = 8, + WhiteBalanceVendor = 1000 + }; + + bool isAvailable() const; + + WhiteBalanceMode whiteBalanceMode() const; + void setWhiteBalanceMode(WhiteBalanceMode mode); + bool isWhiteBalanceModeSupported(WhiteBalanceMode mode) const; + int manualWhiteBalance() const; + void setManualWhiteBalance(int colorTemperature); + + int contrast() const; + void setContrast(int value); + + int saturation() const; + void setSaturation(int value); + + bool isSharpeningSupported() const; + int sharpeningLevel() const; + void setSharpeningLevel(int value); + + bool isDenoisingSupported() const; + int denoisingLevel() const; + void setDenoisingLevel(int value); + +private: + friend class QCamera; + QCameraImageProcessing(QCamera *camera); + ~QCameraImageProcessing(); + + Q_DISABLE_COPY(QCameraImageProcessing) + Q_DECLARE_PRIVATE(QCameraImageProcessing) + QCameraImageProcessingPrivate *d_ptr; +}; + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(QCameraImageProcessing::WhiteBalanceMode) + +Q_MEDIA_ENUM_DEBUG(QCameraImageProcessing, WhiteBalanceMode) + +QT_END_HEADER + +#endif // QCAMERAIMAGEPROCESSING_H diff --git a/src/multimedia/qcameraimageprocessingcontrol.cpp b/src/multimedia/qcameraimageprocessingcontrol.cpp new file mode 100644 index 000000000..5e318cc83 --- /dev/null +++ b/src/multimedia/qcameraimageprocessingcontrol.cpp @@ -0,0 +1,169 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <qcameraimageprocessingcontrol.h> +#include "qmediacontrol_p.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QCameraImageProcessingControl + \inmodule QtMultimedia + \ingroup multimedia-serv + \since 1.1 + + + \brief The QCameraImageProcessingControl class provides an abstract class + for controlling image processing parameters, like white balance, + contrast, saturation, sharpening and denoising. + + The interface name of QCameraImageProcessingControl is \c com.nokia.Qt.QCameraImageProcessingControl/1.0 as + defined in QCameraImageProcessingControl_iid. + + + + \sa QMediaService::requestControl(), QCamera +*/ + +/*! + \macro QCameraImageProcessingControl_iid + + \c com.nokia.Qt.QCameraImageProcessingControl/1.0 + + Defines the interface name of the QCameraImageProcessingControl class. + + \relates QCameraImageProcessingControl +*/ + +/*! + Constructs an image processing control object with \a parent. +*/ + +QCameraImageProcessingControl::QCameraImageProcessingControl(QObject *parent): + QMediaControl(*new QMediaControlPrivate, parent) +{ +} + +/*! + Destruct the image processing control object. +*/ + +QCameraImageProcessingControl::~QCameraImageProcessingControl() +{ +} + + +/*! + \fn QCameraImageProcessingControl::whiteBalanceMode() const + Return the white balance mode being used. + \since 1.1 +*/ + +/*! + \fn QCameraImageProcessingControl::setWhiteBalanceMode(QCameraImageProcessing::WhiteBalanceMode mode) + Set the white balance mode to \a mode + \since 1.1 +*/ + +/*! + \fn QCameraImageProcessingControl::isWhiteBalanceModeSupported(QCameraImageProcessing::WhiteBalanceMode mode) const + Returns true if the white balance \a mode is supported. + The backend should support at least QCameraImageProcessing::WhiteBalanceAuto mode. + \since 1.1 +*/ + +/*! + \fn bool QCameraImageProcessingControl::isProcessingParameterSupported(ProcessingParameter parameter) const + + Returns true if the camera supports adjusting image processing \a parameter. + + Usually the the supported settings is static, + but some parameter may not be available depending on other + camera settings, like presets. + In such case the currently supported parameters should be returned. + \since 1.1 +*/ + +/*! + \fn QCameraImageProcessingControl::processingParameter(ProcessingParameter parameter) const + Returns the image processing \a parameter value. + \since 1.1 +*/ + +/*! + \fn QCameraImageProcessingControl::setProcessingParameter(ProcessingParameter parameter, QVariant value) + + Sets the image processing \a parameter \a value. + Passing the null or invalid QVariant value allows + backend to choose the suitable parameter value. + + The valid values range depends on the parameter type, + for contrast, saturation and brightness value should be + between -100 and 100, the default is 0, + + For sharpening and denoising the range is 0..100, + 0 for sharpening or denoising disabled + and 100 for maximum sharpening/denoising applied. + \since 1.1 +*/ + +/*! + \enum QCameraImageProcessingControl::ProcessingParameter + + \value Contrast + Image contrast. + \value Saturation + Image saturation. + \value Brightness + Image brightness. + \value Sharpening + Amount of sharpening applied. + \value Denoising + Amount of denoising applied. + \value ColorTemperature + Color temperature in K. This value is used when the manual white balance mode is selected. + \value ExtendedParameter + The base value for platform specific extended parameters. + */ + +#include "moc_qcameraimageprocessingcontrol.cpp" +QT_END_NAMESPACE + diff --git a/src/multimedia/qcameraimageprocessingcontrol.h b/src/multimedia/qcameraimageprocessingcontrol.h new file mode 100644 index 000000000..8c739287c --- /dev/null +++ b/src/multimedia/qcameraimageprocessingcontrol.h @@ -0,0 +1,100 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QCAMERAIMAGEPROCESSINGCONTROL_H +#define QCAMERAIMAGEPROCESSINGCONTROL_H + +#include <qmediacontrol.h> +#include <qmediaobject.h> + +#include <qcamera.h> +#include <qmediaenumdebug.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + +class Q_MULTIMEDIA_EXPORT QCameraImageProcessingControl : public QMediaControl +{ + Q_OBJECT + Q_ENUMS(ProcessingParameter) + +public: + ~QCameraImageProcessingControl(); + + enum ProcessingParameter { + Contrast = 0, + Saturation = 1, + Brightness = 2, + Sharpening = 3, + Denoising = 4, + ColorTemperature = 5, + ExtendedParameter = 1000 + }; + + virtual QCameraImageProcessing::WhiteBalanceMode whiteBalanceMode() const = 0; + virtual void setWhiteBalanceMode(QCameraImageProcessing::WhiteBalanceMode mode) = 0; + virtual bool isWhiteBalanceModeSupported(QCameraImageProcessing::WhiteBalanceMode) const = 0; + + virtual bool isProcessingParameterSupported(ProcessingParameter) const = 0; + virtual QVariant processingParameter(ProcessingParameter parameter) const = 0; + virtual void setProcessingParameter(ProcessingParameter parameter, QVariant value) = 0; + +protected: + QCameraImageProcessingControl(QObject* parent = 0); +}; + +#define QCameraImageProcessingControl_iid "com.nokia.Qt.QCameraImageProcessingControl/1.0" +Q_MEDIA_DECLARE_CONTROL(QCameraImageProcessingControl, QCameraImageProcessingControl_iid) + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(QCameraImageProcessingControl::ProcessingParameter) + +Q_MEDIA_ENUM_DEBUG(QCameraImageProcessingControl, ProcessingParameter) + +QT_END_HEADER + +#endif + diff --git a/src/multimedia/qcameralockscontrol.cpp b/src/multimedia/qcameralockscontrol.cpp new file mode 100644 index 000000000..289a07bf5 --- /dev/null +++ b/src/multimedia/qcameralockscontrol.cpp @@ -0,0 +1,134 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <qcameralockscontrol.h> +#include "qmediacontrol_p.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QCameraLocksControl + + + + \brief The QCameraLocksControl class is an abstract base class for + classes that control still cameras or video cameras. + + \inmodule QtMultimedia + \ingroup multimedia-serv + \since 1.1 + + This service is provided by a QMediaService object via + QMediaService::control(). It is used by QCamera. + + The interface name of QCameraLocksControl is \c com.nokia.Qt.QCameraLocksControl/1.0 as + defined in QCameraLocksControl_iid. + + + \sa QMediaService::requestControl(), QCamera +*/ + +/*! + \macro QCameraLocksControl_iid + + \c com.nokia.Qt.QCameraLocksControl/1.0 + + Defines the interface name of the QCameraLocksControl class. + + \relates QCameraLocksControl +*/ + +/*! + Constructs a camera locks control object with \a parent. +*/ + +QCameraLocksControl::QCameraLocksControl(QObject *parent): + QMediaControl(*new QMediaControlPrivate, parent) +{ +} + +/*! + Destruct the camera locks control object. +*/ + +QCameraLocksControl::~QCameraLocksControl() +{ +} + +/*! + \fn QCameraLocksControl::supportedLocks() const + + Returns the lock types, the camera supports. + \since 1.1 +*/ + +/*! + \fn QCameraLocksControl::lockStatus(QCamera::LockType lock) const + + Returns the camera \a lock status. + \since 1.1 +*/ + +/*! + \fn QCameraLocksControl::searchAndLock(QCamera::LockTypes locks) + + Request camera \a locks. + \since 1.1 +*/ + +/*! + \fn QCameraLocksControl::unlock(QCamera::LockTypes locks) + + Unlock camera \a locks. + \since 1.1 +*/ + +/*! + \fn QCameraLocksControl::lockStatusChanged(QCamera::LockType lock, QCamera::LockStatus status, QCamera::LockChangeReason reason) + + Signals the \a lock \a status was changed with a specified \a reason. + \since 1.1 +*/ + + + +#include "moc_qcameralockscontrol.cpp" +QT_END_NAMESPACE diff --git a/src/multimedia/qcameralockscontrol.h b/src/multimedia/qcameralockscontrol.h new file mode 100644 index 000000000..93120ee1a --- /dev/null +++ b/src/multimedia/qcameralockscontrol.h @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QCAMERALOCKSCONTROL_H +#define QCAMERALOCKSCONTROL_H + +#include <qmediacontrol.h> +#include <qmediaobject.h> + +#include <qcamera.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + +class Q_MULTIMEDIA_EXPORT QCameraLocksControl : public QMediaControl +{ + Q_OBJECT +public: + ~QCameraLocksControl(); + + virtual QCamera::LockTypes supportedLocks() const = 0; + + virtual QCamera::LockStatus lockStatus(QCamera::LockType lock) const = 0; + + virtual void searchAndLock(QCamera::LockTypes locks) = 0; + virtual void unlock(QCamera::LockTypes locks) = 0; + +Q_SIGNALS: + void lockStatusChanged(QCamera::LockType type, QCamera::LockStatus status, QCamera::LockChangeReason reason); + +protected: + QCameraLocksControl(QObject* parent = 0); +}; + +#define QCameraLocksControl_iid "com.nokia.Qt.QCameraLocksControl/1.0" +Q_MEDIA_DECLARE_CONTROL(QCameraLocksControl, QCameraLocksControl_iid) + +QT_END_NAMESPACE + +QT_END_HEADER + + +#endif // QCAMERALOCKSCONTROL_H + diff --git a/src/multimedia/qimageencodercontrol.cpp b/src/multimedia/qimageencodercontrol.cpp new file mode 100644 index 000000000..ee62a502d --- /dev/null +++ b/src/multimedia/qimageencodercontrol.cpp @@ -0,0 +1,142 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qimageencodercontrol.h" +#include <QtCore/qstringlist.h> + +QT_BEGIN_NAMESPACE + +/*! + \class QImageEncoderControl + + \inmodule QtMultimedia + \ingroup multimedia-serv + \since 1.0 + + \brief The QImageEncoderControl class provides access to the settings of a media service that + performs image encoding. + + If a QMediaService supports encoding image data it will implement QImageEncoderControl. + This control allows to \l {setImageSettings()}{set image encoding settings} and + provides functions for quering supported image \l {supportedImageCodecs()}{codecs} and + \l {supportedResolutions()}{resolutions}. + + The interface name of QImageEncoderControl is \c com.nokia.Qt.QImageEncoderControl/1.0 as + defined in QImageEncoderControl_iid. + + \sa QImageEncoderSettings, QMediaService::requestControl() +*/ + +/*! + \macro QImageEncoderControl_iid + + \c com.nokia.Qt.QImageEncoderControl/1.0 + + Defines the interface name of the QImageEncoderControl class. + + \relates QImageEncoderControl +*/ + +/*! + Constructs a new image encoder control object with the given \a parent +*/ +QImageEncoderControl::QImageEncoderControl(QObject *parent) + :QMediaControl(parent) +{ +} + +/*! + Destroys the image encoder control. +*/ +QImageEncoderControl::~QImageEncoderControl() +{ +} + +/*! + \fn QImageEncoderControl::supportedResolutions(const QImageEncoderSettings &settings = QImageEncoderSettings(), + bool *continuous = 0) const + + Returns a list of supported resolutions. + + If non null image \a settings parameter is passed, + the returned list is reduced to resolutions supported with partial settings applied. + It can be used to query the list of resolutions, supported by specific image codec. + + If the encoder supports arbitrary resolutions within the supported resolutions range, + *\a continuous is set to true, otherwise *\a continuous is set to false. + \since 1.0 +*/ + +/*! + \fn QImageEncoderControl::supportedImageCodecs() const + + Returns a list of supported image codecs. + \since 1.0 +*/ + +/*! + \fn QImageEncoderControl::imageCodecDescription(const QString &codec) const + + Returns a description of an image \a codec. + \since 1.0 +*/ + +/*! + \fn QImageEncoderControl::imageSettings() const + + Returns the currently used image encoder settings. + + The returned value may be different tha passed to QImageEncoderControl::setImageSettings() + if the settings contains the default or undefined parameters. + In this case if the undefined parameters are already resolved, they should be returned. + \since 1.0 +*/ + +/*! + \fn QImageEncoderControl::setImageSettings(const QImageEncoderSettings &settings) + + Sets the selected image encoder \a settings. + \since 1.0 +*/ + +#include "moc_qimageencodercontrol.cpp" +QT_END_NAMESPACE + diff --git a/src/multimedia/qimageencodercontrol.h b/src/multimedia/qimageencodercontrol.h new file mode 100644 index 000000000..c8a8261a4 --- /dev/null +++ b/src/multimedia/qimageencodercontrol.h @@ -0,0 +1,91 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QIMAGEENCODERCONTROL_H +#define QIMAGEENCODERCONTROL_H + +#include "qmediacontrol.h" +#include "qmediarecorder.h" +#include "qmediaencodersettings.h" + +#include <QtCore/qsize.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + +class QByteArray; +class QStringList; +QT_END_NAMESPACE + +QT_BEGIN_NAMESPACE + +class Q_MULTIMEDIA_EXPORT QImageEncoderControl : public QMediaControl +{ + Q_OBJECT + +public: + virtual ~QImageEncoderControl(); + + virtual QStringList supportedImageCodecs() const = 0; + virtual QString imageCodecDescription(const QString &codecName) const = 0; + + virtual QList<QSize> supportedResolutions(const QImageEncoderSettings &settings, + bool *continuous = 0) const = 0; + + virtual QImageEncoderSettings imageSettings() const = 0; + virtual void setImageSettings(const QImageEncoderSettings &settings) = 0; + +protected: + QImageEncoderControl(QObject *parent = 0); +}; + +#define QImageEncoderControl_iid "com.nokia.Qt.QImageEncoderControl/1.0" +Q_MEDIA_DECLARE_CONTROL(QImageEncoderControl, QImageEncoderControl_iid) + +QT_END_NAMESPACE + +QT_END_HEADER + + +#endif diff --git a/src/multimedia/qlocalmediaplaylistprovider.cpp b/src/multimedia/qlocalmediaplaylistprovider.cpp new file mode 100644 index 000000000..84d54ecfd --- /dev/null +++ b/src/multimedia/qlocalmediaplaylistprovider.cpp @@ -0,0 +1,194 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qlocalmediaplaylistprovider.h" +#include "qmediaplaylistprovider_p.h" +#include "qmediacontent.h" + +QT_BEGIN_NAMESPACE + +class QLocalMediaPlaylistProviderPrivate: public QMediaPlaylistProviderPrivate +{ +public: + QList<QMediaContent> resources; +}; + +QLocalMediaPlaylistProvider::QLocalMediaPlaylistProvider(QObject *parent) + :QMediaPlaylistProvider(*new QLocalMediaPlaylistProviderPrivate, parent) +{ +} + +QLocalMediaPlaylistProvider::~QLocalMediaPlaylistProvider() +{ +} + +bool QLocalMediaPlaylistProvider::isReadOnly() const +{ + return false; +} + +int QLocalMediaPlaylistProvider::mediaCount() const +{ + return d_func()->resources.size(); +} + +QMediaContent QLocalMediaPlaylistProvider::media(int pos) const +{ + return d_func()->resources.value(pos); +} + +bool QLocalMediaPlaylistProvider::addMedia(const QMediaContent &content) +{ + Q_D(QLocalMediaPlaylistProvider); + + int pos = d->resources.count(); + + emit mediaAboutToBeInserted(pos, pos); + d->resources.append(content); + emit mediaInserted(pos, pos); + + return true; +} + +bool QLocalMediaPlaylistProvider::addMedia(const QList<QMediaContent> &items) +{ + Q_D(QLocalMediaPlaylistProvider); + + if (items.isEmpty()) + return true; + + int pos = d->resources.count(); + int end = pos+items.count()-1; + + emit mediaAboutToBeInserted(pos, end); + d->resources.append(items); + emit mediaInserted(pos, end); + + return true; +} + + +bool QLocalMediaPlaylistProvider::insertMedia(int pos, const QMediaContent &content) +{ + Q_D(QLocalMediaPlaylistProvider); + + emit mediaAboutToBeInserted(pos, pos); + d->resources.insert(pos, content); + emit mediaInserted(pos,pos); + + return true; +} + +bool QLocalMediaPlaylistProvider::insertMedia(int pos, const QList<QMediaContent> &items) +{ + Q_D(QLocalMediaPlaylistProvider); + + if (items.isEmpty()) + return true; + + const int last = pos+items.count()-1; + + emit mediaAboutToBeInserted(pos, last); + for (int i=0; i<items.count(); i++) + d->resources.insert(pos+i, items.at(i)); + emit mediaInserted(pos, last); + + return true; +} + +bool QLocalMediaPlaylistProvider::removeMedia(int fromPos, int toPos) +{ + Q_D(QLocalMediaPlaylistProvider); + + Q_ASSERT(fromPos >= 0); + Q_ASSERT(fromPos <= toPos); + Q_ASSERT(toPos < mediaCount()); + + emit mediaAboutToBeRemoved(fromPos, toPos); + d->resources.erase(d->resources.begin()+fromPos, d->resources.begin()+toPos+1); + emit mediaRemoved(fromPos, toPos); + + return true; +} + +bool QLocalMediaPlaylistProvider::removeMedia(int pos) +{ + Q_D(QLocalMediaPlaylistProvider); + + emit mediaAboutToBeRemoved(pos, pos); + d->resources.removeAt(pos); + emit mediaRemoved(pos, pos); + + return true; +} + +bool QLocalMediaPlaylistProvider::clear() +{ + Q_D(QLocalMediaPlaylistProvider); + if (!d->resources.isEmpty()) { + int lastPos = mediaCount()-1; + emit mediaAboutToBeRemoved(0, lastPos); + d->resources.clear(); + emit mediaRemoved(0, lastPos); + } + + return true; +} + +void QLocalMediaPlaylistProvider::shuffle() +{ + Q_D(QLocalMediaPlaylistProvider); + if (!d->resources.isEmpty()) { + QList<QMediaContent> resources; + + while (!d->resources.isEmpty()) { + resources.append(d->resources.takeAt(qrand() % d->resources.size())); + } + + d->resources = resources; + emit mediaChanged(0, mediaCount()-1); + } + +} + +#include "moc_qlocalmediaplaylistprovider.cpp" +QT_END_NAMESPACE + diff --git a/src/multimedia/qlocalmediaplaylistprovider.h b/src/multimedia/qlocalmediaplaylistprovider.h new file mode 100644 index 000000000..e712a3f73 --- /dev/null +++ b/src/multimedia/qlocalmediaplaylistprovider.h @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QLOCALMEDIAPAYLISTPROVIDER_H +#define QLOCALMEDIAPAYLISTPROVIDER_H + +#include "qmediaplaylistprovider.h" + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + +class QLocalMediaPlaylistProviderPrivate; +class Q_MULTIMEDIA_EXPORT QLocalMediaPlaylistProvider : public QMediaPlaylistProvider +{ + Q_OBJECT +public: + QLocalMediaPlaylistProvider(QObject *parent=0); + virtual ~QLocalMediaPlaylistProvider(); + + virtual int mediaCount() const; + virtual QMediaContent media(int pos) const; + + virtual bool isReadOnly() const; + + virtual bool addMedia(const QMediaContent &content); + virtual bool addMedia(const QList<QMediaContent> &items); + virtual bool insertMedia(int pos, const QMediaContent &content); + virtual bool insertMedia(int pos, const QList<QMediaContent> &items); + virtual bool removeMedia(int pos); + virtual bool removeMedia(int start, int end); + virtual bool clear(); + +public Q_SLOTS: + virtual void shuffle(); + +private: + Q_DECLARE_PRIVATE(QLocalMediaPlaylistProvider) +}; + +QT_END_NAMESPACE + +QT_END_HEADER + + +#endif // QLOCALMEDIAPAYLISTSOURCE_H diff --git a/src/multimedia/qmediabackgroundplaybackcontrol.cpp b/src/multimedia/qmediabackgroundplaybackcontrol.cpp new file mode 100644 index 000000000..d7cbd380a --- /dev/null +++ b/src/multimedia/qmediabackgroundplaybackcontrol.cpp @@ -0,0 +1,149 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmediabackgroundplaybackcontrol.h" +#include "qmediacontrol_p.h" + +QT_BEGIN_NAMESPACE + + +/*! + \class QMediaBackgroundPlaybackControl + \inmodule QtMultimedia + \ingroup multimedia + \since 5.0 + + + \brief The QMediaBackgroundPlaybackControl class provides access to the background playback + related control of a QMediaService. + + If a QMediaService can play media in background, it should implement QMediaBackgroundPlaybackControl. + This control provides a means to set the \l {setContextId()}{contextId} for application, + \l {acquire()}{acquire the resource for playback} and \l {release()} {release the playback resource}. + + The interface name of QMediaBackgroundPlaybackControl is \c com.nokia.Qt.QMediaBackgroundPlaybackControl/1.0 as + defined in QMediaBackgroundPlaybackControl_iid. + + \sa QMediaService::requestControl(), QMediaPlayer +*/ + +/*! + \macro QMediaBackgroundPlaybackControl_iid + + \c com.nokia.Qt.QMediaBackgroundPlaybackControl/1.0 + + Defines the interface name of the QMediaBackgroundPlaybackControl class. + + \relates QMediaBackgroundPlaybackControl +*/ + +/*! + Destroys a media background playback control. +*/ +QMediaBackgroundPlaybackControl::~QMediaBackgroundPlaybackControl() +{ +} + +/*! + Constructs a new media background playback control with the given \a parent. +*/ +QMediaBackgroundPlaybackControl::QMediaBackgroundPlaybackControl(QObject *parent): + QMediaControl(*new QMediaControlPrivate, parent) +{ +} + +/*! + \fn QMediaBackgroundPlaybackControl::setContextId(const QString& contextId) + + Sets the contextId for the application, the last contextId will be released if previously set. + \l {acquire()}{acquire method} will be automatically invoked after setting a new contextId. + + contextId is an unique string set by the application and is used by the background daemon to + distinguish and manage different context for different application. + + \since 1.0 +*/ + +/*! + \fn QMediaBackgroundPlaybackControl::acquire() + + Try to acquire the playback resource for current application + \since 1.0 +*/ + +/*! + \fn QMediaBackgroundPlaybackControl::release() + + Give up the playback resource if current applicaiton holds it. + \since 1.0 +*/ + +/*! + \property QMediaBackgroundPlaybackControl::isAcquired() + \brief indicate whether the background playback resource is granted or not + + It may take sometime for the backend to actually update this value before the first use. + + By default this property is false + + \since 1.0 +*/ + +/*! + \fn QMediaBackgroundPlaybackControl::acquired() + + Signals that the playback resource is acquired + + \since 1.0 +*/ + +/*! + \fn QMediaBackgroundPlaybackControl::lost() + + Signals that the playback resource is lost + + \since 1.0 +*/ + +#include "moc_qmediabackgroundplaybackcontrol.cpp" +QT_END_NAMESPACE + + diff --git a/src/multimedia/qmediabackgroundplaybackcontrol.h b/src/multimedia/qmediabackgroundplaybackcontrol.h new file mode 100644 index 000000000..2cf8d1935 --- /dev/null +++ b/src/multimedia/qmediabackgroundplaybackcontrol.h @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMEDIABACKGROUNDPLAYBACKCONTROL_H +#define QMEDIABACKGROUNDPLAYBACKCONTROL_H + +#include "qmediacontrol.h" + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + +class Q_MULTIMEDIA_EXPORT QMediaBackgroundPlaybackControl : public QMediaControl +{ + Q_OBJECT + +public: + virtual ~QMediaBackgroundPlaybackControl(); + + virtual void setContextId(const QString& contextId) = 0; + virtual void acquire() = 0; + virtual void release() = 0; + + virtual bool isAcquired() const = 0; + +Q_SIGNALS: + void acquired(); + void lost(); + +protected: + QMediaBackgroundPlaybackControl(QObject* parent = 0); +}; + +#define QMediaBackgroundPlaybackControl_iid "com.nokia.Qt.QMediaBackgroundPlaybackControl/1.0" +Q_MEDIA_DECLARE_CONTROL(QMediaBackgroundPlaybackControl, QMediaBackgroundPlaybackControl_iid) + +QT_END_NAMESPACE + +QT_END_HEADER + + +#endif // QMEDIABACKGROUNDPLAYBACKCONTROL_H diff --git a/src/multimedia/qmediabindableinterface.cpp b/src/multimedia/qmediabindableinterface.cpp new file mode 100644 index 000000000..f5be34dac --- /dev/null +++ b/src/multimedia/qmediabindableinterface.cpp @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <qmediabindableinterface.h> + +QT_BEGIN_NAMESPACE + +/*! + \class QMediaBindableInterface + \inmodule QtMultimedia + \ingroup multimedia + \since 1.0 + + + \brief The QMediaBindableInterface class is the base class for objects extending media objects functionality. + + \sa +*/ + +/*! + Destroys a media helper object. +*/ + +QMediaBindableInterface::~QMediaBindableInterface() +{ +} + +/*! + \fn QMediaBindableInterface::mediaObject() const; + + Return the currently attached media object. + \since 1.0 +*/ + + +/*! + \fn QMediaBindableInterface::setMediaObject(QMediaObject *object); + + Attaches to the media \a object. + Returns true if attached successfully, otherwise returns false. + \since 1.0 +*/ + + + +QT_END_NAMESPACE + diff --git a/src/multimedia/qmediabindableinterface.h b/src/multimedia/qmediabindableinterface.h new file mode 100644 index 000000000..02b5b1a21 --- /dev/null +++ b/src/multimedia/qmediabindableinterface.h @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMEDIABINDABLEINTERFACE_H +#define QMEDIABINDABLEINTERFACE_H + +#include <qmediaobject.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + +class QMediaObject; + +class Q_MULTIMEDIA_EXPORT QMediaBindableInterface +{ +public: + virtual ~QMediaBindableInterface(); + + virtual QMediaObject *mediaObject() const = 0; + +protected: + friend class QMediaObject; + virtual bool setMediaObject(QMediaObject *object) = 0; +}; + +#define QMediaBindableInterface_iid \ + "com.nokia.Qt.QMediaBindableInterface/1.0" +Q_DECLARE_INTERFACE(QMediaBindableInterface, QMediaBindableInterface_iid) + +QT_END_NAMESPACE + +QT_END_HEADER + + +#endif // QMEDIABINDABLEINTERFACE_H diff --git a/src/multimedia/qmediacontainercontrol.cpp b/src/multimedia/qmediacontainercontrol.cpp new file mode 100644 index 000000000..5a4e618f2 --- /dev/null +++ b/src/multimedia/qmediacontainercontrol.cpp @@ -0,0 +1,126 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include "qmediacontainercontrol.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QMediaContainerControl + + \brief The QMediaContainerControl class provides access to the output container format of a QMediaService + + \inmodule QtMultimedia + \ingroup multimedia-serv + \since 1.0 + + If a QMediaService supports writing encoded data it will implement + QMediaContainerControl. This control provides information about the output + containers supported by a media service and allows one to be selected as + the current output containers. + + The functionality provided by this control is exposed to application code + through the QMediaRecorder class. + + The interface name of QMediaContainerControl is \c com.nokia.Qt.QMediaContainerControl/1.0 as + defined in QMediaContainerControl_iid. + + \sa QMediaService::requestControl(), QMediaRecorder +*/ + +/*! + \macro QMediaContainerControl_iid + + \c com.nokia.Qt.QMediaContainerControl/1.0 + + Defines the interface name of the QMediaContainerControl class. + + \relates QMediaContainerControl +*/ + +/*! + Constructs a new media container control with the given \a parent. +*/ +QMediaContainerControl::QMediaContainerControl(QObject *parent) + :QMediaControl(parent) +{ +} + +/*! + Destroys a media container control. +*/ +QMediaContainerControl::~QMediaContainerControl() +{ +} + + +/*! + \fn QMediaContainerControl::supportedContainers() const + + Returns a list of MIME types of supported container formats. + \since 1.0 +*/ + +/*! + \fn QMediaContainerControl::containerMimeType() const + + Returns the MIME type of the selected container format. + \since 1.0 +*/ + +/*! + \fn QMediaContainerControl::setContainerMimeType(const QString &mimeType) + + Sets the current container format to the format identified by the given \a mimeType. + \since 1.0 +*/ + +/*! + \fn QMediaContainerControl::containerDescription(const QString &mimeType) const + + Returns a description of the container format identified by the given \a mimeType. + \since 1.0 +*/ + +#include "moc_qmediacontainercontrol.cpp" +QT_END_NAMESPACE + diff --git a/src/multimedia/qmediacontainercontrol.h b/src/multimedia/qmediacontainercontrol.h new file mode 100644 index 000000000..af48605d0 --- /dev/null +++ b/src/multimedia/qmediacontainercontrol.h @@ -0,0 +1,80 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#ifndef QMEDIACONTAINERCONTROL_H +#define QMEDIACONTAINERCONTROL_H + +#include "qmediacontrol.h" + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + +class Q_MULTIMEDIA_EXPORT QMediaContainerControl : public QMediaControl +{ + Q_OBJECT + +public: + virtual ~QMediaContainerControl(); + + virtual QStringList supportedContainers() const = 0; + virtual QString containerMimeType() const = 0; + virtual void setContainerMimeType(const QString &formatMimeType) = 0; + + virtual QString containerDescription(const QString &formatMimeType) const = 0; + +protected: + QMediaContainerControl(QObject *parent = 0); +}; + +#define QMediaContainerControl_iid "com.nokia.Qt.QMediaContainerControl/1.0" +Q_MEDIA_DECLARE_CONTROL(QMediaContainerControl, QMediaContainerControl_iid) + +QT_END_NAMESPACE + +QT_END_HEADER + + +#endif // QMEDIACONTAINERCONTROL_H diff --git a/src/multimedia/qmediacontent.cpp b/src/multimedia/qmediacontent.cpp new file mode 100644 index 000000000..8cd97bbe0 --- /dev/null +++ b/src/multimedia/qmediacontent.cpp @@ -0,0 +1,254 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtCore/qurl.h> +#include <QtCore/qvariant.h> + +#include "qmediacontent.h" + +QT_BEGIN_NAMESPACE + + +class QMediaContentPrivate : public QSharedData +{ +public: + QMediaContentPrivate() {} + QMediaContentPrivate(const QMediaResourceList &r): + resources(r) {} + + QMediaContentPrivate(const QMediaContentPrivate &other): + QSharedData(other), + resources(other.resources) + {} + + bool operator ==(const QMediaContentPrivate &other) const + { + return resources == other.resources; + } + + QMediaResourceList resources; +private: + QMediaContentPrivate& operator=(const QMediaContentPrivate &other); +}; + + +/*! + \class QMediaContent + + \brief The QMediaContent class provides access to the resources relating to a media content. + + \inmodule QtMultimedia + \ingroup multimedia + \since 1.0 + + QMediaContent is used within the multimedia framework as the logical handle + to media content. A QMediaContent object is composed of one or more + \l {QMediaResource}s where each resource provides the URL and format + information of a different encoding of the content. + + A non-null QMediaContent will always have a primary or canonical reference to + the content available through the canonicalUrl() or canonicalResource() + methods, any additional resources are optional. +*/ + + +/*! + Constructs a null QMediaContent. +*/ + +QMediaContent::QMediaContent() +{ +} + +/*! + Constructs a media content with \a url providing a reference to the content. + \since 1.0 +*/ + +QMediaContent::QMediaContent(const QUrl &url): + d(new QMediaContentPrivate) +{ + d->resources << QMediaResource(url); +} + +/*! + Constructs a media content with \a request providing a reference to the content. + + This constructor can be used to reference media content via network protocols such as HTTP. + This may include additional information required to obtain the resource, such as Cookies or HTTP headers. + \since 1.0 +*/ + +QMediaContent::QMediaContent(const QNetworkRequest &request): + d(new QMediaContentPrivate) +{ + d->resources << QMediaResource(request); +} + +/*! + Constructs a media content with \a resource providing a reference to the content. + \since 1.0 +*/ + +QMediaContent::QMediaContent(const QMediaResource &resource): + d(new QMediaContentPrivate) +{ + d->resources << resource; +} + +/*! + Constructs a media content with \a resources providing a reference to the content. + \since 1.0 +*/ + +QMediaContent::QMediaContent(const QMediaResourceList &resources): + d(new QMediaContentPrivate(resources)) +{ +} + +/*! + Constructs a copy of the media content \a other. + \since 1.0 +*/ + +QMediaContent::QMediaContent(const QMediaContent &other): + d(other.d) +{ +} + +/*! + Destroys the media content object. +*/ + +QMediaContent::~QMediaContent() +{ +} + +/*! + Assigns the value of \a other to this media content. + \since 1.0 +*/ + +QMediaContent& QMediaContent::operator=(const QMediaContent &other) +{ + d = other.d; + return *this; +} + +/*! + Returns true if \a other is equivalent to this media content; false otherwise. + \since 1.0 +*/ + +bool QMediaContent::operator==(const QMediaContent &other) const +{ + return (d.constData() == 0 && other.d.constData() == 0) || + (d.constData() != 0 && other.d.constData() != 0 && + *d.constData() == *other.d.constData()); +} + +/*! + Returns true if \a other is not equivalent to this media content; false otherwise. + \since 1.0 +*/ + +bool QMediaContent::operator!=(const QMediaContent &other) const +{ + return !(*this == other); +} + +/*! + Returns true if this media content is null (uninitialized); false otherwise. + \since 1.0 +*/ + +bool QMediaContent::isNull() const +{ + return d.constData() == 0; +} + +/*! + Returns a QUrl that represents that canonical resource for this media content. + \since 1.0 +*/ + +QUrl QMediaContent::canonicalUrl() const +{ + return canonicalResource().url(); +} + +/*! + Returns a QNetworkRequest that represents that canonical resource for this media content. + \since 1.0 +*/ + +QNetworkRequest QMediaContent::canonicalRequest() const +{ + return canonicalResource().request(); +} + +/*! + Returns a QMediaResource that represents that canonical resource for this media content. + \since 1.0 +*/ + +QMediaResource QMediaContent::canonicalResource() const +{ + return d.constData() != 0 + ? d->resources.value(0) + : QMediaResource(); +} + +/*! + Returns a list of alternative resources for this media content. The first item in this list + is always the canonical resource. + \since 1.0 +*/ + +QMediaResourceList QMediaContent::resources() const +{ + return d.constData() != 0 + ? d->resources + : QMediaResourceList(); +} + +QT_END_NAMESPACE + diff --git a/src/multimedia/qmediacontent.h b/src/multimedia/qmediacontent.h new file mode 100644 index 000000000..cfd109d84 --- /dev/null +++ b/src/multimedia/qmediacontent.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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMEDIACONTENT_H +#define QMEDIACONTENT_H + +#include <QtCore/qmetatype.h> +#include <QtCore/qshareddata.h> + +#include "qmediaresource.h" + +#include <qtmultimediadefs.h> + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + +class QMediaContentPrivate; +class Q_MULTIMEDIA_EXPORT QMediaContent +{ +public: + QMediaContent(); + QMediaContent(const QUrl &contentUrl); + QMediaContent(const QNetworkRequest &contentRequest); + QMediaContent(const QMediaResource &contentResource); + QMediaContent(const QMediaResourceList &resources); + QMediaContent(const QMediaContent &other); + ~QMediaContent(); + + QMediaContent& operator=(const QMediaContent &other); + + bool operator==(const QMediaContent &other) const; + bool operator!=(const QMediaContent &other) const; + + bool isNull() const; + + QUrl canonicalUrl() const; + QNetworkRequest canonicalRequest() const; + QMediaResource canonicalResource() const; + + QMediaResourceList resources() const; + +private: + QSharedDataPointer<QMediaContentPrivate> d; +}; + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(QMediaContent) + +QT_END_HEADER + +#endif // QMEDIACONTENT_H diff --git a/src/multimedia/qmediacontrol.cpp b/src/multimedia/qmediacontrol.cpp new file mode 100644 index 000000000..0cde2cddd --- /dev/null +++ b/src/multimedia/qmediacontrol.cpp @@ -0,0 +1,138 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtCore/qmetaobject.h> +#include <QtCore/qtimer.h> + +#include "qmediacontrol.h" +#include "qmediacontrol_p.h" + + + +QT_BEGIN_NAMESPACE + +/*! + \class QMediaControl + \inmodule QtMultimedia + \ingroup multimedia-serv + \since 1.0 + + + \brief The QMediaControl class provides a base interface for media service controls. + + Media controls provide an interface to individual features provided by a + media service. Most services implement a principal control which exposes + the core functionality of the service and a number of optional controls which + expose any additional functionality. + + A pointer to a control implemented by a media service can be obtained using + the \l {QMediaService::requestControl()} member of QMediaService. If the + service doesn't implement a control it will instead return a null pointer. + + \snippet doc/src/snippets/multimedia-snippets/media.cpp Request control + + Alternatively if the IId of the control has been declared using + Q_MEDIA_DECLARE_CONTROL the template version of + QMediaService::requestControl() can be used to request the service without + explicitly passing the IId or using qobject_cast(). + + \snippet doc/src/snippets/multimedia-snippets/media.cpp Request control templated + + Most application code will not interface directly with a media service's + controls, instead the QMediaObject which owns the service acts as an + intermediary between one or more controls and the application. + + \sa QMediaService, QMediaObject +*/ + +/*! + \macro Q_MEDIA_DECLARE_CONTROL(Class, IId) + \relates QMediaControl + + The Q_MEDIA_DECLARE_CONTROL macro declares an \a IId for a \a Class that + inherits from QMediaControl. + + Declaring an IId for a QMediaControl allows an instance of that control to + be requested from QMediaService::requestControl() without explicitly + passing the IId. + + \snippet doc/src/snippets/multimedia-snippets/media.cpp Request control templated + + \sa QMediaService::requestControl() +*/ + +/*! + Destroys a media control. +*/ + +QMediaControl::~QMediaControl() +{ + delete d_ptr; +} + +/*! + Constructs a media control with the given \a parent. + \since 1.0 +*/ + +QMediaControl::QMediaControl(QObject *parent) + : QObject(parent) + , d_ptr(new QMediaControlPrivate) +{ + d_ptr->q_ptr = this; +} + +/*! + \internal + \since 1.0 +*/ + +QMediaControl::QMediaControl(QMediaControlPrivate &dd, QObject *parent) + : QObject(parent) + , d_ptr(&dd) + +{ + d_ptr->q_ptr = this; +} + +#include "moc_qmediacontrol.cpp" +QT_END_NAMESPACE + diff --git a/src/multimedia/qmediacontrol.h b/src/multimedia/qmediacontrol.h new file mode 100644 index 000000000..3d27026c5 --- /dev/null +++ b/src/multimedia/qmediacontrol.h @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QABSTRACTMEDIACONTROL_H +#define QABSTRACTMEDIACONTROL_H + +#include <qtmultimediadefs.h> + +#include <QtCore/qobject.h> +#include <QtCore/qstring.h> +#include <QtCore/qvariant.h> + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + +class QMediaControlPrivate; +class Q_MULTIMEDIA_EXPORT QMediaControl : public QObject +{ + Q_OBJECT + +public: + ~QMediaControl(); + +protected: + QMediaControl(QObject *parent = 0); + QMediaControl(QMediaControlPrivate &dd, QObject *parent = 0); + + QMediaControlPrivate *d_ptr; + +private: + Q_DECLARE_PRIVATE(QMediaControl) +}; + +template <typename T> const char *qmediacontrol_iid() { return 0; } + +#define Q_MEDIA_DECLARE_CONTROL(Class, IId) \ + template <> inline const char *qmediacontrol_iid<Class *>() { return IId; } + +QT_END_NAMESPACE + +QT_END_HEADER + + +#endif // QABSTRACTMEDIACONTROL_H diff --git a/src/multimedia/qmediacontrol_p.h b/src/multimedia/qmediacontrol_p.h new file mode 100644 index 000000000..05693a028 --- /dev/null +++ b/src/multimedia/qmediacontrol_p.h @@ -0,0 +1,80 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QABSTRACTMEDIACONTROL_P_H +#define QABSTRACTMEDIACONTROL_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <qtmultimediadefs.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + +class QMediaControl; + +class QMediaControlPrivate +{ +public: + virtual ~QMediaControlPrivate() {} + + QMediaControl *q_ptr; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + + +#endif diff --git a/src/multimedia/qmediaencodersettings.cpp b/src/multimedia/qmediaencodersettings.cpp new file mode 100644 index 000000000..5f85eec37 --- /dev/null +++ b/src/multimedia/qmediaencodersettings.cpp @@ -0,0 +1,822 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmediaencodersettings.h" + +QT_BEGIN_NAMESPACE + +class QAudioEncoderSettingsPrivate : public QSharedData +{ +public: + QAudioEncoderSettingsPrivate() : + isNull(true), + encodingMode(QtMultimedia::ConstantQualityEncoding), + bitrate(-1), + sampleRate(-1), + channels(-1), + quality(QtMultimedia::NormalQuality) + { + } + + QAudioEncoderSettingsPrivate(const QAudioEncoderSettingsPrivate &other): + QSharedData(other), + isNull(other.isNull), + encodingMode(other.encodingMode), + codec(other.codec), + bitrate(other.bitrate), + sampleRate(other.sampleRate), + channels(other.channels), + quality(other.quality) + { + } + + bool isNull; + QtMultimedia::EncodingMode encodingMode; + QString codec; + int bitrate; + int sampleRate; + int channels; + QtMultimedia::EncodingQuality quality; + +private: + QAudioEncoderSettingsPrivate& operator=(const QAudioEncoderSettingsPrivate &other); +}; + +/*! + \class QAudioEncoderSettings + + \brief The QAudioEncoderSettings class provides a set of audio encoder settings. + + \inmodule QtMultimedia + \ingroup multimedia + \since 1.0 + + A audio encoder settings object is used to specify the audio encoder + settings used by QMediaRecorder. Audio encoder settings are selected by + constructing a QAudioEncoderSettings object, setting the desired properties + and then passing it to a QMediaRecorder instance using the + QMediaRecorder::setEncodingSettings() function. + + \snippet doc/src/snippets/multimedia-snippets/media.cpp Audio encoder settings + + \sa QMediaRecorder, QAudioEncoderControl +*/ + +/*! + Construct a null audio encoder settings object. +*/ +QAudioEncoderSettings::QAudioEncoderSettings() + :d(new QAudioEncoderSettingsPrivate) +{ +} + +/*! + Constructs a copy of the audio encoder settings object \a other. + \since 1.0 +*/ + +QAudioEncoderSettings::QAudioEncoderSettings(const QAudioEncoderSettings& other) + :d(other.d) +{ +} + +/*! + Destroys an audio encoder settings object. +*/ + +QAudioEncoderSettings::~QAudioEncoderSettings() +{ +} + +/*! + Assigns the value of \a other to an audio encoder settings object. + \since 1.0 +*/ + +QAudioEncoderSettings& QAudioEncoderSettings::operator=(const QAudioEncoderSettings &other) +{ + d = other.d; + return *this; +} + +/*! + Determines if \a other is of equal value to an audio encoder settings + object. + + Returns true if the settings objects are of equal value, and false if they + are not of equal value. + \since 1.0 +*/ + +bool QAudioEncoderSettings::operator==(const QAudioEncoderSettings &other) const +{ + return (d == other.d) || + (d->isNull == other.d->isNull && + d->encodingMode == other.d->encodingMode && + d->bitrate == other.d->bitrate && + d->sampleRate == other.d->sampleRate && + d->channels == other.d->channels && + d->quality == other.d->quality && + d->codec == other.d->codec); +} + +/*! + Determines if \a other is of equal value to an audio encoder settings + object. + + Returns true if the settings objects are not of equal value, and true if + they are of equal value. + \since 1.0 +*/ + +bool QAudioEncoderSettings::operator!=(const QAudioEncoderSettings &other) const +{ + return !(*this == other); +} + +/*! + Identifies if an audio settings object is initialized. + + Returns true if the settings object is null, and false if it is not. + \since 1.0 +*/ + +bool QAudioEncoderSettings::isNull() const +{ + return d->isNull; +} + +/*! + Returns the audio encoding mode. + + \since 1.0 + \sa QtMultimedia::EncodingMode +*/ +QtMultimedia::EncodingMode QAudioEncoderSettings::encodingMode() const +{ + return d->encodingMode; +} + +/*! + Sets the audio encoding \a mode setting. + + If QtMultimedia::ConstantQualityEncoding is set, the quality + encoding parameter is used and bit rate is ignored, + otherwise the bitrate is used. + + The audio codec, channels count and sample rate settings are used in all + the encoding modes. + + \since 1.0 + \sa encodingMode(), QtMultimedia::EncodingMode +*/ +void QAudioEncoderSettings::setEncodingMode(QtMultimedia::EncodingMode mode) +{ + d->encodingMode = mode; +} + +/*! + Returns the audio codec. + \since 1.0 +*/ +QString QAudioEncoderSettings::codec() const +{ + return d->codec; +} + +/*! + Sets the audio \a codec. + \since 1.0 +*/ +void QAudioEncoderSettings::setCodec(const QString& codec) +{ + d->isNull = false; + d->codec = codec; +} + +/*! + Returns the bit rate of the compressed audio stream in bits per second. + \since 1.0 +*/ +int QAudioEncoderSettings::bitRate() const +{ + return d->bitrate; +} + +/*! + Returns the number of audio channels. + \since 1.0 +*/ +int QAudioEncoderSettings::channelCount() const +{ + return d->channels; +} + +/*! + Sets the number of audio \a channels. + + A value of -1 indicates the encoder should make an optimal choice based on + what is available from the audio source and the limitations of the codec. + \since 1.0 +*/ +void QAudioEncoderSettings::setChannelCount(int channels) +{ + d->isNull = false; + d->channels = channels; +} + +/*! + Sets the audio bit \a rate in bits per second. + \since 1.0 +*/ +void QAudioEncoderSettings::setBitRate(int rate) +{ + d->isNull = false; + d->bitrate = rate; +} + +/*! + Returns the audio sample rate in Hz. + \since 1.0 +*/ +int QAudioEncoderSettings::sampleRate() const +{ + return d->sampleRate; +} + +/*! + Sets the audio sample \a rate in Hz. + + A value of -1 indicates the encoder should make an optimal choice based on what is avaialbe + from the audio source and the limitations of the codec. + \since 1.0 + */ +void QAudioEncoderSettings::setSampleRate(int rate) +{ + d->isNull = false; + d->sampleRate = rate; +} + +/*! + Returns the audio encoding quality. + \since 1.0 +*/ + +QtMultimedia::EncodingQuality QAudioEncoderSettings::quality() const +{ + return d->quality; +} + +/*! + Set the audio encoding \a quality. + + Setting the audio quality parameter allows backend to choose the balanced + set of encoding parameters to achieve the desired quality level. + + The \a quality settings parameter is only used in the + \l {QtMultimedia::ConstantQualityEncoding}{constant quality} \l{encodingMode()}{encoding mode}. + \since 1.0 +*/ +void QAudioEncoderSettings::setQuality(QtMultimedia::EncodingQuality quality) +{ + d->isNull = false; + d->quality = quality; +} + +class QVideoEncoderSettingsPrivate : public QSharedData +{ +public: + QVideoEncoderSettingsPrivate() : + isNull(true), + encodingMode(QtMultimedia::ConstantQualityEncoding), + bitrate(-1), + frameRate(0), + quality(QtMultimedia::NormalQuality) + { + } + + QVideoEncoderSettingsPrivate(const QVideoEncoderSettingsPrivate &other): + QSharedData(other), + isNull(other.isNull), + encodingMode(other.encodingMode), + codec(other.codec), + bitrate(other.bitrate), + resolution(other.resolution), + frameRate(other.frameRate), + quality(other.quality) + { + } + + bool isNull; + QtMultimedia::EncodingMode encodingMode; + QString codec; + int bitrate; + QSize resolution; + qreal frameRate; + QtMultimedia::EncodingQuality quality; + +private: + QVideoEncoderSettingsPrivate& operator=(const QVideoEncoderSettingsPrivate &other); +}; + +/*! + \class QVideoEncoderSettings + + \brief The QVideoEncoderSettings class provides a set of video encoder settings. + \since 1.0 + + A video encoder settings object is used to specify the video encoder + settings used by QMediaRecorder. Video encoder settings are selected by + constructing a QVideoEncoderSettings object, setting the desired properties + and then passing it to a QMediaRecorder instance using the + QMediaRecorder::setEncodingSettings() function. + + \snippet doc/src/snippets/multimedia-snippets/media.cpp Video encoder settings + + \sa QMediaRecorder, QVideoEncoderControl +*/ + +/*! + Constructs a null video encoder settings object. +*/ + +QVideoEncoderSettings::QVideoEncoderSettings() + :d(new QVideoEncoderSettingsPrivate) +{ +} + +/*! + Constructs a copy of the video encoder settings object \a other. + \since 1.0 +*/ + +QVideoEncoderSettings::QVideoEncoderSettings(const QVideoEncoderSettings& other) + :d(other.d) +{ +} + +/*! + Destroys a video encoder settings object. +*/ + +QVideoEncoderSettings::~QVideoEncoderSettings() +{ +} + +/*! + Assigns the value of \a other to a video encoder settings object. + \since 1.0 +*/ +QVideoEncoderSettings &QVideoEncoderSettings::operator=(const QVideoEncoderSettings &other) +{ + d = other.d; + return *this; +} + +/*! + Determines if \a other is of equal value to a video encoder settings object. + + Returns true if the settings objects are of equal value, and false if they + are not of equal value. + \since 1.0 +*/ +bool QVideoEncoderSettings::operator==(const QVideoEncoderSettings &other) const +{ + return (d == other.d) || + (d->isNull == other.d->isNull && + d->encodingMode == other.d->encodingMode && + d->bitrate == other.d->bitrate && + d->quality == other.d->quality && + d->codec == other.d->codec && + d->resolution == other.d->resolution && + qFuzzyCompare(d->frameRate, other.d->frameRate)); +} + +/*! + Determines if \a other is of equal value to a video encoder settings object. + + Returns true if the settings objects are not of equal value, and false if + they are of equal value. + \since 1.0 +*/ +bool QVideoEncoderSettings::operator!=(const QVideoEncoderSettings &other) const +{ + return !(*this == other); +} + +/*! + Identifies if a video encoder settings object is uninitalized. + + Returns true if the settings are null, and false if they are not. + \since 1.0 +*/ +bool QVideoEncoderSettings::isNull() const +{ + return d->isNull; +} + +/*! + Returns the video encoding mode. + + \since 1.0 + \sa QtMultimedia::EncodingMode +*/ +QtMultimedia::EncodingMode QVideoEncoderSettings::encodingMode() const +{ + return d->encodingMode; +} + +/*! + Sets the video encoding \a mode. + + If QtMultimedia::ConstantQualityEncoding is set, + the quality encoding parameter is used and bit rate is ignored, + otherwise the bitrate is used. + + The rest of encoding settings are respected regardless of encoding mode. + + \since 1.0 + \sa QtMultimedia::EncodingMode +*/ +void QVideoEncoderSettings::setEncodingMode(QtMultimedia::EncodingMode mode) +{ + d->isNull = false; + d->encodingMode = mode; +} + +/*! + Returns the video codec. + \since 1.0 +*/ + +QString QVideoEncoderSettings::codec() const +{ + return d->codec; +} + +/*! + Sets the video \a codec. + \since 1.0 +*/ +void QVideoEncoderSettings::setCodec(const QString& codec) +{ + d->isNull = false; + d->codec = codec; +} + +/*! + Returns bit rate of the encoded video stream in bits per second. + \since 1.0 +*/ +int QVideoEncoderSettings::bitRate() const +{ + return d->bitrate; +} + +/*! + Sets the bit rate of the encoded video stream to \a value. + \since 1.0 +*/ + +void QVideoEncoderSettings::setBitRate(int value) +{ + d->isNull = false; + d->bitrate = value; +} + +/*! + Returns the video frame rate. + \since 1.0 +*/ +qreal QVideoEncoderSettings::frameRate() const +{ + return d->frameRate; +} + +/*! + \fn QVideoEncoderSettings::setFrameRate(qreal rate) + + Sets the video frame \a rate. + + A value of 0 indicates the encoder should make an optimal choice based on what is available + from the video source and the limitations of the codec. + \since 1.0 +*/ + +void QVideoEncoderSettings::setFrameRate(qreal rate) +{ + d->isNull = false; + d->frameRate = rate; +} + +/*! + Returns the resolution of the encoded video. + \since 1.0 +*/ + +QSize QVideoEncoderSettings::resolution() const +{ + return d->resolution; +} + +/*! + Sets the \a resolution of the encoded video. + + An empty QSize indicates the encoder should make an optimal choice based on + what is available from the video source and the limitations of the codec. + \since 1.0 +*/ + +void QVideoEncoderSettings::setResolution(const QSize &resolution) +{ + d->isNull = false; + d->resolution = resolution; +} + +/*! + Sets the \a width and \a height of the resolution of the encoded video. + + \overload + \since 1.0 +*/ + +void QVideoEncoderSettings::setResolution(int width, int height) +{ + d->isNull = false; + d->resolution = QSize(width, height); +} + +/*! + Returns the video encoding quality. + \since 1.0 +*/ + +QtMultimedia::EncodingQuality QVideoEncoderSettings::quality() const +{ + return d->quality; +} + +/*! + Sets the video encoding \a quality. + + Setting the video quality parameter allows backend to choose the balanced + set of encoding parameters to achieve the desired quality level. + + The \a quality settings parameter is only used in the + \l {QtMultimedia::ConstantQualityEncoding}{constant quality} \l{encodingMode()}{encoding mode}. + The \a quality settings parameter is only used in the \l + {QtMultimedia::ConstantQualityEncoding}{constant quality} + \l{encodingMode()}{encoding mode}. + \since 1.0 +*/ + +void QVideoEncoderSettings::setQuality(QtMultimedia::EncodingQuality quality) +{ + d->isNull = false; + d->quality = quality; +} + + + +class QImageEncoderSettingsPrivate : public QSharedData +{ +public: + QImageEncoderSettingsPrivate() : + isNull(true), + quality(QtMultimedia::NormalQuality) + { + } + + QImageEncoderSettingsPrivate(const QImageEncoderSettingsPrivate &other): + QSharedData(other), + isNull(other.isNull), + codec(other.codec), + resolution(other.resolution), + quality(other.quality) + { + } + + bool isNull; + QString codec; + QSize resolution; + QtMultimedia::EncodingQuality quality; + +private: + QImageEncoderSettingsPrivate& operator=(const QImageEncoderSettingsPrivate &other); +}; + +/*! + \class QImageEncoderSettings + + + \brief The QImageEncoderSettings class provides a set of image encoder + settings. + \since 1.0 + + A image encoder settings object is used to specify the image encoder + settings used by QCameraImageCapture. Image encoder settings are selected + by constructing a QImageEncoderSettings object, setting the desired + properties and then passing it to a QCameraImageCapture instance using the + QCameraImageCapture::setImageSettings() function. + + \snippet doc/src/snippets/multimedia-snippets/media.cpp Image encoder settings + + \sa QImageEncoderControl +*/ + +/*! + Constructs a null image encoder settings object. +*/ + +QImageEncoderSettings::QImageEncoderSettings() + :d(new QImageEncoderSettingsPrivate) +{ +} + +/*! + Constructs a copy of the image encoder settings object \a other. + \since 1.0 +*/ + +QImageEncoderSettings::QImageEncoderSettings(const QImageEncoderSettings& other) + :d(other.d) +{ +} + +/*! + Destroys a image encoder settings object. +*/ + +QImageEncoderSettings::~QImageEncoderSettings() +{ +} + +/*! + Assigns the value of \a other to a image encoder settings object. + \since 1.0 +*/ +QImageEncoderSettings &QImageEncoderSettings::operator=(const QImageEncoderSettings &other) +{ + d = other.d; + return *this; +} + +/*! + Determines if \a other is of equal value to a image encoder settings + object. + + Returns true if the settings objects are of equal value, and false if they + are not of equal value. + \since 1.0 +*/ +bool QImageEncoderSettings::operator==(const QImageEncoderSettings &other) const +{ + return (d == other.d) || + (d->isNull == other.d->isNull && + d->quality == other.d->quality && + d->codec == other.d->codec && + d->resolution == other.d->resolution); + +} + +/*! + Determines if \a other is of equal value to a image encoder settings + object. + + Returns true if the settings objects are not of equal value, and false if + they are of equal value. + \since 1.0 +*/ +bool QImageEncoderSettings::operator!=(const QImageEncoderSettings &other) const +{ + return !(*this == other); +} + +/*! + Identifies if a image encoder settings object is uninitalized. + + Returns true if the settings are null, and false if they are not. + \since 1.0 +*/ +bool QImageEncoderSettings::isNull() const +{ + return d->isNull; +} + +/*! + Returns the image codec. + \since 1.0 +*/ + +QString QImageEncoderSettings::codec() const +{ + return d->codec; +} + +/*! + Sets the image \a codec. + \since 1.0 +*/ +void QImageEncoderSettings::setCodec(const QString& codec) +{ + d->isNull = false; + d->codec = codec; +} + +/*! + Returns the resolution of the encoded image. + \since 1.0 +*/ + +QSize QImageEncoderSettings::resolution() const +{ + return d->resolution; +} + +/*! + Sets the \a resolution of the encoded image. + + 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. + \since 1.0 +*/ + +void QImageEncoderSettings::setResolution(const QSize &resolution) +{ + d->isNull = false; + d->resolution = resolution; +} + +/*! + Sets the \a width and \a height of the resolution of the encoded image. + + \overload + \since 1.0 +*/ + +void QImageEncoderSettings::setResolution(int width, int height) +{ + d->isNull = false; + d->resolution = QSize(width, height); +} + +/*! + Returns the image encoding quality. + \since 1.0 +*/ + +QtMultimedia::EncodingQuality QImageEncoderSettings::quality() const +{ + return d->quality; +} + +/*! + Sets the image encoding \a quality. + \since 1.0 +*/ + +void QImageEncoderSettings::setQuality(QtMultimedia::EncodingQuality quality) +{ + d->isNull = false; + d->quality = quality; +} +QT_END_NAMESPACE + diff --git a/src/multimedia/qmediaencodersettings.h b/src/multimedia/qmediaencodersettings.h new file mode 100644 index 000000000..28bf6d6c8 --- /dev/null +++ b/src/multimedia/qmediaencodersettings.h @@ -0,0 +1,168 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMEDIAENCODERSETTINGS_H +#define QMEDIAENCODERSETTINGS_H + +#include <QtCore/qsharedpointer.h> +#include <QtCore/qstring.h> +#include <QtCore/qsize.h> +#include <qtmultimediadefs.h> +#include "qtmedianamespace.h" + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + + +class QAudioEncoderSettingsPrivate; +class Q_MULTIMEDIA_EXPORT QAudioEncoderSettings +{ +public: + QAudioEncoderSettings(); + QAudioEncoderSettings(const QAudioEncoderSettings& other); + + ~QAudioEncoderSettings(); + + QAudioEncoderSettings& operator=(const QAudioEncoderSettings &other); + bool operator==(const QAudioEncoderSettings &other) const; + bool operator!=(const QAudioEncoderSettings &other) const; + + bool isNull() const; + + QtMultimedia::EncodingMode encodingMode() const; + void setEncodingMode(QtMultimedia::EncodingMode); + + QString codec() const; + void setCodec(const QString& codec); + + int bitRate() const; + void setBitRate(int bitrate); + + int channelCount() const; + void setChannelCount(int channels); + + int sampleRate() const; + void setSampleRate(int rate); + + QtMultimedia::EncodingQuality quality() const; + void setQuality(QtMultimedia::EncodingQuality quality); + +private: + QSharedDataPointer<QAudioEncoderSettingsPrivate> d; +}; + +class QVideoEncoderSettingsPrivate; +class Q_MULTIMEDIA_EXPORT QVideoEncoderSettings +{ +public: + QVideoEncoderSettings(); + QVideoEncoderSettings(const QVideoEncoderSettings& other); + + ~QVideoEncoderSettings(); + + QVideoEncoderSettings& operator=(const QVideoEncoderSettings &other); + bool operator==(const QVideoEncoderSettings &other) const; + bool operator!=(const QVideoEncoderSettings &other) const; + + bool isNull() const; + + QtMultimedia::EncodingMode encodingMode() const; + void setEncodingMode(QtMultimedia::EncodingMode); + + QString codec() const; + void setCodec(const QString &); + + QSize resolution() const; + void setResolution(const QSize &); + void setResolution(int width, int height); + + qreal frameRate() const; + void setFrameRate(qreal rate); + + int bitRate() const; + void setBitRate(int bitrate); + + QtMultimedia::EncodingQuality quality() const; + void setQuality(QtMultimedia::EncodingQuality quality); + +private: + QSharedDataPointer<QVideoEncoderSettingsPrivate> d; +}; + +class QImageEncoderSettingsPrivate; +class Q_MULTIMEDIA_EXPORT QImageEncoderSettings +{ +public: + QImageEncoderSettings(); + QImageEncoderSettings(const QImageEncoderSettings& other); + + ~QImageEncoderSettings(); + + QImageEncoderSettings& operator=(const QImageEncoderSettings &other); + bool operator==(const QImageEncoderSettings &other) const; + bool operator!=(const QImageEncoderSettings &other) const; + + bool isNull() const; + + QString codec() const; + void setCodec(const QString &); + + QSize resolution() const; + void setResolution(const QSize &); + void setResolution(int width, int height); + + QtMultimedia::EncodingQuality quality() const; + void setQuality(QtMultimedia::EncodingQuality quality); + +private: + QSharedDataPointer<QImageEncoderSettingsPrivate> d; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + + +#endif diff --git a/src/multimedia/qmediaenumdebug.h b/src/multimedia/qmediaenumdebug.h new file mode 100644 index 000000000..3fa7ee820 --- /dev/null +++ b/src/multimedia/qmediaenumdebug.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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMEDIAENUMDEBUG_H +#define QMEDIAENUMDEBUG_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#include <QtCore/qmetaobject.h> +#include <QtCore/qdebug.h> + +QT_BEGIN_HEADER + +#ifndef QT_NO_DEBUG_STREAM + +#define Q_MEDIA_ENUM_DEBUG(Class,Enum) \ +inline QDebug operator<<(QDebug dbg, Class::Enum value) \ +{ \ + int index = Class::staticMetaObject.indexOfEnumerator(#Enum); \ + dbg.nospace() << #Class << "::" << Class::staticMetaObject.enumerator(index).valueToKey(value); \ + return dbg.space(); \ +} + +#else + +#define Q_MEDIA_ENUM_DEBUG(Class,Enum) + +#endif //QT_NO_DEBUG_STREAM + +QT_END_HEADER + +#endif + diff --git a/src/multimedia/qmediaimageviewer.cpp b/src/multimedia/qmediaimageviewer.cpp new file mode 100644 index 000000000..01265dc2f --- /dev/null +++ b/src/multimedia/qmediaimageviewer.cpp @@ -0,0 +1,604 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmediaimageviewer.h" + +#include "qmediaobject_p.h" +#include "qmediaimageviewerservice_p.h" + +#include <qmediaplaylist.h> +#include <qmediaplaylistsourcecontrol.h> +#include <qmediacontent.h> +#include <qmediaresource.h> +#include <qvideosurfaceoutput_p.h> + +#include <QtCore/qcoreevent.h> +#include <QtCore/qdatetime.h> +#include <QtCore/qpointer.h> +#include <QtCore/qtextstream.h> + +QT_BEGIN_NAMESPACE + +class QMediaImageViewerPrivate : public QMediaObjectPrivate +{ + Q_DECLARE_NON_CONST_PUBLIC(QMediaImageViewer) +public: + QMediaImageViewerPrivate(): + viewerControl(0), playlist(0), + state(QMediaImageViewer::StoppedState), timeout(3000), pauseTime(0) + { + } + + void _q_mediaStatusChanged(QMediaImageViewer::MediaStatus status); + void _q_playlistMediaChanged(const QMediaContent &content); + void _q_playlistDestroyed(); + + QMediaImageViewerControl *viewerControl; + QMediaPlaylist *playlist; + QPointer<QObject> videoOutput; + QVideoSurfaceOutput surfaceOutput; + QMediaImageViewer::State state; + int timeout; + int pauseTime; + QTime time; + QBasicTimer timer; + QMediaContent media; +}; + +void QMediaImageViewerPrivate::_q_mediaStatusChanged(QMediaImageViewer::MediaStatus status) +{ + switch (status) { + case QMediaImageViewer::NoMedia: + case QMediaImageViewer::LoadingMedia: + emit q_func()->mediaStatusChanged(status); + break; + case QMediaImageViewer::LoadedMedia: + if (state == QMediaImageViewer::PlayingState) { + time.start(); + timer.start(qMax(0, timeout), q_func()); + q_func()->addPropertyWatch("elapsedTime"); + } + emit q_func()->mediaStatusChanged(status); + emit q_func()->elapsedTimeChanged(0); + break; + case QMediaImageViewer::InvalidMedia: + emit q_func()->mediaStatusChanged(status); + + if (state == QMediaImageViewer::PlayingState) { + playlist->next(); + if (playlist->currentIndex() < 0) + emit q_func()->stateChanged(state = QMediaImageViewer::StoppedState); + } + break; + } +} + +void QMediaImageViewerPrivate::_q_playlistMediaChanged(const QMediaContent &content) +{ + media = content; + pauseTime = 0; + + viewerControl->showMedia(media); + + emit q_func()->mediaChanged(media); +} + +void QMediaImageViewerPrivate::_q_playlistDestroyed() +{ + playlist = 0; + timer.stop(); + + if (state != QMediaImageViewer::StoppedState) + emit q_func()->stateChanged(state = QMediaImageViewer::StoppedState); + + q_func()->setMedia(QMediaContent()); +} + +/*! + \class QMediaImageViewer + \brief The QMediaImageViewer class provides a means of viewing image media. + \inmodule QtMultimedia + \ingroup multimedia + \since 1.0 + + + QMediaImageViewer is used together with a media display object such as + QVideoWidget to present an image. A display object is attached to the + image viewer by means of the bind function. + + \snippet doc/src/snippets/multimedia-snippets/media.cpp Binding + + QMediaImageViewer can be paired with a QMediaPlaylist to create a slide + show of images. Constructing a QMediaPlaylist with a pointer to an + instance of QMediaImageViewer will attach it to the image viewer; + changing the playlist's selection will then change the media displayed + by the image viewer. With a playlist attached QMediaImageViewer's + play(), pause(), and stop() slots can be control the progression of the + playlist. The \l timeout property determines how long an image is + displayed for before progressing to the next in the playlist, and the + \l elapsedTime property holds how the duration the current image has + been displayed for. + + \snippet doc/src/snippets/multimedia-snippets/media.cpp Playlist +*/ + +/*! + \enum QMediaImageViewer::State + + Enumerates the possible control states an image viewer may be in. The + control state of an image viewer determines whether the image viewer is + automatically progressing through images in an attached playlist. + + \value StoppedState The image viewer is stopped, and will not automatically move to the next + image. The \l elapsedTime is fixed at 0. + \value PlayingState The slide show is playing, and will move to the next image when the + \l elapsedTime reaches the \l timeout. The \l elapsedTime is being incremented. + \value PausedState The image viewer is paused, and will not automatically move the to next + image. The \l elapsedTime is fixed at the time the image viewer was paused. +*/ + +/*! + \enum QMediaImageViewer::MediaStatus + + Enumerates the status of an image viewer's current media. + + \value NoMedia There is no current media. + \value LoadingMedia The image viewer is loading the current media. + \value LoadedMedia The image viewer has loaded the current media. + \value InvalidMedia The current media cannot be loaded. +*/ + +/*! + Constructs a new image viewer with the given \a parent. +*/ +QMediaImageViewer::QMediaImageViewer(QObject *parent) + : QMediaObject(*new QMediaImageViewerPrivate, parent, new QMediaImageViewerService) +{ + Q_D(QMediaImageViewer); + + d->viewerControl = qobject_cast<QMediaImageViewerControl*>( + d->service->requestControl(QMediaImageViewerControl_iid)); + + connect(d->viewerControl, SIGNAL(mediaStatusChanged(QMediaImageViewer::MediaStatus)), + this, SLOT(_q_mediaStatusChanged(QMediaImageViewer::MediaStatus))); +} + +/*! + Destroys an image viewer. +*/ +QMediaImageViewer::~QMediaImageViewer() +{ + Q_D(QMediaImageViewer); + + delete d->service; +} + +/*! + \property QMediaImageViewer::state + \brief the playlist control state of a slide show. + \since 1.0 +*/ + +QMediaImageViewer::State QMediaImageViewer::state() const +{ + return d_func()->state; +} + +/*! + \fn QMediaImageViewer::stateChanged(QMediaImageViewer::State state) + + Signals that the playlist control \a state of an image viewer has changed. + \since 1.0 +*/ + +/*! + \property QMediaImageViewer::mediaStatus + \brief the status of the current media. + \since 1.0 +*/ + +QMediaImageViewer::MediaStatus QMediaImageViewer::mediaStatus() const +{ + return d_func()->viewerControl->mediaStatus(); +} + +/*! + \fn QMediaImageViewer::mediaStatusChanged(QMediaImageViewer::MediaStatus status) + + Signals the the \a status of the current media has changed. + \since 1.0 +*/ + +/*! + \property QMediaImageViewer::media + \brief the media an image viewer is presenting. + \since 1.0 +*/ + +QMediaContent QMediaImageViewer::media() const +{ + Q_D(const QMediaImageViewer); + + return d->media; +} + +void QMediaImageViewer::setMedia(const QMediaContent &media) +{ + Q_D(QMediaImageViewer); + + if (d->playlist && d->playlist->currentMedia() != media) { + disconnect(d->playlist, SIGNAL(currentMediaChanged(QMediaContent)), + this, SLOT(_q_playlistMediaChanged(QMediaContent))); + disconnect(d->playlist, SIGNAL(destroyed()), this, SLOT(_q_playlistDestroyed())); + + d->playlist = 0; + } + + d->media = media; + + if (d->timer.isActive()) { + d->pauseTime = 0; + d->timer.stop(); + removePropertyWatch("elapsedTime"); + emit elapsedTimeChanged(0); + } + + if (d->state != QMediaImageViewer::StoppedState) + emit stateChanged(d->state = QMediaImageViewer::StoppedState); + + d->viewerControl->showMedia(d->media); + + emit mediaChanged(d->media); +} + +/*! + Use \a playlist as the source of images to be displayed in the viewer. + \since 1.0 +*/ +void QMediaImageViewer::setPlaylist(QMediaPlaylist *playlist) +{ + Q_D(QMediaImageViewer); + + if (d->playlist) { + disconnect(d->playlist, SIGNAL(currentMediaChanged(QMediaContent)), + this, SLOT(_q_playlistMediaChanged(QMediaContent))); + disconnect(d->playlist, SIGNAL(destroyed()), this, SLOT(_q_playlistDestroyed())); + + QMediaObject::unbind(d->playlist); + } + + d->playlist = playlist; + + if (d->playlist) { + connect(d->playlist, SIGNAL(currentMediaChanged(QMediaContent)), + this, SLOT(_q_playlistMediaChanged(QMediaContent))); + connect(d->playlist, SIGNAL(destroyed()), this, SLOT(_q_playlistDestroyed())); + + QMediaObject::bind(d->playlist); + + setMedia(d->playlist->currentMedia()); + } else { + setMedia(QMediaContent()); + } +} + +/*! + Returns the current playlist, or 0 if none. + \since 1.0 +*/ +QMediaPlaylist *QMediaImageViewer::playlist() const +{ + return d_func()->playlist; +} + +/*! + \fn QMediaImageViewer::mediaChanged(const QMediaContent &media) + + Signals that the \a media an image viewer is presenting has changed. + \since 1.0 +*/ + +/*! + \property QMediaImageViewer::timeout + \brief the amount of time in milliseconds an image is displayed for before moving to the next + image. + + The timeout only applies if the image viewer has a playlist attached and is in the PlayingState. + \since 1.0 +*/ + +int QMediaImageViewer::timeout() const +{ + return d_func()->timeout; +} + +void QMediaImageViewer::setTimeout(int timeout) +{ + Q_D(QMediaImageViewer); + + d->timeout = qMax(0, timeout); + + if (d->timer.isActive()) + d->timer.start(qMax(0, d->timeout - d->pauseTime - d->time.elapsed()), this); +} + +/*! + \property QMediaImageViewer::elapsedTime + \brief the amount of time in milliseconds that has elapsed since the current image was loaded. + + The elapsed time only increases while the image viewer is in the PlayingState. If stopped the + elapsed time will be reset to 0. + \since 1.0 +*/ + +int QMediaImageViewer::elapsedTime() const +{ + Q_D(const QMediaImageViewer); + + int elapsedTime = d->pauseTime; + + if (d->timer.isActive()) + elapsedTime += d->time.elapsed(); + + return elapsedTime; +} + +/*! + \fn QMediaImageViewer::elapsedTimeChanged(int time) + + Signals that the amount of \a time in milliseconds since the current + image was loaded has changed. + + This signal is emitted at a regular interval when the image viewer is + in the PlayingState and an image is loaded. The notification interval + is controlled by the QMediaObject::notifyInterval property. + + \since 1.0 + \sa timeout, QMediaObject::notifyInterval +*/ + +/*! + Sets a video \a widget as the current video output. + + This will unbind any previous video output bound with setVideoOutput(). + \since 1.1 +*/ + +void QMediaImageViewer::setVideoOutput(QVideoWidget *widget) +{ + Q_D(QMediaImageViewer); + + if (d->videoOutput) + unbind(d->videoOutput); + + // We don't know (in this library) that QVideoWidget inherits QObject + QObject *widgetObject = reinterpret_cast<QObject*>(widget); + + d->videoOutput = widgetObject && bind(widgetObject) ? widgetObject : 0; +} + +/*! + Sets a video \a item as the current video output. + + This will unbind any previous video output bound with setVideoOutput(). + \since 1.1 +*/ + +void QMediaImageViewer::setVideoOutput(QGraphicsVideoItem *item) +{ + Q_D(QMediaImageViewer); + + if (d->videoOutput) + unbind(d->videoOutput); + + // We don't know (in this library) that QGraphicsVideoItem (multiply) inherits QObject + // but QObject inheritance depends on QObject coming first, so try this out. + QObject *itemObject = reinterpret_cast<QObject*>(item); + + d->videoOutput = itemObject && bind(itemObject) ? itemObject : 0; +} + +/*! + Sets a video \a surface as the video output of a image viewer. + + If a video output has already been set on the image viewer the new surface + will replace it. + \since 1.2 +*/ + +void QMediaImageViewer::setVideoOutput(QAbstractVideoSurface *surface) +{ + Q_D(QMediaImageViewer); + + d->surfaceOutput.setVideoSurface(surface); + + if (d->videoOutput != &d->surfaceOutput) { + if (d->videoOutput) + unbind(d->videoOutput); + + d->videoOutput = bind(&d->surfaceOutput) ? &d->surfaceOutput : 0; + } +} + +/*! + \internal + \since 1.0 +*/ +bool QMediaImageViewer::bind(QObject *object) +{ + if (QMediaPlaylist *playlist = qobject_cast<QMediaPlaylist *>(object)) { + setPlaylist(playlist); + + return true; + } else { + return QMediaObject::bind(object); + } +} + +/*! + \internal + \since 1.0 + */ +void QMediaImageViewer::unbind(QObject *object) +{ + if (object == d_func()->playlist) + setPlaylist(0); + else + QMediaObject::unbind(object); +} + +/*! + Starts a slide show. + + If the playlist has no current media this will start at the beginning of the playlist, otherwise + it will resume from the current media. + + If no playlist is attached to an image viewer this will do nothing. + \since 1.0 +*/ +void QMediaImageViewer::play() +{ + Q_D(QMediaImageViewer); + + if (d->playlist && d->playlist->mediaCount() > 0 && d->state != PlayingState) { + d->state = PlayingState; + + switch (d->viewerControl->mediaStatus()) { + case NoMedia: + case InvalidMedia: + d->playlist->next(); + if (d->playlist->currentIndex() < 0) + d->state = StoppedState; + break; + case LoadingMedia: + break; + case LoadedMedia: + d->time.start(); + d->timer.start(qMax(0, d->timeout - d->pauseTime), this); + break; + } + + if (d->state == PlayingState) + emit stateChanged(d->state); + } +} + +/*! + Pauses a slide show. + + The current media and elapsed time are retained. If resumed, the current image will be + displayed for the remainder of the time out period before the next image is loaded. + \since 1.0 +*/ +void QMediaImageViewer::pause() +{ + Q_D(QMediaImageViewer); + + if (d->state == PlayingState) { + if (d->viewerControl->mediaStatus() == LoadedMedia) { + d->pauseTime += d->timeout - d->time.elapsed(); + d->timer.stop(); + removePropertyWatch("elapsedTime"); + } + + emit stateChanged(d->state = PausedState); + emit elapsedTimeChanged(d->pauseTime); + } +} + +/*! + Stops a slide show. + + The current media is retained, but the elapsed time is discarded. If resumed, the current + image will be displayed for the full time out period before the next image is loaded. + \since 1.0 +*/ +void QMediaImageViewer::stop() +{ + Q_D(QMediaImageViewer); + + switch (d->state) { + case PlayingState: + d->timer.stop(); + removePropertyWatch("elapsedTime"); + // fall through. + case PausedState: + d->pauseTime = 0; + d->state = QMediaImageViewer::StoppedState; + + emit stateChanged(d->state); + emit elapsedTimeChanged(0); + break; + case StoppedState: + break; + } +} + +/*! + \reimp + + \internal + \since 1.0 +*/ +void QMediaImageViewer::timerEvent(QTimerEvent *event) +{ + Q_D(QMediaImageViewer); + + if (event->timerId() == d->timer.timerId()) { + d->timer.stop(); + removePropertyWatch("elapsedTime"); + emit elapsedTimeChanged(d->pauseTime = d->timeout); + + d->playlist->next(); + + if (d->playlist->currentIndex() < 0) { + d->pauseTime = 0; + emit stateChanged(d->state = StoppedState); + emit elapsedTimeChanged(0); + } + } else { + QMediaObject::timerEvent(event); + } +} + +#include "moc_qmediaimageviewer.cpp" +QT_END_NAMESPACE + diff --git a/src/multimedia/qmediaimageviewer.h b/src/multimedia/qmediaimageviewer.h new file mode 100644 index 000000000..7010fad3f --- /dev/null +++ b/src/multimedia/qmediaimageviewer.h @@ -0,0 +1,142 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMEDIAIMAGEVIEWER_H +#define QMEDIAIMAGEVIEWER_H + +#include "qmediaobject.h" +#include "qmediacontent.h" +#include <qmediaenumdebug.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + +class QAbstractVideoSurface; +class QGraphicsVideoItem; +class QMediaPlaylist; +class QVideoWidget; + +class QMediaImageViewerPrivate; +class Q_MULTIMEDIA_EXPORT QMediaImageViewer : public QMediaObject +{ + Q_OBJECT + Q_PROPERTY(State state READ state NOTIFY stateChanged) + Q_PROPERTY(MediaStatus mediaStatus READ mediaStatus NOTIFY mediaStatusChanged) + Q_PROPERTY(QMediaContent media READ media WRITE setMedia NOTIFY mediaChanged) + Q_PROPERTY(int timeout READ timeout WRITE setTimeout) + Q_PROPERTY(int elapsedTime READ elapsedTime NOTIFY elapsedTimeChanged) + Q_ENUMS(State MediaStatus) + +public: + enum State + { + StoppedState, + PlayingState, + PausedState + }; + + enum MediaStatus + { + NoMedia, + LoadingMedia, + LoadedMedia, + InvalidMedia + }; + + explicit QMediaImageViewer(QObject *parent = 0); + ~QMediaImageViewer(); + + State state() const; + MediaStatus mediaStatus() const; + + QMediaContent media() const; + QMediaPlaylist *playlist() const; + + int timeout() const; + int elapsedTime() const; + + void setVideoOutput(QVideoWidget *widget); + void setVideoOutput(QGraphicsVideoItem *item); + void setVideoOutput(QAbstractVideoSurface *surface); + + bool bind(QObject *); + void unbind(QObject *); + +public Q_SLOTS: + void setMedia(const QMediaContent &media); + void setPlaylist(QMediaPlaylist *playlist); + + void play(); + void pause(); + void stop(); + + void setTimeout(int timeout); + +Q_SIGNALS: + void stateChanged(QMediaImageViewer::State state); + void mediaStatusChanged(QMediaImageViewer::MediaStatus status); + void mediaChanged(const QMediaContent &media); + void elapsedTimeChanged(int time); +protected: + void timerEvent(QTimerEvent *event); + +private: + Q_DECLARE_PRIVATE(QMediaImageViewer) + Q_PRIVATE_SLOT(d_func(), void _q_mediaStatusChanged(QMediaImageViewer::MediaStatus)) + Q_PRIVATE_SLOT(d_func(), void _q_playlistMediaChanged(const QMediaContent &)) + Q_PRIVATE_SLOT(d_func(), void _q_playlistDestroyed()) +}; + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(QMediaImageViewer::State) +Q_DECLARE_METATYPE(QMediaImageViewer::MediaStatus) + +Q_MEDIA_ENUM_DEBUG(QMediaImageViewer, State) +Q_MEDIA_ENUM_DEBUG(QMediaImageViewer, MediaStatus) + +QT_END_HEADER + +#endif diff --git a/src/multimedia/qmediaimageviewerservice.cpp b/src/multimedia/qmediaimageviewerservice.cpp new file mode 100644 index 000000000..65de7a81b --- /dev/null +++ b/src/multimedia/qmediaimageviewerservice.cpp @@ -0,0 +1,463 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmediaimageviewerservice_p.h" + +#include "qmediacontrol_p.h" +#include "qmediaservice_p.h" + +#include <qmediacontent.h> +#include <qmediaresource.h> +#include <qmediaobject_p.h> +#include <qvideorenderercontrol.h> + +#include <QtCore/qdebug.h> + +#include <QtCore/qurl.h> +#include <QtGui/qimagereader.h> + +#include <QtNetwork/qnetworkaccessmanager.h> +#include <QtNetwork/qnetworkreply.h> +#include <QtNetwork/qnetworkrequest.h> + +#include <qabstractvideosurface.h> +#include <qvideosurfaceformat.h> + +QT_BEGIN_NAMESPACE + +class QMediaImageViewerServicePrivate : public QMediaServicePrivate +{ +public: + QMediaImageViewerServicePrivate() + : viewerControl(0) + , rendererControl(0) + , network(0) + , internalNetwork(0) + { + } + + bool load(QIODevice *device); + void clear(); + + QMediaImageViewerControl *viewerControl; + QMediaImageViewerRenderer *rendererControl; + QNetworkAccessManager *network; + QNetworkAccessManager *internalNetwork; + QImage m_image; +}; + + +QMediaImageViewerRenderer::QMediaImageViewerRenderer(QObject *parent) + : QVideoRendererControl(parent) + , m_surface(0) +{ +} + +QMediaImageViewerRenderer::~QMediaImageViewerRenderer() +{ + if (m_surface) + m_surface->stop(); +} + +QAbstractVideoSurface *QMediaImageViewerRenderer::surface() const +{ + return m_surface; +} + +void QMediaImageViewerRenderer::setSurface(QAbstractVideoSurface *surface) +{ + if (m_surface) + m_surface->stop(); + + m_surface = surface; + + if (m_surface && !m_image.isNull()) + showImage(m_image); +} + +void QMediaImageViewerRenderer::showImage(const QImage &image) +{ + m_image = image; + + if (m_surface) { + if (m_image.isNull()) { + m_surface->stop(); + } else { + QVideoSurfaceFormat format( + image.size(), QVideoFrame::pixelFormatFromImageFormat(image.format())); + + if (!m_surface->isFormatSupported(format)) { + foreach (QVideoFrame::PixelFormat pixelFormat, m_surface->supportedPixelFormats()) { + const QImage::Format imageFormat + = QVideoFrame::imageFormatFromPixelFormat(pixelFormat); + + if (imageFormat != QImage::Format_Invalid) { + format = QVideoSurfaceFormat(image.size(), pixelFormat); + + if (m_surface->isFormatSupported(format) && m_surface->start(format)) { + m_image = image.convertToFormat(imageFormat); + + m_surface->present(QVideoFrame(m_image)); + + return; + } + } + } + } else if (m_surface->start(format)) { + m_surface->present(QVideoFrame(image)); + } + } + } +} + +bool QMediaImageViewerServicePrivate::load(QIODevice *device) +{ + QImageReader reader(device); + + if (!reader.canRead()) { + m_image = QImage(); + } else { + m_image = reader.read(); + } + + if (rendererControl) + rendererControl->showImage(m_image); + + return !m_image.isNull(); +} + +void QMediaImageViewerServicePrivate::clear() +{ + m_image = QImage(); + + if (rendererControl) + rendererControl->showImage(m_image); +} + +/*! + \class QMediaImageViewerService + \since 1.0 + \internal +*/ + +/*! +*/ +QMediaImageViewerService::QMediaImageViewerService(QObject *parent) + : QMediaService(*new QMediaImageViewerServicePrivate, parent) +{ + Q_D(QMediaImageViewerService); + + d->viewerControl = new QMediaImageViewerControl(this); +} + +/*! +*/ +QMediaImageViewerService::~QMediaImageViewerService() +{ + Q_D(QMediaImageViewerService); + + delete d->rendererControl; + delete d->viewerControl; +} + +/*! +*/ +QMediaControl *QMediaImageViewerService::requestControl(const char *name) +{ + Q_D(QMediaImageViewerService); + + if (qstrcmp(name, QMediaImageViewerControl_iid) == 0) { + return d->viewerControl; + } else if (qstrcmp(name, QVideoRendererControl_iid) == 0) { + if (!d->rendererControl) { + d->rendererControl = new QMediaImageViewerRenderer; + d->rendererControl->showImage(d->m_image); + + return d->rendererControl; + } + } + return 0; +} + +void QMediaImageViewerService::releaseControl(QMediaControl *control) +{ + Q_D(QMediaImageViewerService); + + if (!control) { + qWarning("QMediaService::releaseControl():" + " Attempted release of null control"); + } else if (control == d->rendererControl) { + delete d->rendererControl; + + d->rendererControl = 0; + } +} + +/*! +*/ +QNetworkAccessManager *QMediaImageViewerService::networkManager() const +{ + Q_D(const QMediaImageViewerService); + + if (!d->network) { + QMediaImageViewerServicePrivate *_d = const_cast<QMediaImageViewerServicePrivate *>(d); + + if (!_d->internalNetwork) + _d->internalNetwork = new QNetworkAccessManager( + const_cast<QMediaImageViewerService *>(this)); + + _d->network = d->internalNetwork; + } + + return d->network; +} + + +void QMediaImageViewerService::setNetworkManager(QNetworkAccessManager *manager) +{ + d_func()->network = manager; +} + +class QMediaImageViewerControlPrivate : public QMediaControlPrivate +{ + Q_DECLARE_NON_CONST_PUBLIC(QMediaImageViewerControl) +public: + QMediaImageViewerControlPrivate() + : service(0) + , getReply(0) + , headReply(0) + , status(QMediaImageViewer::NoMedia) + { + foreach (const QByteArray &format, QImageReader::supportedImageFormats()) { + supportedExtensions.append( + QLatin1Char('.') + QString::fromLatin1(format.data(), format.size())); + } + } + + bool isImageType(const QUrl &url, const QString &mimeType) const; + + void loadImage(); + void cancelRequests(); + + void _q_getFinished(); + void _q_headFinished(); + + QMediaImageViewerService *service; + QNetworkReply *getReply; + QNetworkReply *headReply; + QMediaImageViewer::MediaStatus status; + QMediaContent media; + QMediaResource currentMedia; + QList<QMediaResource> possibleResources; + QStringList supportedExtensions; +}; + +bool QMediaImageViewerControlPrivate::isImageType(const QUrl &url, const QString &mimeType) const +{ + if (!mimeType.isEmpty()) { + return mimeType.startsWith(QLatin1String("image/")) + || mimeType == QLatin1String("application/xml+svg"); + } else if (url.scheme() == QLatin1String("file")) { + QString path = url.path(); + + foreach (const QString &extension, supportedExtensions) { + if (path.endsWith(extension, Qt::CaseInsensitive)) + return true; + } + } + return false; +} + +void QMediaImageViewerControlPrivate::loadImage() +{ + cancelRequests(); + + QMediaImageViewer::MediaStatus currentStatus = status; + status = QMediaImageViewer::InvalidMedia; + + QNetworkAccessManager *network = service->networkManager(); + + while (!possibleResources.isEmpty() && !headReply && !getReply) { + currentMedia = possibleResources.takeFirst(); + + QUrl url = currentMedia.url(); + QString mimeType = currentMedia.mimeType(); + + if (isImageType(url, mimeType)) { + getReply = network->get(QNetworkRequest(url)); + QObject::connect(getReply, SIGNAL(finished()), q_func(), SLOT(_q_getFinished())); + + status = QMediaImageViewer::LoadingMedia; + } else if (mimeType.isEmpty() && url.scheme() != QLatin1String("file")) { + headReply = network->head(QNetworkRequest(currentMedia.url())); + QObject::connect(headReply, SIGNAL(finished()), q_func(), SLOT(_q_headFinished())); + + status = QMediaImageViewer::LoadingMedia; + } + } + + if (status == QMediaImageViewer::InvalidMedia) + currentMedia = QMediaResource(); + + if (status != currentStatus) + emit q_func()->mediaStatusChanged(status); +} + +void QMediaImageViewerControlPrivate::cancelRequests() +{ + if (getReply) { + getReply->abort(); + getReply->deleteLater(); + getReply = 0; + } + + if (headReply) { + headReply->abort(); + headReply->deleteLater(); + headReply = 0; + } +} + +void QMediaImageViewerControlPrivate::_q_getFinished() +{ + if (getReply != q_func()->sender()) + return; + + QImage image; + + if (service->d_func()->load(getReply)) { + possibleResources.clear(); + + status = QMediaImageViewer::LoadedMedia; + + emit q_func()->mediaStatusChanged(status); + } else { + loadImage(); + } +} + +void QMediaImageViewerControlPrivate::_q_headFinished() +{ + if (headReply != q_func()->sender()) + return; + + QString mimeType = headReply->header(QNetworkRequest::ContentTypeHeader) + .toString().section(QLatin1Char(';'), 0, 0); + QUrl url = headReply->url(); + if (url.isEmpty()) + url = headReply->request().url(); + + headReply->deleteLater(); + headReply = 0; + + if (isImageType(url, mimeType) || mimeType.isEmpty()) { + QNetworkAccessManager *network = service->networkManager(); + + getReply = network->get(QNetworkRequest(url)); + + QObject::connect(getReply, SIGNAL(finished()), q_func(), SLOT(_q_getFinished())); + } else { + loadImage(); + } +} + +/*! + \class QMediaImageViewerControl + \internal + \since 1.1 +*/ +QMediaImageViewerControl::QMediaImageViewerControl(QMediaImageViewerService *parent) + : QMediaControl(*new QMediaImageViewerControlPrivate, parent) +{ + Q_D(QMediaImageViewerControl); + + d->service = parent; +} + +/*! +*/ +QMediaImageViewerControl::~QMediaImageViewerControl() +{ + Q_D(QMediaImageViewerControl); + + delete d->getReply; +} + +/*! + \since 1.1 +*/ +QMediaImageViewer::MediaStatus QMediaImageViewerControl::mediaStatus() const +{ + return d_func()->status; +} + +/*! + \fn QMediaImageViewerControl::mediaStatusChanged(QMediaImageViewer::MediaStatus status); + \since 1.1 +*/ + +/*! + \since 1.1 +*/ +void QMediaImageViewerControl::showMedia(const QMediaContent &media) +{ + Q_D(QMediaImageViewerControl); + + d->media = media; + d->currentMedia = QMediaResource(); + d->cancelRequests(); + + if (media.isNull()) { + d->service->d_func()->clear(); + if (d->status != QMediaImageViewer::NoMedia) { + d->status = QMediaImageViewer::NoMedia; + emit mediaStatusChanged(d->status); + } + } else { + d->possibleResources = media.resources(); + d->loadImage(); + } +} + + +#include "moc_qmediaimageviewerservice_p.cpp" +QT_END_NAMESPACE + diff --git a/src/multimedia/qmediaimageviewerservice_p.h b/src/multimedia/qmediaimageviewerservice_p.h new file mode 100644 index 000000000..d1b6956d9 --- /dev/null +++ b/src/multimedia/qmediaimageviewerservice_p.h @@ -0,0 +1,147 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMEDIASLIDESHOWSERVICE_P_H +#define QMEDIASLIDESHOWSERVICE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <qtmultimediadefs.h> +#include <qmediaservice.h> +#include <qmediaimageviewer.h> +#include <qvideorenderercontrol.h> + +#include <QtCore/qpointer.h> +#include <QtGui/qimage.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + +class QAbstractVideoSurface; +class QNetworkAccessManager; +QT_END_NAMESPACE + +QT_BEGIN_NAMESPACE + +class QMediaImageViewerServicePrivate; + +class Q_AUTOTEST_EXPORT QMediaImageViewerService : public QMediaService +{ + Q_OBJECT +public: + explicit QMediaImageViewerService(QObject *parent = 0); + ~QMediaImageViewerService(); + + QMediaControl *requestControl(const char *name); + void releaseControl(QMediaControl *); + + QNetworkAccessManager *networkManager() const; + void setNetworkManager(QNetworkAccessManager *manager); + +private: + Q_DECLARE_PRIVATE(QMediaImageViewerService) + friend class QMediaImageViewerControl; + friend class QMediaImageViewerControlPrivate; +}; + +class QMediaImageViewerControlPrivate; + +class QMediaImageViewerControl : public QMediaControl +{ + Q_OBJECT +public: + explicit QMediaImageViewerControl(QMediaImageViewerService *parent); + ~QMediaImageViewerControl(); + + QMediaImageViewer::MediaStatus mediaStatus() const; + + void showMedia(const QMediaContent &media); + +Q_SIGNALS: + void mediaStatusChanged(QMediaImageViewer::MediaStatus status); + +private: + Q_DECLARE_PRIVATE(QMediaImageViewerControl) + Q_PRIVATE_SLOT(d_func(), void _q_headFinished()) + Q_PRIVATE_SLOT(d_func(), void _q_getFinished()) +}; + +#define QMediaImageViewerControl_iid "com.nokia.Qt.QMediaImageViewerControl/1.0" +Q_MEDIA_DECLARE_CONTROL(QMediaImageViewerControl, QMediaImageViewerControl_iid) + +class QMediaImageViewerRenderer : public QVideoRendererControl +{ + Q_OBJECT +public: + QMediaImageViewerRenderer(QObject *parent = 0); + ~QMediaImageViewerRenderer(); + + QAbstractVideoSurface *surface() const; + void setSurface(QAbstractVideoSurface *surface); + + void showImage(const QImage &image); + +Q_SIGNALS: + void surfaceChanged(QAbstractVideoSurface *surface); + +private: + QPointer<QAbstractVideoSurface> m_surface; + QImage m_image; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + + +#endif diff --git a/src/multimedia/qmedianetworkaccesscontrol.cpp b/src/multimedia/qmedianetworkaccesscontrol.cpp new file mode 100644 index 000000000..a976859ed --- /dev/null +++ b/src/multimedia/qmedianetworkaccesscontrol.cpp @@ -0,0 +1,103 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmedianetworkaccesscontrol.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QMediaNetworkAccessControl + \preliminary + \brief The QMediaNetworkAccessControl class allows the setting of the Network Access Point for media related activities. + \ingroup multimedia-serv + \inmodule QtMultimedia + \since 1.2 + + The functionality provided by this control allows the + setting of a Network Access Point. + + This control can be used to set a network access for various + network related activities. the exact nature in dependant on the underlying + usage by the supported QMediaObject +*/ + +QMediaNetworkAccessControl::QMediaNetworkAccessControl(QObject *parent) : + QMediaControl(parent) +{ +} + +/*! + Destroys a network access control. +*/ +QMediaNetworkAccessControl::~QMediaNetworkAccessControl() +{ +} + +/*! + \fn void QMediaNetworkAccessControl::setConfigurations(const QList<QNetworkConfiguration> &configurations); + + \a configurations contains a list of network configurations to be used for network access. + + It is assumed the list is given in highest to lowest preference order. + By calling this function all previous configurations will be invalidated + and replaced with the new list. + \since 1.2 +*/ + +/* + \fn QNetworkConfiguration QMediaNetworkAccessControl::currentConfiguration() const + + Returns the current active configuration in use. + A default constructed QNetworkConfigration is returned if no user supplied configuration are in use. +*/ + + +/*! + \fn QMediaNetworkAccessControl::configurationChanged(const QNetworkConfiguration &configuration) + This signal is emitted when the current active network configuration changes + to \a configuration. + \since 1.2 +*/ + + + +#include "moc_qmedianetworkaccesscontrol.cpp" +QT_END_NAMESPACE diff --git a/src/multimedia/qmedianetworkaccesscontrol.h b/src/multimedia/qmedianetworkaccesscontrol.h new file mode 100644 index 000000000..22ee95711 --- /dev/null +++ b/src/multimedia/qmedianetworkaccesscontrol.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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#ifndef QMEDIANETWORKACCESSCONTROL_H +#define QMEDIANETWORKACCESSCONTROL_H + +#include "qmediacontrol.h" + +#include <QtCore/qlist.h> +#include <QtNetwork/qnetworkconfiguration.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + +class Q_MULTIMEDIA_EXPORT QMediaNetworkAccessControl : public QMediaControl +{ + Q_OBJECT +public: + + virtual ~QMediaNetworkAccessControl(); + + virtual void setConfigurations(const QList<QNetworkConfiguration> &configuration) = 0; + virtual QNetworkConfiguration currentConfiguration() const = 0; + +Q_SIGNALS: + void configurationChanged(const QNetworkConfiguration& configuration); + +protected: + QMediaNetworkAccessControl(QObject *parent = 0); +}; + +#define QMediaNetworkAccessControl_iid "com.nokia.Qt.QMediaNetworkAccessControl/1.0" +Q_MEDIA_DECLARE_CONTROL(QMediaNetworkAccessControl, QMediaNetworkAccessControl_iid) + +QT_END_NAMESPACE + +QT_END_HEADER + + +#endif diff --git a/src/multimedia/qmediaobject.cpp b/src/multimedia/qmediaobject.cpp new file mode 100644 index 000000000..7eb1a2dfa --- /dev/null +++ b/src/multimedia/qmediaobject.cpp @@ -0,0 +1,423 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtCore/qmetaobject.h> +#include <QtCore/qdebug.h> + +#include "qmediaobject_p.h" + +#include <qmediaservice.h> +#include <qmetadatareadercontrol.h> +#include <qmediabindableinterface.h> + + +QT_BEGIN_NAMESPACE + +void QMediaObjectPrivate::_q_notify() +{ + Q_Q(QMediaObject); + + const QMetaObject* m = q->metaObject(); + + foreach (int pi, notifyProperties) { + QMetaProperty p = m->property(pi); + p.notifySignal().invoke( + q, QGenericArgument(QMetaType::typeName(p.userType()), p.read(q).data())); + } +} + + +/*! + \class QMediaObject + + \brief The QMediaObject class provides a common base for multimedia objects. + + \inmodule QtMultimedia + \ingroup multimedia + \since 1.0 + + QMediaObject derived classes provide access to the functionality of a + QMediaService. Each media object hosts a QMediaService and uses the + QMediaControl interfaces implemented by the service to implement its + API. Most media objects when constructed will request a new + QMediaService instance from a QMediaServiceProvider, but some like + QMediaRecorder will share a service with another object. + + QMediaObject itself provides an API for accessing a media + service's \l {metaData()}{meta-data} and a means of connecting other media objects, + and peripheral classes like QVideoWidget and QMediaPlaylist. + + \sa QMediaService, QMediaControl +*/ + +/*! + Destroys this media object. +*/ + +QMediaObject::~QMediaObject() +{ + delete d_ptr; +} + +/*! + Returns the service availability error state. + \since 1.0 +*/ + +QtMultimedia::AvailabilityError QMediaObject::availabilityError() const +{ + return d_func()->service == 0 ? QtMultimedia::ServiceMissingError : QtMultimedia::NoError; +} + +/*! + Returns true if the service is available for use. + \since 1.0 +*/ + +bool QMediaObject::isAvailable() const +{ + return d_func()->service != 0; +} + +/*! + Returns the media service that provides the functionality of this multimedia object. + \since 1.0 +*/ + +QMediaService* QMediaObject::service() const +{ + return d_func()->service; +} + +int QMediaObject::notifyInterval() const +{ + return d_func()->notifyTimer->interval(); +} + +void QMediaObject::setNotifyInterval(int milliSeconds) +{ + Q_D(QMediaObject); + + if (d->notifyTimer->interval() != milliSeconds) { + d->notifyTimer->setInterval(milliSeconds); + + emit notifyIntervalChanged(milliSeconds); + } +} + +/*! + Bind \a object to this QMediaObject instance. + + This method establishes a relationship between this media object and a + helper object. The nature of the relationship depends on both parties. This + methods returns true if the helper was successfully bound, false otherwise. + + Most subclasses of QMediaObject provide more convenient functions + that wrap this functionality, so this function rarely needs to be + called directly. + + The object passed must implement the QMediaBindableInterface interface. + + \since 1.0 + \sa QMediaBindableInterface +*/ +bool QMediaObject::bind(QObject *object) +{ + QMediaBindableInterface *helper = qobject_cast<QMediaBindableInterface*>(object); + if (!helper) + return false; + + QMediaObject *currentObject = helper->mediaObject(); + + if (currentObject == this) + return true; + + if (currentObject) + currentObject->unbind(object); + + return helper->setMediaObject(this); +} + +/*! + Detach \a object from the QMediaObject instance. + + Unbind the helper object from this media object. A warning + will be generated if the object was not previously bound to this + object. + + \since 1.0 + \sa QMediaBindableInterface +*/ +void QMediaObject::unbind(QObject *object) +{ + QMediaBindableInterface *helper = qobject_cast<QMediaBindableInterface*>(object); + + if (helper && helper->mediaObject() == this) + helper->setMediaObject(0); + else + qWarning() << "QMediaObject: Trying to unbind not connected helper object"; +} + +/*! + Constructs a media object which uses the functionality provided by a media \a service. + + The \a parent is passed to QObject. + + This class is meant as a base class for multimedia objects so this + constructor is protected. + \since 1.0 +*/ + +QMediaObject::QMediaObject(QObject *parent, QMediaService *service): + QObject(parent), + d_ptr(new QMediaObjectPrivate) + +{ + Q_D(QMediaObject); + + d->q_ptr = this; + + d->notifyTimer = new QTimer(this); + d->notifyTimer->setInterval(1000); + connect(d->notifyTimer, SIGNAL(timeout()), SLOT(_q_notify())); + + d->service = service; + + setupMetaData(); +} + +/*! + \internal +*/ + +QMediaObject::QMediaObject(QMediaObjectPrivate &dd, QObject *parent, + QMediaService *service): + QObject(parent), + d_ptr(&dd) +{ + Q_D(QMediaObject); + d->q_ptr = this; + + d->notifyTimer = new QTimer(this); + d->notifyTimer->setInterval(1000); + connect(d->notifyTimer, SIGNAL(timeout()), SLOT(_q_notify())); + + d->service = service; + + setupMetaData(); +} + +/*! + Watch the property \a name. The property's notify signal will be emitted + once every \code notifyInterval milliseconds. + + \since 1.0 + \sa notifyInterval +*/ + +void QMediaObject::addPropertyWatch(QByteArray const &name) +{ + Q_D(QMediaObject); + + const QMetaObject* m = metaObject(); + + int index = m->indexOfProperty(name.constData()); + + if (index != -1 && m->property(index).hasNotifySignal()) { + d->notifyProperties.insert(index); + + if (!d->notifyTimer->isActive()) + d->notifyTimer->start(); + } +} + +/*! + Remove property \a name from the list of properties whose changes are + regularly signaled. + + \since 1.0 + \sa notifyInterval +*/ + +void QMediaObject::removePropertyWatch(QByteArray const &name) +{ + Q_D(QMediaObject); + + int index = metaObject()->indexOfProperty(name.constData()); + + if (index != -1) { + d->notifyProperties.remove(index); + + if (d->notifyProperties.isEmpty()) + d->notifyTimer->stop(); + } +} + +/*! + \property QMediaObject::notifyInterval + + The interval at which notifiable properties will update. + + The interval is expressed in milliseconds, the default value is 1000. + + \since 1.0 + \sa addPropertyWatch(), removePropertyWatch() +*/ + +/*! + \fn void QMediaObject::notifyIntervalChanged(int milliseconds) + + Signal a change in the notify interval period to \a milliseconds. + \since 1.0 +*/ + +/*! + Returns true if there is meta-data associated with this media object, else false. + \since 1.0 +*/ + +bool QMediaObject::isMetaDataAvailable() const +{ + Q_D(const QMediaObject); + + return d->metaDataControl + ? d->metaDataControl->isMetaDataAvailable() + : false; +} + +/*! + \fn QMediaObject::metaDataAvailableChanged(bool available) + + Signals that the \a available state of a media object's meta-data has changed. + \since 1.0 +*/ + +/*! + Returns the value associated with a meta-data \a key. + \since 1.0 +*/ +QVariant QMediaObject::metaData(QtMultimedia::MetaData key) const +{ + Q_D(const QMediaObject); + + return d->metaDataControl + ? d->metaDataControl->metaData(key) + : QVariant(); +} + +/*! + Returns a list of keys there is meta-data available for. + \since 1.0 +*/ +QList<QtMultimedia::MetaData> QMediaObject::availableMetaData() const +{ + Q_D(const QMediaObject); + + return d->metaDataControl + ? d->metaDataControl->availableMetaData() + : QList<QtMultimedia::MetaData>(); +} + +/*! + \fn QMediaObject::metaDataChanged() + + Signals that this media object's meta-data has changed. + \since 1.0 +*/ + +/*! + Returns the value associated with a meta-data \a key. + + The naming and type of extended meta-data is not standardized, so the values and meaning + of keys may vary between backends. + \since 1.0 +*/ +QVariant QMediaObject::extendedMetaData(const QString &key) const +{ + Q_D(const QMediaObject); + + return d->metaDataControl + ? d->metaDataControl->extendedMetaData(key) + : QVariant(); +} + +/*! + Returns a list of keys there is extended meta-data available for. + \since 1.0 +*/ +QStringList QMediaObject::availableExtendedMetaData() const +{ + Q_D(const QMediaObject); + + return d->metaDataControl + ? d->metaDataControl->availableExtendedMetaData() + : QStringList(); +} + + +void QMediaObject::setupMetaData() +{ + Q_D(QMediaObject); + + if (d->service != 0) { + d->metaDataControl = qobject_cast<QMetaDataReaderControl*>( + d->service->requestControl(QMetaDataReaderControl_iid)); + + if (d->metaDataControl) { + connect(d->metaDataControl, SIGNAL(metaDataChanged()), SIGNAL(metaDataChanged())); + connect(d->metaDataControl, + SIGNAL(metaDataAvailableChanged(bool)), + SIGNAL(metaDataAvailableChanged(bool))); + } + } +} + +/*! + \fn QMediaObject::availabilityChanged(bool available) + + Signal emitted when the availability state has changed to \a available + \since 1.0 +*/ + + +#include "moc_qmediaobject.cpp" +QT_END_NAMESPACE + diff --git a/src/multimedia/qmediaobject.h b/src/multimedia/qmediaobject.h new file mode 100644 index 000000000..aba8f7021 --- /dev/null +++ b/src/multimedia/qmediaobject.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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QABSTRACTMEDIAOBJECT_H +#define QABSTRACTMEDIAOBJECT_H + +#include <QtCore/qobject.h> +#include <QtCore/qstringlist.h> + +#include <qtmultimediadefs.h> +#include "qtmedianamespace.h" + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + +class QMediaService; +class QMediaBindableInterface; + +class QMediaObjectPrivate; +class Q_MULTIMEDIA_EXPORT QMediaObject : public QObject +{ + Q_OBJECT + Q_PROPERTY(int notifyInterval READ notifyInterval WRITE setNotifyInterval NOTIFY notifyIntervalChanged) +public: + ~QMediaObject(); + + virtual bool isAvailable() const; + virtual QtMultimedia::AvailabilityError availabilityError() const; + + virtual QMediaService* service() const; + + int notifyInterval() const; + void setNotifyInterval(int milliSeconds); + + virtual bool bind(QObject *); + virtual void unbind(QObject *); + + bool isMetaDataAvailable() const; + + QVariant metaData(QtMultimedia::MetaData key) const; + QList<QtMultimedia::MetaData> availableMetaData() const; + + QVariant extendedMetaData(const QString &key) const; + QStringList availableExtendedMetaData() const; + +Q_SIGNALS: + void notifyIntervalChanged(int milliSeconds); + + void metaDataAvailableChanged(bool available); + void metaDataChanged(); + + void availabilityChanged(bool available); + +protected: + QMediaObject(QObject *parent, QMediaService *service); + QMediaObject(QMediaObjectPrivate &dd, QObject *parent, QMediaService *service); + + void addPropertyWatch(QByteArray const &name); + void removePropertyWatch(QByteArray const &name); + + QMediaObjectPrivate *d_ptr; + +private: + void setupMetaData(); + + Q_DECLARE_PRIVATE(QMediaObject) + Q_PRIVATE_SLOT(d_func(), void _q_notify()) +}; + + +QT_END_NAMESPACE + +QT_END_HEADER + + +#endif // QABSTRACTMEDIAOBJECT_H diff --git a/src/multimedia/qmediaobject_p.h b/src/multimedia/qmediaobject_p.h new file mode 100644 index 000000000..f27420cf0 --- /dev/null +++ b/src/multimedia/qmediaobject_p.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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QABSTRACTMEDIAOBJECT_P_H +#define QABSTRACTMEDIAOBJECT_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtCore/qbytearray.h> +#include <QtCore/qset.h> +#include <QtCore/qtimer.h> + +#include "qmediaobject.h" + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + +class QMetaDataReaderControl; + +#define Q_DECLARE_NON_CONST_PUBLIC(Class) \ + inline Class* q_func() { return static_cast<Class *>(q_ptr); } \ + friend class Class; + + +class QMediaObjectPrivate +{ + Q_DECLARE_PUBLIC(QMediaObject) + +public: + QMediaObjectPrivate():metaDataControl(0), notifyTimer(0) {} + virtual ~QMediaObjectPrivate() {} + + void _q_notify(); + + QMediaService *service; + QMetaDataReaderControl *metaDataControl; + QTimer* notifyTimer; + QSet<int> notifyProperties; + + QMediaObject *q_ptr; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + + +#endif diff --git a/src/multimedia/qmediaplayer.cpp b/src/multimedia/qmediaplayer.cpp new file mode 100644 index 000000000..5d5a7a7a3 --- /dev/null +++ b/src/multimedia/qmediaplayer.cpp @@ -0,0 +1,1139 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtCore/qcoreevent.h> +#include <QtCore/qmetaobject.h> +#include <QtCore/qtimer.h> +#include <QtCore/qdebug.h> +#include <QtCore/qpointer.h> + + +#include "qmediaplayer.h" + +#include <qmediaobject_p.h> +#include <qmediaservice.h> +#include <qmediaplayercontrol.h> +#include <qmediaserviceprovider.h> +#include <qmediaplaylist.h> +#include <qmediaplaylistcontrol.h> +#include <qmediaplaylistsourcecontrol.h> +#include <qvideosurfaceoutput_p.h> +#include <qmedianetworkaccesscontrol.h> + +QT_BEGIN_NAMESPACE + +/*! + \class QMediaPlayer + \brief The QMediaPlayer class allows the playing of a media source. + \inmodule QtMultimedia + \ingroup multimedia + \since 1.0 + + + + The QMediaPlayer class is a high level media playback class. It can be used + to playback such content as songs, movies and internet radio. The content + to playback is specified as a QMediaContent, which can be thought of as a + main or canonical URL with addition information attached. When provided + with a QMediaContent playback may be able to commence. + + \snippet doc/src/snippets/multimedia-snippets/media.cpp Player + + QVideoWidget can be used with QMediaPlayer for video rendering and QMediaPlaylist + for accessing playlist functionality. + + \snippet doc/src/snippets/multimedia-snippets/media.cpp Movie playlist + + \sa QMediaObject, QMediaService, QVideoWidget, QMediaPlaylist +*/ + +namespace +{ +class MediaPlayerRegisterMetaTypes +{ +public: + MediaPlayerRegisterMetaTypes() + { + qRegisterMetaType<QMediaPlayer::State>("QMediaPlayer::State"); + qRegisterMetaType<QMediaPlayer::MediaStatus>("QMediaPlayer::MediaStatus"); + qRegisterMetaType<QMediaPlayer::Error>("QMediaPlayer::Error"); + } +} _registerPlayerMetaTypes; +} + +class QMediaPlayerPrivate : public QMediaObjectPrivate +{ + Q_DECLARE_NON_CONST_PUBLIC(QMediaPlayer) + +public: + QMediaPlayerPrivate() + : provider(0) + , control(0) + , playlistSourceControl(0) + , state(QMediaPlayer::StoppedState) + , error(QMediaPlayer::NoError) + , filterStates(false) + , playlist(0) + {} + + QMediaServiceProvider *provider; + QMediaPlayerControl* control; + QMediaPlaylistSourceControl* playlistSourceControl; + QMediaPlayer::State state; + QMediaPlayer::Error error; + QString errorString; + bool filterStates; + + QPointer<QObject> videoOutput; + QMediaPlaylist *playlist; + QMediaNetworkAccessControl *networkAccessControl; + QVideoSurfaceOutput surfaceOutput; + + void _q_stateChanged(QMediaPlayer::State state); + void _q_mediaStatusChanged(QMediaPlayer::MediaStatus status); + void _q_error(int error, const QString &errorString); + void _q_updateMedia(const QMediaContent&); + void _q_playlistDestroyed(); +}; + +void QMediaPlayerPrivate::_q_stateChanged(QMediaPlayer::State ps) +{ + Q_Q(QMediaPlayer); + + if (filterStates) + return; + + if (playlist + && ps != state && ps == QMediaPlayer::StoppedState + && (control->mediaStatus() == QMediaPlayer::EndOfMedia || + control->mediaStatus() == QMediaPlayer::InvalidMedia)) { + playlist->next(); + ps = control->state(); + } + + if (ps != state) { + state = ps; + + if (ps == QMediaPlayer::PlayingState) + q->addPropertyWatch("position"); + else + q->removePropertyWatch("position"); + + emit q->stateChanged(ps); + } +} + +void QMediaPlayerPrivate::_q_mediaStatusChanged(QMediaPlayer::MediaStatus status) +{ + Q_Q(QMediaPlayer); + + switch (status) { + case QMediaPlayer::StalledMedia: + case QMediaPlayer::BufferingMedia: + q->addPropertyWatch("bufferStatus"); + emit q->mediaStatusChanged(status); + break; + default: + q->removePropertyWatch("bufferStatus"); + emit q->mediaStatusChanged(status); + break; + } + +} + +void QMediaPlayerPrivate::_q_error(int error, const QString &errorString) +{ + Q_Q(QMediaPlayer); + + this->error = QMediaPlayer::Error(error); + this->errorString = errorString; + + emit q->error(this->error); +} + +void QMediaPlayerPrivate::_q_updateMedia(const QMediaContent &media) +{ + Q_Q(QMediaPlayer); + + if (!control) + return; + + const QMediaPlayer::State currentState = state; + + filterStates = true; + control->setMedia(media, 0); + + if (!media.isNull()) { + switch (currentState) { + case QMediaPlayer::PlayingState: + control->play(); + break; + case QMediaPlayer::PausedState: + control->pause(); + break; + default: + break; + } + } + filterStates = false; + + state = control->state(); + + if (state != currentState) { + if (state == QMediaPlayer::PlayingState) + q->addPropertyWatch("position"); + else + q->removePropertyWatch("position"); + + emit q->stateChanged(state); + } +} + +void QMediaPlayerPrivate::_q_playlistDestroyed() +{ + playlist = 0; + + if (!control) + return; + + if (playlistSourceControl) + playlistSourceControl->setPlaylist(0); + + control->setMedia(QMediaContent(), 0); +} + +static QMediaService *playerService(QMediaPlayer::Flags flags, QMediaServiceProvider *provider) +{ + if (flags) { + QMediaServiceProviderHint::Features features = 0; + if (flags & QMediaPlayer::LowLatency) + features |= QMediaServiceProviderHint::LowLatencyPlayback; + + if (flags & QMediaPlayer::StreamPlayback) + features |= QMediaServiceProviderHint::StreamPlayback; + + if (flags & QMediaPlayer::VideoSurface) + features |= QMediaServiceProviderHint::VideoSurface; + + return provider->requestService(Q_MEDIASERVICE_MEDIAPLAYER, + QMediaServiceProviderHint(features)); + } else + return provider->requestService(Q_MEDIASERVICE_MEDIAPLAYER); +} + + +/*! + Construct a QMediaPlayer that uses the playback service from \a provider, + parented to \a parent and with \a flags. + + If a playback service is not specified the system default will be used. + \since 1.0 +*/ + +QMediaPlayer::QMediaPlayer(QObject *parent, QMediaPlayer::Flags flags, QMediaServiceProvider *provider): + QMediaObject(*new QMediaPlayerPrivate, + parent, + playerService(flags,provider)) +{ + Q_D(QMediaPlayer); + + d->provider = provider; + + if (d->service == 0) { + d->error = ServiceMissingError; + } else { + d->control = qobject_cast<QMediaPlayerControl*>(d->service->requestControl(QMediaPlayerControl_iid)); + d->playlistSourceControl = qobject_cast<QMediaPlaylistSourceControl*>(d->service->requestControl(QMediaPlaylistSourceControl_iid)); + d->networkAccessControl = qobject_cast<QMediaNetworkAccessControl*>(d->service->requestControl(QMediaNetworkAccessControl_iid)); + if (d->control != 0) { + connect(d->control, SIGNAL(mediaChanged(QMediaContent)), SIGNAL(mediaChanged(QMediaContent))); + connect(d->control, SIGNAL(stateChanged(QMediaPlayer::State)), SLOT(_q_stateChanged(QMediaPlayer::State))); + connect(d->control, SIGNAL(mediaStatusChanged(QMediaPlayer::MediaStatus)), + SLOT(_q_mediaStatusChanged(QMediaPlayer::MediaStatus))); + connect(d->control, SIGNAL(error(int,QString)), SLOT(_q_error(int,QString))); + + connect(d->control, SIGNAL(durationChanged(qint64)), SIGNAL(durationChanged(qint64))); + connect(d->control, SIGNAL(positionChanged(qint64)), SIGNAL(positionChanged(qint64))); + connect(d->control, SIGNAL(audioAvailableChanged(bool)), SIGNAL(audioAvailableChanged(bool))); + connect(d->control, SIGNAL(videoAvailableChanged(bool)), SIGNAL(videoAvailableChanged(bool))); + connect(d->control, SIGNAL(volumeChanged(int)), SIGNAL(volumeChanged(int))); + connect(d->control, SIGNAL(mutedChanged(bool)), SIGNAL(mutedChanged(bool))); + connect(d->control, SIGNAL(seekableChanged(bool)), SIGNAL(seekableChanged(bool))); + connect(d->control, SIGNAL(playbackRateChanged(qreal)), SIGNAL(playbackRateChanged(qreal))); + connect(d->control, SIGNAL(bufferStatusChanged(int)), SIGNAL(bufferStatusChanged(int))); + + if (d->control->state() == PlayingState) + addPropertyWatch("position"); + + if (d->control->mediaStatus() == StalledMedia || d->control->mediaStatus() == BufferingMedia) + addPropertyWatch("bufferStatus"); + } + if (d->networkAccessControl != 0) { + connect(d->networkAccessControl, SIGNAL(configurationChanged(QNetworkConfiguration)), + this, SIGNAL(networkConfigurationChanged(QNetworkConfiguration))); + } + } +} + + +/*! + Destroys the player object. +*/ + +QMediaPlayer::~QMediaPlayer() +{ + Q_D(QMediaPlayer); + + if (d->service) { + if (d->control) + d->service->releaseControl(d->control); + } + + d->provider->releaseService(d->service); +} + +QMediaContent QMediaPlayer::media() const +{ + Q_D(const QMediaPlayer); + + if (d->control != 0) + return d->control->media(); + + return QMediaContent(); +} + +/*! + Returns the stream source of media data. + + This is only valid if a stream was passed to setMedia(). + + \since 1.0 + \sa setMedia() +*/ + +const QIODevice *QMediaPlayer::mediaStream() const +{ + Q_D(const QMediaPlayer); + + if (d->control != 0) + return d->control->mediaStream(); + + return 0; +} + +QMediaPlaylist *QMediaPlayer::playlist() const +{ + return d_func()->playlistSourceControl ? + d_func()->playlistSourceControl->playlist() : + d_func()->playlist; +} + +void QMediaPlayer::setPlaylist(QMediaPlaylist *playlist) +{ + Q_D(QMediaPlayer); + + if (d->playlistSourceControl) { + if (d->playlistSourceControl->playlist()) + disconnect(d->playlist, SIGNAL(destroyed()), this, SLOT(_q_playlistDestroyed())); + + d->playlistSourceControl->setPlaylist(playlist); + + if (playlist) + connect(d->playlist, SIGNAL(destroyed()), this, SLOT(_q_playlistDestroyed())); + } else { + if (d->playlist) { + disconnect(d->playlist, SIGNAL(currentMediaChanged(QMediaContent)), + this, SLOT(_q_updateMedia(QMediaContent))); + disconnect(d->playlist, SIGNAL(destroyed()), this, SLOT(_q_playlistDestroyed())); + } + + d->playlist = playlist; + + if (d->playlist) { + connect(d->playlist, SIGNAL(currentMediaChanged(QMediaContent)), + this, SLOT(_q_updateMedia(QMediaContent))); + connect(d->playlist, SIGNAL(destroyed()), this, SLOT(_q_playlistDestroyed())); + + if (d->control != 0) + d->control->setMedia(playlist->currentMedia(), 0); + } else { + setMedia(QMediaContent(), 0); + } + + } +} + +/*! + Sets the network access points for remote media playback. + \a configurations contains, in ascending preferential order, a list of + configuration that can be used for network access. + + This will invalidate the choice of previous configurations. + \since 1.2 +*/ +void QMediaPlayer::setNetworkConfigurations(const QList<QNetworkConfiguration> &configurations) +{ + Q_D(QMediaPlayer); + + if (d->networkAccessControl) + d->networkAccessControl->setConfigurations(configurations); +} + +QMediaPlayer::State QMediaPlayer::state() const +{ + return d_func()->state; +} + +QMediaPlayer::MediaStatus QMediaPlayer::mediaStatus() const +{ + Q_D(const QMediaPlayer); + + if (d->control != 0) + return d->control->mediaStatus(); + + return QMediaPlayer::UnknownMediaStatus; +} + +qint64 QMediaPlayer::duration() const +{ + Q_D(const QMediaPlayer); + + if (d->control != 0) + return d->control->duration(); + + return -1; +} + +qint64 QMediaPlayer::position() const +{ + Q_D(const QMediaPlayer); + + if (d->control != 0) + return d->control->position(); + + return 0; +} + +int QMediaPlayer::volume() const +{ + Q_D(const QMediaPlayer); + + if (d->control != 0) + return d->control->volume(); + + return 0; +} + +bool QMediaPlayer::isMuted() const +{ + Q_D(const QMediaPlayer); + + if (d->control != 0) + return d->control->isMuted(); + + return false; +} + +int QMediaPlayer::bufferStatus() const +{ + Q_D(const QMediaPlayer); + + if (d->control != 0) + return d->control->bufferStatus(); + + return 0; +} + +bool QMediaPlayer::isAudioAvailable() const +{ + Q_D(const QMediaPlayer); + + if (d->control != 0) + return d->control->isAudioAvailable(); + + return false; +} + +bool QMediaPlayer::isVideoAvailable() const +{ + Q_D(const QMediaPlayer); + + if (d->control != 0) + return d->control->isVideoAvailable(); + + return false; +} + +bool QMediaPlayer::isSeekable() const +{ + Q_D(const QMediaPlayer); + + if (d->control != 0) + return d->control->isSeekable(); + + return false; +} + +qreal QMediaPlayer::playbackRate() const +{ + Q_D(const QMediaPlayer); + + if (d->control != 0) + return d->control->playbackRate(); + + return 0.0; +} + +/*! + Returns the current error state. + \since 1.0 +*/ + +QMediaPlayer::Error QMediaPlayer::error() const +{ + return d_func()->error; +} + +QString QMediaPlayer::errorString() const +{ + return d_func()->errorString; +} + +/*! + Returns the current network access point in use. + If a default contructed QNetworkConfiguration is returned + this feature is not available or that none of the + current supplied configurations are in use. + \since 1.2 +*/ +QNetworkConfiguration QMediaPlayer::currentNetworkConfiguration() const +{ + Q_D(const QMediaPlayer); + + if (d->networkAccessControl) + return d_func()->networkAccessControl->currentConfiguration(); + + return QNetworkConfiguration(); +} + +//public Q_SLOTS: +/*! + Start or resume playing the current source. + \since 1.0 +*/ + +void QMediaPlayer::play() +{ + Q_D(QMediaPlayer); + + if (d->control == 0) { + QMetaObject::invokeMethod(this, "_q_error", Qt::QueuedConnection, + Q_ARG(int, QMediaPlayer::ServiceMissingError), + Q_ARG(QString, tr("The QMediaPlayer object does not have a valid service"))); + return; + } + + //if playlist control is available, the service should advance itself + if (d->playlist && d->playlist->currentIndex() == -1 && !d->playlist->isEmpty()) + d->playlist->setCurrentIndex(0); + + // Reset error conditions + d->error = NoError; + d->errorString = QString(); + + d->control->play(); +} + +/*! + Pause playing the current source. + \since 1.0 +*/ + +void QMediaPlayer::pause() +{ + Q_D(QMediaPlayer); + + if (d->control != 0) + d->control->pause(); +} + +/*! + Stop playing, and reset the play position to the beginning. + \since 1.0 +*/ + +void QMediaPlayer::stop() +{ + Q_D(QMediaPlayer); + + if (d->control != 0) + d->control->stop(); +} + +void QMediaPlayer::setPosition(qint64 position) +{ + Q_D(QMediaPlayer); + + if (d->control == 0 || !isSeekable()) + return; + + d->control->setPosition(qBound(qint64(0), position, duration())); +} + +void QMediaPlayer::setVolume(int v) +{ + Q_D(QMediaPlayer); + + if (d->control == 0) + return; + + int clamped = qBound(0, v, 100); + if (clamped == volume()) + return; + + d->control->setVolume(clamped); +} + +void QMediaPlayer::setMuted(bool muted) +{ + Q_D(QMediaPlayer); + + if (d->control == 0 || muted == isMuted()) + return; + + d->control->setMuted(muted); +} + +void QMediaPlayer::setPlaybackRate(qreal rate) +{ + Q_D(QMediaPlayer); + + if (d->control != 0) + d->control->setPlaybackRate(rate); +} + +/*! + Sets the current \a media source. + + If a \a stream is supplied; media data will be read from it instead of resolving the media + source. In this case the media source may still be used to resolve additional information + about the media such as mime type. + + Setting the media to a null QMediaContent will cause the player to discard all + information relating to the current media source and to cease all I/O operations related + to that media. + \since 1.0 +*/ + +void QMediaPlayer::setMedia(const QMediaContent &media, QIODevice *stream) +{ + Q_D(QMediaPlayer); + + if (playlist() && playlist()->currentMedia() != media) + setPlaylist(0); + + if (d->control != 0) + d_func()->control->setMedia(media, stream); +} + +/*! + \internal + \since 1.0 +*/ + +bool QMediaPlayer::bind(QObject *obj) +{ + return QMediaObject::bind(obj); +} + +/*! + \internal + \since 1.0 +*/ + +void QMediaPlayer::unbind(QObject *obj) +{ + QMediaObject::unbind(obj); +} + +/*! + Returns the level of support a media player has for a \a mimeType and a set of \a codecs. + + The \a flags argument allows additional requirements such as performance indicators to be + specified. + \since 1.0 +*/ +QtMultimedia::SupportEstimate QMediaPlayer::hasSupport(const QString &mimeType, + const QStringList& codecs, + Flags flags) +{ + return QMediaServiceProvider::defaultServiceProvider()->hasSupport(QByteArray(Q_MEDIASERVICE_MEDIAPLAYER), + mimeType, + codecs, + flags); +} + +/*! + \deprecated + Returns a list of MIME types supported by the media player. + + The \a flags argument causes the resultant list to be restricted to MIME types which can be supported + given additional requirements, such as performance indicators. + + This function may not return useful results on some platforms, and support for a specific file of a + given mime type is not guaranteed even if the mime type is in general supported. In addition, in some + cases this function will need to load all available media plugins and query them for their support, which + may take some time. + \since 1.0 +*/ +QStringList QMediaPlayer::supportedMimeTypes(Flags flags) +{ + return QMediaServiceProvider::defaultServiceProvider()->supportedMimeTypes(QByteArray(Q_MEDIASERVICE_MEDIAPLAYER), + flags); +} + +/*! + \fn void QMediaPlayer::setVideoOutput(QVideoWidget* output) + + Attach a QVideoWidget video \a output to the media player. + + If the media player has already video output attached, + it will be replaced with a new one. + \since 1.0 +*/ +void QMediaPlayer::setVideoOutput(QVideoWidget *output) +{ + Q_D(QMediaPlayer); + + if (d->videoOutput) + unbind(d->videoOutput); + + // We don't know (in this library) that QVideoWidget inherits QObject + QObject *outputObject = reinterpret_cast<QObject*>(output); + + d->videoOutput = outputObject && bind(outputObject) ? outputObject : 0; +} + +/*! + \fn void QMediaPlayer::setVideoOutput(QGraphicsVideoItem* output) + + Attach a QGraphicsVideoItem video \a output to the media player. + + If the media player has already video output attached, + it will be replaced with a new one. + \since 1.0 +*/ +void QMediaPlayer::setVideoOutput(QGraphicsVideoItem *output) +{ + Q_D(QMediaPlayer); + + if (d->videoOutput) + unbind(d->videoOutput); + + // We don't know (in this library) that QGraphicsVideoItem (multiply) inherits QObject + // but QObject inheritance depends on QObject coming first, so try this out. + QObject *outputObject = reinterpret_cast<QObject*>(output); + + d->videoOutput = outputObject && bind(outputObject) ? outputObject : 0; +} + +/*! + Sets a video \a surface as the video output of a media player. + + If a video output has already been set on the media player the new surface + will replace it. + \since 1.2 +*/ + +void QMediaPlayer::setVideoOutput(QAbstractVideoSurface *surface) +{ + Q_D(QMediaPlayer); + + d->surfaceOutput.setVideoSurface(surface); + + if (d->videoOutput != &d->surfaceOutput) { + if (d->videoOutput) + unbind(d->videoOutput); + + d->videoOutput = bind(&d->surfaceOutput) ? &d->surfaceOutput : 0; + } +} + +// Enums +/*! + \enum QMediaPlayer::State + + Defines the current state of a media player. + + \value PlayingState The media player is currently playing content. + \value PausedState The media player has paused playback, playback of the current track will + resume from the position the player was paused at. + \value StoppedState The media player is not playing content, playback will begin from the start + of the current track. +*/ + +/*! + \enum QMediaPlayer::MediaStatus + + Defines the status of a media player's current media. + + \value UnknownMediaStatus The status of the media cannot be determined. + \value NoMedia The is no current media. The player is in the StoppedState. + \value LoadingMedia The current media is being loaded. The player may be in any state. + \value LoadedMedia The current media has been loaded. The player is in the StoppedState. + \value StalledMedia Playback of the current media has stalled due to insufficient buffering or + some other temporary interruption. The player is in the PlayingState or PausedState. + \value BufferingMedia The player is buffering data but has enough data buffered for playback to + continue for the immediate future. The player is in the PlayingState or PausedState. + \value BufferedMedia The player has fully buffered the current media. The player is in the + PlayingState or PausedState. + \value EndOfMedia Playback has reached the end of the current media. The player is in the + StoppedState. + \value InvalidMedia The current media cannot be played. The player is in the StoppedState. +*/ + +/*! + \enum QMediaPlayer::Error + + Defines a media player error condition. + + \value NoError No error has occurred. + \value ResourceError A media resource couldn't be resolved. + \value FormatError The format of a media resource isn't (fully) supported. Playback may still + be possible, but without an audio or video component. + \value NetworkError A network error occurred. + \value AccessDeniedError There are not the appropriate permissions to play a media resource. + \value ServiceMissingError A valid playback service was not found, playback cannot proceed. +*/ + +// Signals +/*! + \fn QMediaPlayer::error(QMediaPlayer::Error error) + + Signals that an \a error condition has occurred. + + \since 1.0 + \sa errorString() +*/ + +/*! + \fn void QMediaPlayer::stateChanged(State state) + + \since 1.0 + Signal the \a state of the Player object has changed. +*/ + +/*! + \fn QMediaPlayer::mediaStatusChanged(QMediaPlayer::MediaStatus status) + + Signals that the \a status of the current media has changed. + + \since 1.0 + \sa mediaStatus() +*/ + +/*! + \fn void QMediaPlayer::mediaChanged(const QMediaContent &media); + + Signals that the current playing content will be obtained from \a media. + + \since 1.0 + \sa media() +*/ + +/*! + \fn void QMediaPlayer::playbackRateChanged(qreal rate); + + Signals the playbackRate has changed to \a rate. + \since 1.0 +*/ + +/*! + \fn void QMediaPlayer::seekableChanged(bool seekable); + + Signals the \a seekable status of the player object has changed. + \since 1.0 +*/ + +// Properties +/*! + \property QMediaPlayer::state + \brief the media player's playback state. + + By default this property is QMediaPlayer::Stopped + + \since 1.0 + \sa mediaStatus(), play(), pause(), stop() +*/ + +/*! + \property QMediaPlayer::error + \brief a string describing the last error condition. + + \since 1.0 + \sa error() +*/ + +/*! + \property QMediaPlayer::media + \brief the active media source being used by the player object. + + The player object will use the QMediaContent for selection of the content to + be played. + + By default this property has a null QMediaContent. + + Setting this property to a null QMediaContent will cause the player to discard all + information relating to the current media source and to cease all I/O operations related + to that media. + + \since 1.0 + \sa QMediaContent +*/ + +/*! + \property QMediaPlayer::playlist + \brief the media playlist being used by the player object. + + The player object will use the current playlist item for selection of the content to + be played. + + By default this property is set to null. + + If the media playlist is used as a source, QMediaPlayer::media is updated with + a current playlist item. The current source should be selected with + QMediaPlaylist::setCurrentIndex(int) instead of QMediaPlayer::setMedia(), + otherwise the current playlist will be discarded. + + \since 1.0 + \sa QMediaContent +*/ + + +/*! + \property QMediaPlayer::mediaStatus + \brief the status of the current media stream. + + The stream status describes how the playback of the current stream is + progressing. + + By default this property is QMediaPlayer::NoMedia + + \since 1.0 + \sa state +*/ + +/*! + \property QMediaPlayer::duration + \brief the duration of the current media. + + The value is the total playback time in milliseconds of the current media. + The value may change across the life time of the QMediaPlayer object and + may not be available when initial playback begins, connect to the + durationChanged() signal to receive status notifications. + \since 1.0 +*/ + +/*! + \property QMediaPlayer::position + \brief the playback position of the current media. + + The value is the current playback position, expressed in milliseconds since + the beginning of the media. Periodically changes in the position will be + indicated with the signal positionChanged(), the interval between updates + can be set with QMediaObject's method setNotifyInterval(). + \since 1.0 +*/ + +/*! + \property QMediaPlayer::volume + \brief the current playback volume. + + The playback volume is a linear in effect and the value can range from 0 - + 100, values outside this range will be clamped. + \since 1.0 +*/ + +/*! + \property QMediaPlayer::muted + \brief the muted state of the current media. + + The value will be true if the playback volume is muted; otherwise false. + \since 1.0 +*/ + +/*! + \property QMediaPlayer::bufferStatus + \brief 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. + + \since 1.0 + \sa mediaStatus() +*/ + +/*! + \property QMediaPlayer::audioAvailable + \brief the audio availabilty status for the current media. + + As the life time of QMediaPlayer can be longer than the playback of one + QMediaContent, this property may change over time, the + audioAvailableChanged signal can be used to monitor it's status. + \since 1.0 +*/ + +/*! + \property QMediaPlayer::videoAvailable + \brief the video availability status for the current media. + + If available, the QVideoWidget class can be used to view the video. As the + life time of QMediaPlayer can be longer than the playback of one + QMediaContent, this property may change over time, the + videoAvailableChanged signal can be used to monitor it's status. + + \since 1.0 + \sa QVideoWidget, QMediaContent +*/ + +/*! + \property QMediaPlayer::seekable + \brief the seek-able status of the current media + + If seeking is supported this property will be true; false otherwise. The + status of this property may change across the life time of the QMediaPlayer + object, use the seekableChanged signal to monitor changes. + \since 1.0 +*/ + +/*! + \property QMediaPlayer::playbackRate + \brief the playback rate of the current media. + + This value is a multiplier applied to the media's standard play rate. By + default this value is 1.0, indicating that the media is playing at the + standard pace. Values higher than 1.0 will increase the rate of play. + Values less than zero can be set and indicate the media will rewind at the + multiplier of the standard pace. + + Not all playback services support change of the playback rate. It is + framework defined as to the status and quality of audio and video + while fast forwarding or rewinding. + \since 1.0 +*/ + +/*! + \fn void QMediaPlayer::durationChanged(qint64 duration) + + Signal the duration of the content has changed to \a duration, expressed in milliseconds. + \since 1.0 +*/ + +/*! + \fn void QMediaPlayer::positionChanged(qint64 position) + + Signal the position of the content has changed to \a position, expressed in + milliseconds. + \since 1.0 +*/ + +/*! + \fn void QMediaPlayer::volumeChanged(int volume) + + Signal the playback volume has changed to \a volume. + \since 1.0 +*/ + +/*! + \fn void QMediaPlayer::mutedChanged(bool muted) + + Signal the mute state has changed to \a muted. + \since 1.0 +*/ + +/*! + \fn void QMediaPlayer::videoAvailableChanged(bool videoAvailable) + + Signal the availability of visual content has changed to \a videoAvailable. + \since 1.0 +*/ + +/*! + \fn void QMediaPlayer::audioAvailableChanged(bool available) + + Signals the availability of audio content has changed to \a available. + \since 1.0 +*/ + +/*! + \fn void QMediaPlayer::bufferStatusChanged(int percentFilled) + + Signal the amount of the local buffer filled as a percentage by \a percentFilled. + \since 1.0 +*/ + +/*! + \fn void QMediaPlayer::networkConfigurationChanged(const QNetworkConfiguration &configuration) + + Signal that the active in use network access point has been changed to \a configuration and all subsequent network access will use this \a configuration. + \since 1.2 +*/ + +/*! + \enum QMediaPlayer::Flag + + \value LowLatency The player is expected to be used with simple audio formats, + but playback should start without significant delay. + Such playback service can be used for beeps, ringtones, etc. + + \value StreamPlayback The player is expected to play QIODevice based streams. + If passed to QMediaPlayer constructor, the service supporting + streams playback will be chosen. + + \value VideoSurface The player is expected to be able to render to a + QAbstractVideoSurface \l {setVideoOutput()}{output}. +*/ + +#include "moc_qmediaplayer.cpp" +QT_END_NAMESPACE + diff --git a/src/multimedia/qmediaplayer.h b/src/multimedia/qmediaplayer.h new file mode 100644 index 000000000..f53b50ceb --- /dev/null +++ b/src/multimedia/qmediaplayer.h @@ -0,0 +1,227 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMEDIAPLAYER_H +#define QMEDIAPLAYER_H + + +#include "qmediaserviceprovider.h" +#include "qmediaobject.h" +#include "qmediacontent.h" +#include "qmediaenumdebug.h" + +#include <QtNetwork/qnetworkconfiguration.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + +class QAbstractVideoSurface; +class QMediaPlaylist; +class QVideoWidget; +class QGraphicsVideoItem; + +class QMediaPlayerPrivate; +class Q_MULTIMEDIA_EXPORT QMediaPlayer : public QMediaObject +{ + Q_OBJECT + Q_PROPERTY(QMediaContent media READ media WRITE setMedia NOTIFY mediaChanged) + Q_PROPERTY(QMediaPlaylist * playlist READ playlist WRITE setPlaylist) + Q_PROPERTY(qint64 duration READ duration NOTIFY durationChanged) + Q_PROPERTY(qint64 position READ position WRITE setPosition NOTIFY positionChanged) + Q_PROPERTY(int volume READ volume WRITE setVolume NOTIFY volumeChanged) + Q_PROPERTY(bool muted READ isMuted WRITE setMuted NOTIFY mutedChanged) + Q_PROPERTY(int bufferStatus READ bufferStatus NOTIFY bufferStatusChanged) + Q_PROPERTY(bool audioAvailable READ isAudioAvailable NOTIFY audioAvailableChanged) + Q_PROPERTY(bool videoAvailable READ isVideoAvailable NOTIFY videoAvailableChanged) + Q_PROPERTY(bool seekable READ isSeekable NOTIFY seekableChanged) + Q_PROPERTY(qreal playbackRate READ playbackRate WRITE setPlaybackRate NOTIFY playbackRateChanged) + Q_PROPERTY(State state READ state NOTIFY stateChanged) + Q_PROPERTY(MediaStatus mediaStatus READ mediaStatus NOTIFY mediaStatusChanged) + Q_PROPERTY(QString error READ errorString) + Q_ENUMS(State) + Q_ENUMS(MediaStatus) + Q_ENUMS(Error) + +public: + enum State + { + StoppedState, + PlayingState, + PausedState + }; + + enum MediaStatus + { + UnknownMediaStatus, + NoMedia, + LoadingMedia, + LoadedMedia, + StalledMedia, + BufferingMedia, + BufferedMedia, + EndOfMedia, + InvalidMedia + }; + + enum Flag + { + LowLatency = 0x01, + StreamPlayback = 0x02, + VideoSurface = 0x04 + }; + Q_DECLARE_FLAGS(Flags, Flag) + + enum Error + { + NoError, + ResourceError, + FormatError, + NetworkError, + AccessDeniedError, + ServiceMissingError + }; + + QMediaPlayer(QObject *parent = 0, Flags flags = 0, QMediaServiceProvider *provider = QMediaServiceProvider::defaultServiceProvider()); + ~QMediaPlayer(); + + static QtMultimedia::SupportEstimate hasSupport(const QString &mimeType, + const QStringList& codecs = QStringList(), + Flags flags = 0); + static QStringList supportedMimeTypes(Flags flags = 0); + + void setVideoOutput(QVideoWidget *); + void setVideoOutput(QGraphicsVideoItem *); + void setVideoOutput(QAbstractVideoSurface *surface); + + QMediaContent media() const; + const QIODevice *mediaStream() const; + QMediaPlaylist *playlist() const; + + State state() const; + MediaStatus mediaStatus() const; + + qint64 duration() const; + qint64 position() const; + + int volume() const; + bool isMuted() const; + bool isAudioAvailable() const; + bool isVideoAvailable() const; + + int bufferStatus() const; + + bool isSeekable() const; + qreal playbackRate() const; + + Error error() const; + QString errorString() const; + + QNetworkConfiguration currentNetworkConfiguration() const; + +public Q_SLOTS: + void play(); + void pause(); + void stop(); + + void setPosition(qint64 position); + void setVolume(int volume); + void setMuted(bool muted); + + void setPlaybackRate(qreal rate); + + void setMedia(const QMediaContent &media, QIODevice *stream = 0); + void setPlaylist(QMediaPlaylist *playlist); + + void setNetworkConfigurations(const QList<QNetworkConfiguration> &configurations); + +Q_SIGNALS: + void mediaChanged(const QMediaContent &media); + + void stateChanged(QMediaPlayer::State newState); + void mediaStatusChanged(QMediaPlayer::MediaStatus status); + + void durationChanged(qint64 duration); + void positionChanged(qint64 position); + + void volumeChanged(int volume); + void mutedChanged(bool muted); + void audioAvailableChanged(bool available); + void videoAvailableChanged(bool videoAvailable); + + void bufferStatusChanged(int percentFilled); + + void seekableChanged(bool seekable); + void playbackRateChanged(qreal rate); + + void error(QMediaPlayer::Error error); + + void networkConfigurationChanged(const QNetworkConfiguration &configuration); +public: + virtual bool bind(QObject *); + virtual void unbind(QObject *); + +private: + Q_DISABLE_COPY(QMediaPlayer) + Q_DECLARE_PRIVATE(QMediaPlayer) + Q_PRIVATE_SLOT(d_func(), void _q_stateChanged(QMediaPlayer::State)) + Q_PRIVATE_SLOT(d_func(), void _q_mediaStatusChanged(QMediaPlayer::MediaStatus)) + Q_PRIVATE_SLOT(d_func(), void _q_error(int, const QString &)) + Q_PRIVATE_SLOT(d_func(), void _q_updateMedia(const QMediaContent&)) + Q_PRIVATE_SLOT(d_func(), void _q_playlistDestroyed()) +}; + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(QMediaPlayer::State) +Q_DECLARE_METATYPE(QMediaPlayer::MediaStatus) +Q_DECLARE_METATYPE(QMediaPlayer::Error) + +Q_MEDIA_ENUM_DEBUG(QMediaPlayer, State) +Q_MEDIA_ENUM_DEBUG(QMediaPlayer, MediaStatus) +Q_MEDIA_ENUM_DEBUG(QMediaPlayer, Error) + +QT_END_HEADER + +#endif // QMEDIAPLAYER_H diff --git a/src/multimedia/qmediaplayercontrol.cpp b/src/multimedia/qmediaplayercontrol.cpp new file mode 100644 index 000000000..2585b044c --- /dev/null +++ b/src/multimedia/qmediaplayercontrol.cpp @@ -0,0 +1,414 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmediaplayercontrol.h" +#include "qmediacontrol_p.h" +#include "qmediaplayer.h" + +QT_BEGIN_NAMESPACE + + +/*! + \class QMediaPlayerControl + \inmodule QtMultimedia + \ingroup multimedia-serv + \since 1.0 + + + \brief The QMediaPlayerControl class provides access to the media playing + functionality of a QMediaService. + + If a QMediaService can play media is will implement QMediaPlayerControl. + This control provides a means to set the \l {setMedia()}{media} to play, + \l {play()}{start}, \l {pause()} {pause} and \l {stop()}{stop} playback, + \l {setPosition()}{seek}, and control the \l {setVolume()}{volume}. + It also provides feedback on the \l {duration()}{duration} of the media, + the current \l {position()}{position}, and \l {bufferStatus()}{buffering} + progress. + + The functionality provided by this control is exposed to application + code through the QMediaPlayer class. + + The interface name of QMediaPlayerControl is \c com.nokia.Qt.QMediaPlayerControl/1.0 as + defined in QMediaPlayerControl_iid. + + \sa QMediaService::requestControl(), QMediaPlayer +*/ + +/*! + \macro QMediaPlayerControl_iid + + \c com.nokia.Qt.QMediaPlayerControl/1.0 + + Defines the interface name of the QMediaPlayerControl class. + + \relates QMediaPlayerControl +*/ + +/*! + Destroys a media player control. +*/ +QMediaPlayerControl::~QMediaPlayerControl() +{ +} + +/*! + Constructs a new media player control with the given \a parent. +*/ +QMediaPlayerControl::QMediaPlayerControl(QObject *parent): + QMediaControl(*new QMediaControlPrivate, parent) +{ +} + +/*! + \fn QMediaPlayerControl::state() const + + Returns the state of a player control. + \since 1.0 +*/ + +/*! + \fn QMediaPlayerControl::stateChanged(QMediaPlayer::State state) + + Signals that the \a state of a player control has changed. + + \since 1.0 + \sa state() +*/ + +/*! + \fn QMediaPlayerControl::mediaStatus() const + + Returns the status of the current media. + \since 1.0 +*/ + +/*! + \fn QMediaPlayerControl::mediaStatusChanged(QMediaPlayer::MediaStatus status) + + Signals that the \a status of the current media has changed. + + \since 1.0 + \sa mediaStatus() +*/ + + +/*! + \fn QMediaPlayerControl::duration() const + + Returns the duration of the current media in milliseconds. + \since 1.0 +*/ + +/*! + \fn QMediaPlayerControl::durationChanged(qint64 duration) + + Signals that the \a duration of the current media has changed. + + \since 1.0 + \sa duration() +*/ + +/*! + \fn QMediaPlayerControl::position() const + + Returns the current playback position in milliseconds. + \since 1.0 +*/ + +/*! + \fn QMediaPlayerControl::setPosition(qint64 position) + + Sets the playback \a position of the current media. This will initiate a seek and it may take + some time for playback to reach the position set. + \since 1.0 +*/ + +/*! + \fn QMediaPlayerControl::positionChanged(qint64 position) + + Signals the playback \a position has changed. + + This is only emitted in when there has been a discontinous change in the playback postion, such + as a seek or the position being reset. + + \since 1.0 + \sa position() +*/ + +/*! + \fn QMediaPlayerControl::volume() const + + Returns the audio volume of a player control. + \since 1.0 +*/ + +/*! + \fn QMediaPlayerControl::setVolume(int volume) + + Sets the audio \a volume of a player control. + \since 1.0 +*/ + +/*! + \fn QMediaPlayerControl::volumeChanged(int volume) + + Signals the audio \a volume of a player control has changed. + + \since 1.0 + \sa volume() +*/ + +/*! + \fn QMediaPlayerControl::isMuted() const + + Returns the mute state of a player control. + \since 1.0 +*/ + +/*! + \fn QMediaPlayerControl::setMuted(bool mute) + + Sets the \a mute state of a player control. + \since 1.0 +*/ + +/*! + \fn QMediaPlayerControl::mutedChanged(bool mute) + + Signals a change in the \a mute status of a player control. + + \since 1.0 + \sa isMuted() +*/ + +/*! + \fn QMediaPlayerControl::bufferStatus() const + + Returns the buffering progress of the current media. Progress is measured in the percentage + of the buffer filled. + \since 1.0 +*/ + +/*! + \fn QMediaPlayerControl::bufferStatusChanged(int progress) + + Signals that buffering \a progress has changed. + + \since 1.0 + \sa bufferStatus() +*/ + +/*! + \fn QMediaPlayerControl::isAudioAvailable() const + + Identifies if there is audio output available for the current media. + + Returns true if audio output is available and false otherwise. + \since 1.0 +*/ + +/*! + \fn QMediaPlayerControl::audioAvailableChanged(bool audio) + + Signals that there has been a change in the availability of \a audio output. + + \since 1.0 + \sa isAudioAvailable() +*/ + +/*! + \fn QMediaPlayerControl::isVideoAvailable() const + + Identifies if there is video output available for the current media. + + Returns true if video output is available and false otherwise. + \since 1.0 +*/ + +/*! + \fn QMediaPlayerControl::videoAvailableChanged(bool video) + + Signals that there has been a change in the availability of \a video output. + + \since 1.0 + \sa isVideoAvailable() +*/ + +/*! + \fn QMediaPlayerControl::isSeekable() const + + Identifies if the current media is seekable. + + Returns true if it possible to seek within the current media, and false otherwise. + \since 1.0 +*/ + +/*! + \fn QMediaPlayerControl::seekableChanged(bool seekable) + + Signals that the \a seekable state of a player control has changed. + + \since 1.0 + \sa isSeekable() +*/ + +/*! + \fn QMediaPlayerControl::availablePlaybackRanges() const + + Returns 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. + \since 1.0 +*/ + +/*! + \fn QMediaPlayerControl::availablePlaybackRangesChanged(const QMediaTimeRange &ranges) + + Signals that the available media playback \a ranges have changed. + + \since 1.0 + \sa QMediaPlayerControl::availablePlaybackRanges() +*/ + +/*! + \fn qreal QMediaPlayerControl::playbackRate() const + + Returns the rate of playback. + \since 1.0 +*/ + +/*! + \fn QMediaPlayerControl::setPlaybackRate(qreal rate) + + Sets the \a rate of playback. + \since 1.0 +*/ + +/*! + \fn QMediaPlayerControl::media() const + + Returns the current media source. + \since 1.0 +*/ + +/*! + \fn QMediaPlayerControl::mediaStream() const + + Returns the current media stream. This is only a valid if a stream was passed to setMedia(). + + \since 1.0 + \sa setMedia() +*/ + +/*! + \fn QMediaPlayerControl::setMedia(const QMediaContent &media, QIODevice *stream) + + Sets the current \a 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. + \since 1.0 +*/ + +/*! + \fn QMediaPlayerControl::mediaChanged(const QMediaContent& content) + + Signals that the current media \a content has changed. + \since 1.0 +*/ + +/*! + \fn QMediaPlayerControl::play() + + Starts playback of the current media. + + If successful the player control will immediately enter the \l {QMediaPlayer::PlayingState} + {playing} state. + + \since 1.0 + \sa state() +*/ + +/*! + \fn QMediaPlayerControl::pause() + + Pauses playback of the current media. + + If sucessful the player control will immediately enter the \l {QMediaPlayer::PausedState} + {paused} state. + + \since 1.0 + \sa state(), play(), stop() +*/ + +/*! + \fn QMediaPlayerControl::stop() + + Stops playback of the current media. + + If successful the player control will immediately enter the \l {QMediaPlayer::StoppedState} + {stopped} state. + \since 1.0 +*/ + +/*! + \fn QMediaPlayerControl::error(int error, const QString &errorString) + + Signals that an \a error has occurred. The \a errorString provides a more detailed explanation. + \since 1.0 +*/ + +/*! + \fn QMediaPlayerControl::playbackRateChanged(qreal rate) + + Signal emitted when playback rate changes to \a rate. + \since 1.0 +*/ + +#include "moc_qmediaplayercontrol.cpp" +QT_END_NAMESPACE + diff --git a/src/multimedia/qmediaplayercontrol.h b/src/multimedia/qmediaplayercontrol.h new file mode 100644 index 000000000..a6e02ee9a --- /dev/null +++ b/src/multimedia/qmediaplayercontrol.h @@ -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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMEDIAPLAYERCONTROL_H +#define QMEDIAPLAYERCONTROL_H + +#include "qmediacontrol.h" +#include "qmediaplayer.h" +#include "qmediatimerange.h" + +#include <QtCore/qpair.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + +class QMediaPlaylist; + +class Q_MULTIMEDIA_EXPORT QMediaPlayerControl : public QMediaControl +{ + Q_OBJECT + +public: + ~QMediaPlayerControl(); + + virtual QMediaPlayer::State state() const = 0; + + virtual QMediaPlayer::MediaStatus mediaStatus() const = 0; + + virtual qint64 duration() const = 0; + + virtual qint64 position() const = 0; + virtual void setPosition(qint64 position) = 0; + + virtual int volume() const = 0; + virtual void setVolume(int volume) = 0; + + virtual bool isMuted() const = 0; + virtual void setMuted(bool muted) = 0; + + virtual int bufferStatus() const = 0; + + virtual bool isAudioAvailable() const = 0; + virtual bool isVideoAvailable() const = 0; + + virtual bool isSeekable() const = 0; + + virtual QMediaTimeRange availablePlaybackRanges() const = 0; + + virtual qreal playbackRate() const = 0; + virtual void setPlaybackRate(qreal rate) = 0; + + virtual QMediaContent media() const = 0; + virtual const QIODevice *mediaStream() const = 0; + virtual void setMedia(const QMediaContent &media, QIODevice *stream) = 0; + + virtual void play() = 0; + virtual void pause() = 0; + virtual void stop() = 0; + +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 playbackRateChanged(qreal rate); + void error(int error, const QString &errorString); + +protected: + QMediaPlayerControl(QObject* parent = 0); +}; + +#define QMediaPlayerControl_iid "com.nokia.Qt.QMediaPlayerControl/1.0" +Q_MEDIA_DECLARE_CONTROL(QMediaPlayerControl, QMediaPlayerControl_iid) + +QT_END_NAMESPACE + +QT_END_HEADER + + +#endif // QMEDIAPLAYERCONTROL_H + diff --git a/src/multimedia/qmediaplaylist.cpp b/src/multimedia/qmediaplaylist.cpp new file mode 100644 index 000000000..a5618ad5c --- /dev/null +++ b/src/multimedia/qmediaplaylist.cpp @@ -0,0 +1,756 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmediaplaylist.h" +#include "qmediaplaylist_p.h" +#include "qmediaplaylistprovider.h" +#include "qlocalmediaplaylistprovider.h" +#include "qmediaplaylistioplugin.h" +#include "qmediaservice.h" +#include "qmediaplaylistcontrol.h" +#include "qmediaplayercontrol.h" + +#include <QtCore/qlist.h> +#include <QtCore/qfile.h> +#include <QtCore/qurl.h> +#include <QtCore/qcoreevent.h> +#include <QtCore/qcoreapplication.h> + +#include "qmediapluginloader_p.h" + +QT_BEGIN_NAMESPACE + +Q_GLOBAL_STATIC_WITH_ARGS(QMediaPluginLoader, playlistIOLoader, + (QMediaPlaylistIOInterface_iid, QLatin1String("playlistformats"), Qt::CaseInsensitive)) + + +/*! + \class QMediaPlaylist + \inmodule QtMultimedia + \ingroup multimedia + \since 1.0 + + + \brief The QMediaPlaylist class provides a list of media content to play. + + QMediaPlaylist is intended to be used with other media objects, + like QMediaPlayer or QMediaImageViewer. + + QMediaPlaylist allows to access the service intrinsic playlist functionality + if available, otherwise it provides the the local memory playlist implementation. + + \snippet doc/src/snippets/multimedia-snippets/media.cpp Movie playlist + + Depending on playlist source implementation, most of the playlist mutating + operations can be asynchronous. + + \sa QMediaContent +*/ + + +/*! + \enum QMediaPlaylist::PlaybackMode + + The QMediaPlaylist::PlaybackMode describes the order items in playlist are played. + + \value CurrentItemOnce The current item is played only once. + + \value CurrentItemInLoop The current item is played repeatedly in a loop. + + \value Sequential Playback starts from the current and moves through each successive item until the last is reached and then stops. + The next item is a null item when the last one is currently playing. + + \value Loop Playback restarts at the first item after the last has finished playing. + + \value Random Play items in random order. +*/ + + + +/*! + Create a new playlist object for with the given \a parent. +*/ + +QMediaPlaylist::QMediaPlaylist(QObject *parent) + : QObject(parent) + , d_ptr(new QMediaPlaylistPrivate) +{ + Q_D(QMediaPlaylist); + + d->q_ptr = this; + d->localPlaylistControl = new QLocalMediaPlaylistControl(this); + + setMediaObject(0); +} + +/*! + Destroys the playlist. + */ + +QMediaPlaylist::~QMediaPlaylist() +{ + Q_D(QMediaPlaylist); + + if (d->mediaObject) + d->mediaObject->unbind(this); + + delete d_ptr; +} + +/*! + Returns the QMediaObject instance that this QMediaPlaylist is bound too, + or 0 otherwise. + \since 1.0 +*/ +QMediaObject *QMediaPlaylist::mediaObject() const +{ + return d_func()->mediaObject; +} + +/*! + \internal + If \a mediaObject is null or doesn't have an intrinsic playlist, + internal local memory playlist source will be created. + \since 1.0 +*/ +bool QMediaPlaylist::setMediaObject(QMediaObject *mediaObject) +{ + Q_D(QMediaPlaylist); + + if (mediaObject && mediaObject == d->mediaObject) + return true; + + QMediaService *service = mediaObject + ? mediaObject->service() : 0; + + QMediaPlaylistControl *newControl = 0; + + if (service) + newControl = qobject_cast<QMediaPlaylistControl*>(service->requestControl(QMediaPlaylistControl_iid)); + + if (!newControl) + newControl = d->localPlaylistControl; + + if (d->control != newControl) { + int oldSize = 0; + if (d->control) { + QMediaPlaylistProvider *playlist = d->control->playlistProvider(); + oldSize = playlist->mediaCount(); + disconnect(playlist, SIGNAL(loadFailed(QMediaPlaylist::Error,QString)), + this, SLOT(_q_loadFailed(QMediaPlaylist::Error,QString))); + + disconnect(playlist, SIGNAL(mediaChanged(int,int)), this, SIGNAL(mediaChanged(int,int))); + disconnect(playlist, SIGNAL(mediaAboutToBeInserted(int,int)), this, SIGNAL(mediaAboutToBeInserted(int,int))); + disconnect(playlist, SIGNAL(mediaInserted(int,int)), this, SIGNAL(mediaInserted(int,int))); + disconnect(playlist, SIGNAL(mediaAboutToBeRemoved(int,int)), this, SIGNAL(mediaAboutToBeRemoved(int,int))); + disconnect(playlist, SIGNAL(mediaRemoved(int,int)), this, SIGNAL(mediaRemoved(int,int))); + + disconnect(playlist, SIGNAL(loaded()), this, SIGNAL(loaded())); + + disconnect(d->control, SIGNAL(playbackModeChanged(QMediaPlaylist::PlaybackMode)), + this, SIGNAL(playbackModeChanged(QMediaPlaylist::PlaybackMode))); + disconnect(d->control, SIGNAL(currentIndexChanged(int)), + this, SIGNAL(currentIndexChanged(int))); + disconnect(d->control, SIGNAL(currentMediaChanged(QMediaContent)), + this, SIGNAL(currentMediaChanged(QMediaContent))); + + if (d->mediaObject) + d->mediaObject->service()->releaseControl(d->control); + } + + d->control = newControl; + QMediaPlaylistProvider *playlist = d->control->playlistProvider(); + connect(playlist, SIGNAL(loadFailed(QMediaPlaylist::Error,QString)), + this, SLOT(_q_loadFailed(QMediaPlaylist::Error,QString))); + + connect(playlist, SIGNAL(mediaChanged(int,int)), this, SIGNAL(mediaChanged(int,int))); + connect(playlist, SIGNAL(mediaAboutToBeInserted(int,int)), this, SIGNAL(mediaAboutToBeInserted(int,int))); + connect(playlist, SIGNAL(mediaInserted(int,int)), this, SIGNAL(mediaInserted(int,int))); + connect(playlist, SIGNAL(mediaAboutToBeRemoved(int,int)), this, SIGNAL(mediaAboutToBeRemoved(int,int))); + connect(playlist, SIGNAL(mediaRemoved(int,int)), this, SIGNAL(mediaRemoved(int,int))); + + connect(playlist, SIGNAL(loaded()), this, SIGNAL(loaded())); + + connect(d->control, SIGNAL(playbackModeChanged(QMediaPlaylist::PlaybackMode)), + this, SIGNAL(playbackModeChanged(QMediaPlaylist::PlaybackMode))); + connect(d->control, SIGNAL(currentIndexChanged(int)), + this, SIGNAL(currentIndexChanged(int))); + connect(d->control, SIGNAL(currentMediaChanged(QMediaContent)), + this, SIGNAL(currentMediaChanged(QMediaContent))); + + if (oldSize) + emit mediaRemoved(0, oldSize-1); + + if (playlist->mediaCount()) { + emit mediaAboutToBeInserted(0,playlist->mediaCount()-1); + emit mediaInserted(0,playlist->mediaCount()-1); + } + } + + d->mediaObject = mediaObject; + + return true; +} + +/*! + \property QMediaPlaylist::playbackMode + + This property defines the order, items in playlist are played. + + \since 1.0 + \sa QMediaPlaylist::PlaybackMode +*/ + +QMediaPlaylist::PlaybackMode QMediaPlaylist::playbackMode() const +{ + return d_func()->control->playbackMode(); +} + +void QMediaPlaylist::setPlaybackMode(QMediaPlaylist::PlaybackMode mode) +{ + Q_D(QMediaPlaylist); + d->control->setPlaybackMode(mode); +} + +/*! + Returns position of the current media content in the playlist. + \since 1.0 +*/ +int QMediaPlaylist::currentIndex() const +{ + return d_func()->control->currentIndex(); +} + +/*! + Returns the current media content. + \since 1.0 +*/ + +QMediaContent QMediaPlaylist::currentMedia() const +{ + return d_func()->playlist()->media(currentIndex()); +} + +/*! + Returns the index of the item, which would be current after calling next() + \a steps times. + + Returned value depends on the size of playlist, current position + and playback mode. + + \since 1.0 + \sa QMediaPlaylist::playbackMode +*/ +int QMediaPlaylist::nextIndex(int steps) const +{ + return d_func()->control->nextIndex(steps); +} + +/*! + Returns the index of the item, which would be current after calling previous() + \a steps times. + + \since 1.0 + \sa QMediaPlaylist::playbackMode +*/ + +int QMediaPlaylist::previousIndex(int steps) const +{ + return d_func()->control->previousIndex(steps); +} + + +/*! + Returns the number of items in the playlist. + + \since 1.0 + \sa isEmpty() + */ +int QMediaPlaylist::mediaCount() const +{ + return d_func()->playlist()->mediaCount(); +} + +/*! + Returns true if the playlist contains no items; otherwise returns false. + + \since 1.0 + \sa mediaCount() + */ +bool QMediaPlaylist::isEmpty() const +{ + return mediaCount() == 0; +} + +/*! + Returns true if the playlist can be modified; otherwise returns false. + + \since 1.0 + \sa mediaCount() + */ +bool QMediaPlaylist::isReadOnly() const +{ + return d_func()->playlist()->isReadOnly(); +} + +/*! + Returns the media content at \a index in the playlist. + \since 1.0 +*/ + +QMediaContent QMediaPlaylist::media(int index) const +{ + return d_func()->playlist()->media(index); +} + +/*! + Append the media \a content to the playlist. + + Returns true if the operation is successful, otherwise return false. + \since 1.0 + */ +bool QMediaPlaylist::addMedia(const QMediaContent &content) +{ + return d_func()->control->playlistProvider()->addMedia(content); +} + +/*! + Append multiple media content \a items to the playlist. + + Returns true if the operation is successful, otherwise return false. + \since 1.0 + */ +bool QMediaPlaylist::addMedia(const QList<QMediaContent> &items) +{ + return d_func()->control->playlistProvider()->addMedia(items); +} + +/*! + Insert the media \a content to the playlist at position \a pos. + + Returns true if the operation is successful, otherwise false. + \since 1.0 +*/ + +bool QMediaPlaylist::insertMedia(int pos, const QMediaContent &content) +{ + return d_func()->playlist()->insertMedia(pos, content); +} + +/*! + Insert multiple media content \a items to the playlist at position \a pos. + + Returns true if the operation is successful, otherwise false. + \since 1.0 +*/ + +bool QMediaPlaylist::insertMedia(int pos, const QList<QMediaContent> &items) +{ + return d_func()->playlist()->insertMedia(pos, items); +} + +/*! + Remove the item from the playlist at position \a pos. + + Returns true if the operation is successful, otherwise return false. + \since 1.0 + */ +bool QMediaPlaylist::removeMedia(int pos) +{ + Q_D(QMediaPlaylist); + return d->playlist()->removeMedia(pos); +} + +/*! + Remove items in the playlist from \a start to \a end inclusive. + + Returns true if the operation is successful, otherwise return false. + \since 1.0 + */ +bool QMediaPlaylist::removeMedia(int start, int end) +{ + Q_D(QMediaPlaylist); + return d->playlist()->removeMedia(start, end); +} + +/*! + Remove all the items from the playlist. + + Returns true if the operation is successful, otherwise return false. + \since 1.0 + */ +bool QMediaPlaylist::clear() +{ + Q_D(QMediaPlaylist); + return d->playlist()->clear(); +} + +bool QMediaPlaylistPrivate::readItems(QMediaPlaylistReader *reader) +{ + while (!reader->atEnd()) + playlist()->addMedia(reader->readItem()); + + return true; +} + +bool QMediaPlaylistPrivate::writeItems(QMediaPlaylistWriter *writer) +{ + for (int i=0; i<playlist()->mediaCount(); i++) { + if (!writer->writeItem(playlist()->media(i))) + return false; + } + writer->close(); + return true; +} + +/*! + Load playlist from \a location. If \a format is specified, it is used, + otherwise format is guessed from location name and data. + + New items are appended to playlist. + + QMediaPlaylist::loaded() signal is emitted if playlist was loaded successfully, + otherwise the playlist emits loadFailed(). + \since 1.0 +*/ +void QMediaPlaylist::load(const QUrl &location, const char *format) +{ + Q_D(QMediaPlaylist); + + d->error = NoError; + d->errorString.clear(); + + if (d->playlist()->load(location,format)) + return; + + if (isReadOnly()) { + d->error = AccessDeniedError; + d->errorString = tr("Could not add items to read only playlist."); + emit loadFailed(); + return; + } + + foreach (QString const& key, playlistIOLoader()->keys()) { + QMediaPlaylistIOInterface* plugin = qobject_cast<QMediaPlaylistIOInterface*>(playlistIOLoader()->instance(key)); + if (plugin && plugin->canRead(location,format)) { + QMediaPlaylistReader *reader = plugin->createReader(location,QByteArray(format)); + if (reader && d->readItems(reader)) { + delete reader; + emit loaded(); + return; + } + delete reader; + } + } + + d->error = FormatNotSupportedError; + d->errorString = tr("Playlist format is not supported"); + emit loadFailed(); + + return; +} + +/*! + Load playlist from QIODevice \a device. If \a format is specified, it is used, + otherwise format is guessed from device data. + + New items are appended to playlist. + + QMediaPlaylist::loaded() signal is emitted if playlist was loaded successfully, + otherwise the playlist emits loadFailed(). + \since 1.0 +*/ +void QMediaPlaylist::load(QIODevice * device, const char *format) +{ + Q_D(QMediaPlaylist); + + d->error = NoError; + d->errorString.clear(); + + if (d->playlist()->load(device,format)) + return; + + if (isReadOnly()) { + d->error = AccessDeniedError; + d->errorString = tr("Could not add items to read only playlist."); + emit loadFailed(); + return; + } + + foreach (QString const& key, playlistIOLoader()->keys()) { + QMediaPlaylistIOInterface* plugin = qobject_cast<QMediaPlaylistIOInterface*>(playlistIOLoader()->instance(key)); + if (plugin && plugin->canRead(device,format)) { + QMediaPlaylistReader *reader = plugin->createReader(device,QByteArray(format)); + if (reader && d->readItems(reader)) { + delete reader; + emit loaded(); + return; + } + delete reader; + } + } + + d->error = FormatNotSupportedError; + d->errorString = tr("Playlist format is not supported"); + emit loadFailed(); + + return; +} + +/*! + Save playlist to \a location. If \a format is specified, it is used, + otherwise format is guessed from location name. + + Returns true if playlist was saved successfully, otherwise returns false. + \since 1.0 + */ +bool QMediaPlaylist::save(const QUrl &location, const char *format) +{ + Q_D(QMediaPlaylist); + + d->error = NoError; + d->errorString.clear(); + + if (d->playlist()->save(location,format)) + return true; + + QFile file(location.toLocalFile()); + + if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate)) { + d->error = AccessDeniedError; + d->errorString = tr("The file could not be accessed."); + return false; + } + + return save(&file, format); +} + +/*! + Save playlist to QIODevice \a device using format \a format. + + Returns true if playlist was saved successfully, otherwise returns false. + \since 1.0 +*/ +bool QMediaPlaylist::save(QIODevice * device, const char *format) +{ + Q_D(QMediaPlaylist); + + d->error = NoError; + d->errorString.clear(); + + if (d->playlist()->save(device,format)) + return true; + + foreach (QString const& key, playlistIOLoader()->keys()) { + QMediaPlaylistIOInterface* plugin = qobject_cast<QMediaPlaylistIOInterface*>(playlistIOLoader()->instance(key)); + if (plugin && plugin->canWrite(device,format)) { + QMediaPlaylistWriter *writer = plugin->createWriter(device,QByteArray(format)); + if (writer && d->writeItems(writer)) { + delete writer; + return true; + } + delete writer; + } + } + + d->error = FormatNotSupportedError; + d->errorString = tr("Playlist format is not supported."); + + return false; +} + +/*! + Returns the last error condition. + \since 1.0 +*/ +QMediaPlaylist::Error QMediaPlaylist::error() const +{ + return d_func()->error; +} + +/*! + Returns the string describing the last error condition. + \since 1.0 +*/ +QString QMediaPlaylist::errorString() const +{ + return d_func()->errorString; +} + +/*! + Shuffle items in the playlist. + \since 1.0 +*/ +void QMediaPlaylist::shuffle() +{ + d_func()->playlist()->shuffle(); +} + + +/*! + Advance to the next media content in playlist. + \since 1.0 +*/ +void QMediaPlaylist::next() +{ + d_func()->control->next(); +} + +/*! + Return to the previous media content in playlist. + \since 1.0 +*/ +void QMediaPlaylist::previous() +{ + d_func()->control->previous(); +} + +/*! + Activate media content from playlist at position \a playlistPosition. + \since 1.0 +*/ + +void QMediaPlaylist::setCurrentIndex(int playlistPosition) +{ + d_func()->control->setCurrentIndex(playlistPosition); +} + +/*! + \fn void QMediaPlaylist::mediaInserted(int start, int end) + + This signal is emitted after media has been inserted into the playlist. + The new items are those between \a start and \a end inclusive. + \since 1.0 + */ + +/*! + \fn void QMediaPlaylist::mediaRemoved(int start, int end) + + This signal is emitted after media has been removed from the playlist. + The removed items are those between \a start and \a end inclusive. + \since 1.0 + */ + +/*! + \fn void QMediaPlaylist::mediaChanged(int start, int end) + + This signal is emitted after media has been changed in the playlist + between \a start and \a end positions inclusive. + \since 1.0 + */ + +/*! + \fn void QMediaPlaylist::currentIndexChanged(int position) + + Signal emitted when playlist position changed to \a position. + \since 1.0 +*/ + +/*! + \fn void QMediaPlaylist::playbackModeChanged(QMediaPlaylist::PlaybackMode mode) + + Signal emitted when playback mode changed to \a mode. + \since 1.0 +*/ + +/*! + \fn void QMediaPlaylist::mediaAboutToBeInserted(int start, int end) + + Signal emitted when items are to be inserted at \a start and ending at \a end. + \since 1.0 +*/ + +/*! + \fn void QMediaPlaylist::mediaAboutToBeRemoved(int start, int end) + + Signal emitted when item are to be deleted at \a start and ending at \a end. + \since 1.0 +*/ + +/*! + \fn void QMediaPlaylist::currentMediaChanged(const QMediaContent &content) + + Signal emitted when current media changes to \a content. + \since 1.0 +*/ + +/*! + \property QMediaPlaylist::currentIndex + \brief Current position. + \since 1.0 +*/ + +/*! + \property QMediaPlaylist::currentMedia + \brief Current media content. + \since 1.0 +*/ + +/*! + \fn QMediaPlaylist::loaded() + + Signal emitted when playlist finished loading. + \since 1.0 +*/ + +/*! + \fn QMediaPlaylist::loadFailed() + + Signal emitted if failed to load playlist. + \since 1.0 +*/ + +/*! + \enum QMediaPlaylist::Error + + This enum describes the QMediaPlaylist error codes. + + \value NoError No errors. + \value FormatError Format error. + \value FormatNotSupportedError Format not supported. + \value NetworkError Network error. + \value AccessDeniedError Access denied error. +*/ + +#include "moc_qmediaplaylist.cpp" +#include "moc_qmediaplaylist_p.cpp" +QT_END_NAMESPACE + diff --git a/src/multimedia/qmediaplaylist.h b/src/multimedia/qmediaplaylist.h new file mode 100644 index 000000000..7b4b62260 --- /dev/null +++ b/src/multimedia/qmediaplaylist.h @@ -0,0 +1,154 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMEDIAPLAYLIST_H +#define QMEDIAPLAYLIST_H + +#include <QtCore/qobject.h> + +#include <qmediacontent.h> +#include <qmediaobject.h> +#include <qmediabindableinterface.h> +#include <qmediaenumdebug.h> + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + +class QMediaPlaylistProvider; + +class QMediaPlaylistPrivate; +class Q_MULTIMEDIA_EXPORT QMediaPlaylist : public QObject, public QMediaBindableInterface +{ + Q_OBJECT + Q_INTERFACES(QMediaBindableInterface) + Q_PROPERTY(QMediaPlaylist::PlaybackMode playbackMode READ playbackMode WRITE setPlaybackMode NOTIFY playbackModeChanged) + Q_PROPERTY(QMediaContent currentMedia READ currentMedia NOTIFY currentMediaChanged) + Q_PROPERTY(int currentIndex READ currentIndex WRITE setCurrentIndex NOTIFY currentIndexChanged) + Q_ENUMS(PlaybackMode Error) + +public: + enum PlaybackMode { CurrentItemOnce, CurrentItemInLoop, Sequential, Loop, Random }; + enum Error { NoError, FormatError, FormatNotSupportedError, NetworkError, AccessDeniedError }; + + QMediaPlaylist(QObject *parent = 0); + virtual ~QMediaPlaylist(); + + QMediaObject *mediaObject() const; + + PlaybackMode playbackMode() const; + void setPlaybackMode(PlaybackMode mode); + + int currentIndex() const; + QMediaContent currentMedia() const; + + int nextIndex(int steps = 1) const; + int previousIndex(int steps = 1) const; + + QMediaContent media(int index) const; + + int mediaCount() const; + bool isEmpty() const; + bool isReadOnly() const; + + bool addMedia(const QMediaContent &content); + bool addMedia(const QList<QMediaContent> &items); + bool insertMedia(int index, const QMediaContent &content); + bool insertMedia(int index, const QList<QMediaContent> &items); + bool removeMedia(int pos); + bool removeMedia(int start, int end); + bool clear(); + + void load(const QUrl &location, const char *format = 0); + void load(QIODevice * device, const char *format = 0); + + bool save(const QUrl &location, const char *format = 0); + bool save(QIODevice * device, const char *format); + + Error error() const; + QString errorString() const; + +public Q_SLOTS: + void shuffle(); + + void next(); + void previous(); + + void setCurrentIndex(int index); + +Q_SIGNALS: + void currentIndexChanged(int index); + void playbackModeChanged(QMediaPlaylist::PlaybackMode mode); + void currentMediaChanged(const QMediaContent&); + + void mediaAboutToBeInserted(int start, int end); + void mediaInserted(int start, int end); + void mediaAboutToBeRemoved(int start, int end); + void mediaRemoved(int start, int end); + void mediaChanged(int start, int end); + + void loaded(); + void loadFailed(); + +protected: + bool setMediaObject(QMediaObject *object); + QMediaPlaylistPrivate *d_ptr; + +private: + Q_DECLARE_PRIVATE(QMediaPlaylist) + Q_PRIVATE_SLOT(d_func(), void _q_loadFailed(QMediaPlaylist::Error, const QString &)) +}; + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(QMediaPlaylist::PlaybackMode) +Q_DECLARE_METATYPE(QMediaPlaylist::Error) + +Q_MEDIA_ENUM_DEBUG(QMediaPlaylist, PlaybackMode) +Q_MEDIA_ENUM_DEBUG(QMediaPlaylist, Error) + +QT_END_HEADER + +#endif // QMEDIAPLAYLIST_H diff --git a/src/multimedia/qmediaplaylist_p.h b/src/multimedia/qmediaplaylist_p.h new file mode 100644 index 000000000..c04483c02 --- /dev/null +++ b/src/multimedia/qmediaplaylist_p.h @@ -0,0 +1,177 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMEDIAPLAYLIST_P_H +#define QMEDIAPLAYLIST_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qmediaplaylist.h" +#include "qmediaplaylistcontrol.h" +#include "qmediaplayer.h" +#include "qmediaplayercontrol.h" +#include "qlocalmediaplaylistprovider.h" +#include "qmediaobject_p.h" + +#include <QtCore/qdebug.h> + +#ifdef Q_MOC_RUN +# pragma Q_MOC_EXPAND_MACROS +#endif + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + +class QMediaPlaylistControl; +class QMediaPlaylistProvider; +class QMediaPlaylistReader; +class QMediaPlaylistWriter; +class QMediaPlayerControl; + +class QMediaPlaylistPrivate +{ + Q_DECLARE_PUBLIC(QMediaPlaylist) +public: + QMediaPlaylistPrivate() + :mediaObject(0), + control(0), + localPlaylistControl(0), + error(QMediaPlaylist::NoError) + { + } + + virtual ~QMediaPlaylistPrivate() {} + + void _q_loadFailed(QMediaPlaylist::Error error, const QString &errorString) + { + this->error = error; + this->errorString = errorString; + + emit q_ptr->loadFailed(); + } + + void _q_mediaObjectDeleted() + { + Q_Q(QMediaPlaylist); + mediaObject = 0; + if (control != localPlaylistControl) + control = 0; + q->setMediaObject(0); + } + + QMediaObject *mediaObject; + + QMediaPlaylistControl *control; + QMediaPlaylistProvider *playlist() const { return control->playlistProvider(); } + + QMediaPlaylistControl *localPlaylistControl; + + bool readItems(QMediaPlaylistReader *reader); + bool writeItems(QMediaPlaylistWriter *writer); + + QMediaPlaylist::Error error; + QString errorString; + + QMediaPlaylist *q_ptr; +}; + + +class QLocalMediaPlaylistControl : public QMediaPlaylistControl +{ + Q_OBJECT +public: + QLocalMediaPlaylistControl(QObject *parent) + :QMediaPlaylistControl(parent) + { + QMediaPlaylistProvider *playlist = new QLocalMediaPlaylistProvider(this); + m_navigator = new QMediaPlaylistNavigator(playlist,this); + m_navigator->setPlaybackMode(QMediaPlaylist::Sequential); + + connect(m_navigator, SIGNAL(currentIndexChanged(int)), SIGNAL(currentIndexChanged(int))); + connect(m_navigator, SIGNAL(activated(QMediaContent)), SIGNAL(currentMediaChanged(QMediaContent))); + connect(m_navigator, SIGNAL(playbackModeChanged(QMediaPlaylist::PlaybackMode)), SIGNAL(playbackModeChanged(QMediaPlaylist::PlaybackMode))); + } + + virtual ~QLocalMediaPlaylistControl() {}; + + QMediaPlaylistProvider* playlistProvider() const { return m_navigator->playlist(); } + bool setPlaylistProvider(QMediaPlaylistProvider *mediaPlaylist) + { + m_navigator->setPlaylist(mediaPlaylist); + emit playlistProviderChanged(); + return true; + } + + int currentIndex() const { return m_navigator->currentIndex(); } + void setCurrentIndex(int position) { m_navigator->jump(position); } + int nextIndex(int steps) const { return m_navigator->nextIndex(steps); } + int previousIndex(int steps) const { return m_navigator->previousIndex(steps); } + + void next() { m_navigator->next(); } + void previous() { m_navigator->previous(); } + + QMediaPlaylist::PlaybackMode playbackMode() const { return m_navigator->playbackMode(); } + void setPlaybackMode(QMediaPlaylist::PlaybackMode mode) { m_navigator->setPlaybackMode(mode); } + +private: + QMediaPlaylistNavigator *m_navigator; +}; + + +QT_END_NAMESPACE + +QT_END_HEADER + + +#endif // QMEDIAPLAYLIST_P_H diff --git a/src/multimedia/qmediaplaylistcontrol.cpp b/src/multimedia/qmediaplaylistcontrol.cpp new file mode 100644 index 000000000..dc2348956 --- /dev/null +++ b/src/multimedia/qmediaplaylistcontrol.cpp @@ -0,0 +1,219 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include "qmediaplaylistcontrol.h" +#include "qmediacontrol_p.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QMediaPlaylistControl + \inmodule QtMultimedia + \ingroup multimedia-serv + \since 1.0 + + + \brief The QMediaPlaylistControl class provides access to the playlist + functionality of a QMediaService. + + If a QMediaService contains an internal playlist it will implement + QMediaPlaylistControl. This control provides access to the contents of the + \l {playlistProvider()}{playlist}, as well as the \l + {currentIndex()}{position} of the current media, and a means of navigating + to the \l {next()}{next} and \l {previous()}{previous} media. + + The functionality provided by the control is exposed to application code + through the QMediaPlaylist class. + + The interface name of QMediaPlaylistControl is \c com.nokia.Qt.QMediaPlaylistControl/1.0 as + defined in QMediaPlaylistControl_iid. + + \sa QMediaService::requestControl(), QMediaPlayer +*/ + +/*! + \macro QMediaPlaylistControl_iid + + \c com.nokia.Qt.QMediaPlaylistControl/1.0 + + Defines the interface name of the QMediaPlaylistControl class. + + \relates QMediaPlaylistControl +*/ + +/*! + Create a new playlist control object with the given \a parent. +*/ +QMediaPlaylistControl::QMediaPlaylistControl(QObject *parent): + QMediaControl(*new QMediaControlPrivate, parent) +{ +} + +/*! + Destroys the playlist control. +*/ +QMediaPlaylistControl::~QMediaPlaylistControl() +{ +} + + +/*! + \fn QMediaPlaylistControl::playlistProvider() const + + Returns the playlist used by this media player. + \since 1.0 +*/ + +/*! + \fn QMediaPlaylistControl::setPlaylistProvider(QMediaPlaylistProvider *playlist) + + Set the playlist of this media player to \a playlist. + + In many cases it is possible just to use the playlist + constructed by player, but sometimes replacing the whole + playlist allows to avoid copyting of all the items bettween playlists. + + Returns true if player can use this passed playlist; otherwise returns false. + + \since 1.0 +*/ + +/*! + \fn QMediaPlaylistControl::currentIndex() const + + Returns position of the current media source in the playlist. + \since 1.0 +*/ + +/*! + \fn QMediaPlaylistControl::setCurrentIndex(int position) + + Jump to the item at the given \a position. + \since 1.0 +*/ + +/*! + \fn QMediaPlaylistControl::nextIndex(int step) const + + Returns the index of item, which were current after calling next() + \a step times. + + Returned value depends on the size of playlist, current position + and playback mode. + + \since 1.0 + \sa QMediaPlaylist::playbackMode +*/ + +/*! + \fn QMediaPlaylistControl::previousIndex(int step) const + + Returns the index of item, which were current after calling previous() + \a step times. + + \since 1.0 + \sa QMediaPlaylist::playbackMode +*/ + +/*! + \fn QMediaPlaylistControl::next() + + Moves to the next item in playlist. + \since 1.0 +*/ + +/*! + \fn QMediaPlaylistControl::previous() + + Returns to the previous item in playlist. + \since 1.0 +*/ + +/*! + \fn QMediaPlaylistControl::playbackMode() const + + Returns the playlist navigation mode. + + \since 1.0 + \sa QMediaPlaylist::PlaybackMode +*/ + +/*! + \fn QMediaPlaylistControl::setPlaybackMode(QMediaPlaylist::PlaybackMode mode) + + Sets the playback \a mode. + + \since 1.0 + \sa QMediaPlaylist::PlaybackMode +*/ + +/*! + \fn QMediaPlaylistControl::playlistProviderChanged() + + Signal emitted when the playlist provider has changed. + \since 1.0 +*/ + +/*! + \fn QMediaPlaylistControl::currentIndexChanged(int position) + + Signal emitted when the playlist \a position is changed. + \since 1.0 +*/ + +/*! + \fn QMediaPlaylistControl::playbackModeChanged(QMediaPlaylist::PlaybackMode mode) + + Signal emitted when the playback \a mode is changed. + \since 1.0 +*/ + +/*! + \fn QMediaPlaylistControl::currentMediaChanged(const QMediaContent& content) + + Signal emitted when current media changes to \a content. + \since 1.0 +*/ + +#include "moc_qmediaplaylistcontrol.cpp" +QT_END_NAMESPACE + diff --git a/src/multimedia/qmediaplaylistcontrol.h b/src/multimedia/qmediaplaylistcontrol.h new file mode 100644 index 000000000..2cce448fa --- /dev/null +++ b/src/multimedia/qmediaplaylistcontrol.h @@ -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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#ifndef QMEDIAPLAYLISTCONTROL_H +#define QMEDIAPLAYLISTCONTROL_H + +#include "qmediacontrol.h" +#include "qmediaplaylistnavigator.h" + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + +class QMediaPlaylistProvider; + +class Q_MULTIMEDIA_EXPORT QMediaPlaylistControl : public QMediaControl +{ + Q_OBJECT + +public: + virtual ~QMediaPlaylistControl(); + + virtual QMediaPlaylistProvider* playlistProvider() const = 0; + virtual bool setPlaylistProvider(QMediaPlaylistProvider *playlist) = 0; + + virtual int currentIndex() const = 0; + virtual void setCurrentIndex(int position) = 0; + virtual int nextIndex(int steps) const = 0; + virtual int previousIndex(int steps) const = 0; + + virtual void next() = 0; + virtual void previous() = 0; + + virtual QMediaPlaylist::PlaybackMode playbackMode() const = 0; + virtual void setPlaybackMode(QMediaPlaylist::PlaybackMode mode) = 0; + +Q_SIGNALS: + void playlistProviderChanged(); + void currentIndexChanged(int position); + void currentMediaChanged(const QMediaContent&); + void playbackModeChanged(QMediaPlaylist::PlaybackMode mode); + +protected: + QMediaPlaylistControl(QObject* parent = 0); +}; + +#define QMediaPlaylistControl_iid "com.nokia.Qt.QMediaPlaylistControl/1.0" +Q_MEDIA_DECLARE_CONTROL(QMediaPlaylistControl, QMediaPlaylistControl_iid) + +QT_END_NAMESPACE + +QT_END_HEADER + + +#endif // QMEDIAPLAYLISTCONTROL_H diff --git a/src/multimedia/qmediaplaylistioplugin.cpp b/src/multimedia/qmediaplaylistioplugin.cpp new file mode 100644 index 000000000..80fe0ef6b --- /dev/null +++ b/src/multimedia/qmediaplaylistioplugin.cpp @@ -0,0 +1,204 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmediaplaylistioplugin.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QMediaPlaylistReader + + \brief The QMediaPlaylistReader class provides an interface for reading a playlist file. + \inmodule QtMultimedia + \since 1.0 + + \sa QMediaPlaylistIOPlugin +*/ + +/*! + Destroys a media playlist reader. +*/ +QMediaPlaylistReader::~QMediaPlaylistReader() +{ +} + +/*! + \fn QMediaPlaylistReader::atEnd() const + + Identifies if a playlist reader has reached the end of its input. + + Returns true if the reader has reached the end; and false otherwise. + \since 1.0 +*/ + +/*! + \fn QMediaPlaylistReader::readItem() + + Reads an item of media from a playlist file. + + Returns the read media, or a null QMediaContent if no more media is available. + \since 1.0 +*/ + +/*! + \fn QMediaPlaylistReader::close() + + Closes a playlist reader's input device. + \since 1.0 +*/ + +/*! + \class QMediaPlaylistWriter + + \brief The QMediaPlaylistWriter class provides an interface for writing a playlist file. + + \since 1.0 + \sa QMediaPlaylistIOPlugin +*/ + +/*! + Destroys a media playlist writer. +*/ +QMediaPlaylistWriter::~QMediaPlaylistWriter() +{ +} + +/*! + \fn QMediaPlaylistWriter::writeItem(const QMediaContent &media) + + Writes an item of \a media to a playlist file. + + Returns true if the media was written successfully; and false otherwise. + \since 1.0 +*/ + +/*! + \fn QMediaPlaylistWriter::close() + + Finalizes the writing of a playlist and closes the output device. + \since 1.0 +*/ + +/*! + \class QMediaPlaylistIOPlugin + \brief The QMediaPlaylistIOPlugin class provides an interface for media playlist I/O plug-ins. + \since 1.0 +*/ + +/*! + Constructs a media playlist I/O plug-in with the given \a parent. +*/ +QMediaPlaylistIOPlugin::QMediaPlaylistIOPlugin(QObject *parent) + :QObject(parent) +{ +} + +/*! + Destroys a media playlist I/O plug-in. +*/ +QMediaPlaylistIOPlugin::~QMediaPlaylistIOPlugin() +{ +} + +/*! + \fn QMediaPlaylistIOPlugin::canRead(QIODevice *device, const QByteArray &format) const + + Identifies if plug-in can read \a format data from an I/O \a device. + + Returns true if the data can be read; and false otherwise. + \since 1.0 +*/ + +/*! + \fn QMediaPlaylistIOPlugin::canRead(const QUrl& location, const QByteArray &format) const + + Identifies if a plug-in can read \a format data from a URL \a location. + + Returns true if the data can be read; and false otherwise. + \since 1.0 +*/ + +/*! + \fn QMediaPlaylistIOPlugin::canWrite(QIODevice *device, const QByteArray &format) const + + Identifies if a plug-in can write \a format data to an I/O \a device. + + Returns true if the data can be written; and false otherwise. + \since 1.0 +*/ + +/*! + \fn QMediaPlaylistIOPlugin::keys() const + + Returns a list of format keys supported by a plug-in. + \since 1.0 +*/ + +/*! + \fn QMediaPlaylistIOPlugin::createReader(QIODevice *device, const QByteArray &format) + + Returns a new QMediaPlaylistReader which reads \a format data from an I/O \a device. + + If the device is invalid or the format is unsupported this will return a null pointer. + \since 1.0 +*/ + +/*! + \fn QMediaPlaylistIOPlugin::createReader(const QUrl& location, const QByteArray &format) + + Returns a new QMediaPlaylistReader which reads \a format data from a URL \a location. + + If the location or the format is unsupported this will return a null pointer. + \since 1.0 +*/ + +/*! + \fn QMediaPlaylistIOPlugin::createWriter(QIODevice *device, const QByteArray &format) + + Returns a new QMediaPlaylistWriter which writes \a format data to an I/O \a device. + + If the device is invalid or the format is unsupported this will return a null pointer. + \since 1.0 +*/ + +#include "moc_qmediaplaylistioplugin.cpp" +QT_END_NAMESPACE + diff --git a/src/multimedia/qmediaplaylistioplugin.h b/src/multimedia/qmediaplaylistioplugin.h new file mode 100644 index 000000000..97ded8b43 --- /dev/null +++ b/src/multimedia/qmediaplaylistioplugin.h @@ -0,0 +1,126 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMEDIAPLAYLISTIOPLUGIN_H +#define QMEDIAPLAYLISTIOPLUGIN_H + +#include <QtCore/qobject.h> +#include <QtCore/qplugin.h> +#include <QtCore/qfactoryinterface.h> + +#include <qtmultimediadefs.h> + +#include "qmediacontent.h" + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + +class QString; +class QUrl; +class QByteArray; +class QIODevice; +class QStringList; + +class Q_MULTIMEDIA_EXPORT QMediaPlaylistReader +{ +public: + virtual ~QMediaPlaylistReader(); + + virtual bool atEnd() const = 0; + virtual QMediaContent readItem() = 0; + virtual void close() = 0; +}; + +class Q_MULTIMEDIA_EXPORT QMediaPlaylistWriter +{ +public: + virtual ~QMediaPlaylistWriter(); + + virtual bool writeItem(const QMediaContent &content) = 0; + virtual void close() = 0; +}; + +struct Q_MULTIMEDIA_EXPORT QMediaPlaylistIOInterface : public QFactoryInterface +{ + virtual bool canRead(QIODevice *device, const QByteArray &format = QByteArray() ) const = 0; + virtual bool canRead(const QUrl& location, const QByteArray &format = QByteArray()) const = 0; + + virtual bool canWrite(QIODevice *device, const QByteArray &format) const = 0; + + virtual QMediaPlaylistReader *createReader(QIODevice *device, const QByteArray &format = QByteArray()) = 0; + virtual QMediaPlaylistReader *createReader(const QUrl& location, const QByteArray &format = QByteArray()) = 0; + + virtual QMediaPlaylistWriter *createWriter(QIODevice *device, const QByteArray &format) = 0; +}; + +#define QMediaPlaylistIOInterface_iid "com.nokia.Qt.QMediaPlaylistIOInterface" +Q_DECLARE_INTERFACE(QMediaPlaylistIOInterface, QMediaPlaylistIOInterface_iid); + +class Q_MULTIMEDIA_EXPORT QMediaPlaylistIOPlugin : public QObject, public QMediaPlaylistIOInterface +{ +Q_OBJECT +Q_INTERFACES(QMediaPlaylistIOInterface:QFactoryInterface) +public: + explicit QMediaPlaylistIOPlugin(QObject *parent = 0); + virtual ~QMediaPlaylistIOPlugin(); + + virtual bool canRead(QIODevice *device, const QByteArray &format = QByteArray() ) const = 0; + virtual bool canRead(const QUrl& location, const QByteArray &format = QByteArray()) const = 0; + + virtual bool canWrite(QIODevice *device, const QByteArray &format) const = 0; + + virtual QStringList keys() const = 0; + + virtual QMediaPlaylistReader *createReader(QIODevice *device, const QByteArray &format = QByteArray()) = 0; + virtual QMediaPlaylistReader *createReader(const QUrl& location, const QByteArray &format = QByteArray()) = 0; + + virtual QMediaPlaylistWriter *createWriter(QIODevice *device, const QByteArray &format) = 0; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + + +#endif // QMEDIAPLAYLISTIOPLUGIN_H diff --git a/src/multimedia/qmediaplaylistnavigator.cpp b/src/multimedia/qmediaplaylistnavigator.cpp new file mode 100644 index 000000000..d78e6ef42 --- /dev/null +++ b/src/multimedia/qmediaplaylistnavigator.cpp @@ -0,0 +1,568 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmediaplaylistnavigator.h" +#include "qmediaplaylistprovider.h" +#include "qmediaplaylist.h" +#include "qmediaobject_p.h" + +#include <QtCore/qdebug.h> + +QT_BEGIN_NAMESPACE + +class QMediaPlaylistNullProvider : public QMediaPlaylistProvider +{ +public: + QMediaPlaylistNullProvider() :QMediaPlaylistProvider() {} + virtual ~QMediaPlaylistNullProvider() {} + virtual int mediaCount() const {return 0;} + virtual QMediaContent media(int) const { return QMediaContent(); } +}; + +Q_GLOBAL_STATIC(QMediaPlaylistNullProvider, _q_nullMediaPlaylist) + +class QMediaPlaylistNavigatorPrivate +{ + Q_DECLARE_NON_CONST_PUBLIC(QMediaPlaylistNavigator) +public: + QMediaPlaylistNavigatorPrivate() + :playlist(0), + currentPos(-1), + lastValidPos(-1), + playbackMode(QMediaPlaylist::Sequential), + randomPositionsOffset(-1) + { + } + + QMediaPlaylistProvider *playlist; + int currentPos; + int lastValidPos; //to be used with CurrentItemOnce playback mode + QMediaPlaylist::PlaybackMode playbackMode; + QMediaContent currentItem; + + mutable QList<int> randomModePositions; + mutable int randomPositionsOffset; + + int nextItemPos(int steps = 1) const; + int previousItemPos(int steps = 1) const; + + void _q_mediaInserted(int start, int end); + void _q_mediaRemoved(int start, int end); + void _q_mediaChanged(int start, int end); + + QMediaPlaylistNavigator *q_ptr; +}; + + +int QMediaPlaylistNavigatorPrivate::nextItemPos(int steps) const +{ + if (playlist->mediaCount() == 0) + return -1; + + if (steps == 0) + return currentPos; + + switch (playbackMode) { + case QMediaPlaylist::CurrentItemOnce: + return /*currentPos == -1 ? lastValidPos :*/ -1; + case QMediaPlaylist::CurrentItemInLoop: + return currentPos; + case QMediaPlaylist::Sequential: + { + int nextPos = currentPos+steps; + return nextPos < playlist->mediaCount() ? nextPos : -1; + } + case QMediaPlaylist::Loop: + return (currentPos+steps) % playlist->mediaCount(); + case QMediaPlaylist::Random: + { + //TODO: limit the history size + + if (randomPositionsOffset == -1) { + randomModePositions.clear(); + randomModePositions.append(currentPos); + randomPositionsOffset = 0; + } + + while (randomModePositions.size() < randomPositionsOffset+steps+1) + randomModePositions.append(-1); + int res = randomModePositions[randomPositionsOffset+steps]; + if (res<0 || res >= playlist->mediaCount()) { + res = qrand() % playlist->mediaCount(); + randomModePositions[randomPositionsOffset+steps] = res; + } + + return res; + } + } + + return -1; +} + +int QMediaPlaylistNavigatorPrivate::previousItemPos(int steps) const +{ + if (playlist->mediaCount() == 0) + return -1; + + if (steps == 0) + return currentPos; + + switch (playbackMode) { + case QMediaPlaylist::CurrentItemOnce: + return /*currentPos == -1 ? lastValidPos :*/ -1; + case QMediaPlaylist::CurrentItemInLoop: + return currentPos; + case QMediaPlaylist::Sequential: + { + int prevPos = currentPos == -1 ? playlist->mediaCount() - steps : currentPos - steps; + return prevPos>=0 ? prevPos : -1; + } + case QMediaPlaylist::Loop: + { + int prevPos = currentPos - steps; + while (prevPos<0) + prevPos += playlist->mediaCount(); + return prevPos; + } + case QMediaPlaylist::Random: + { + //TODO: limit the history size + + if (randomPositionsOffset == -1) { + randomModePositions.clear(); + randomModePositions.append(currentPos); + randomPositionsOffset = 0; + } + + while (randomPositionsOffset-steps < 0) { + randomModePositions.prepend(-1); + randomPositionsOffset++; + } + + int res = randomModePositions[randomPositionsOffset-steps]; + if (res<0 || res >= playlist->mediaCount()) { + res = qrand() % playlist->mediaCount(); + randomModePositions[randomPositionsOffset-steps] = res; + } + + return res; + } + } + + return -1; +} + +/*! + \class QMediaPlaylistNavigator + + \brief The QMediaPlaylistNavigator class provides navigation for a media playlist. + \inmodule QtMultimedia + \ingroup multimedia + \since 1.0 + + \sa QMediaPlaylist, QMediaPlaylistProvider +*/ + + +/*! + Constructs a media playlist navigator for a \a playlist. + + The \a parent is passed to QObject. + \since 1.0 + */ +QMediaPlaylistNavigator::QMediaPlaylistNavigator(QMediaPlaylistProvider *playlist, QObject *parent) + : QObject(parent) + , d_ptr(new QMediaPlaylistNavigatorPrivate) +{ + d_ptr->q_ptr = this; + + setPlaylist(playlist ? playlist : _q_nullMediaPlaylist()); +} + +/*! + Destroys a media playlist navigator. + */ + +QMediaPlaylistNavigator::~QMediaPlaylistNavigator() +{ + delete d_ptr; +} + + +/*! \property QMediaPlaylistNavigator::playbackMode + Contains the playback mode. + \since 1.0 + */ +QMediaPlaylist::PlaybackMode QMediaPlaylistNavigator::playbackMode() const +{ + return d_func()->playbackMode; +} + +/*! + Sets the playback \a mode. + \since 1.0 + */ +void QMediaPlaylistNavigator::setPlaybackMode(QMediaPlaylist::PlaybackMode mode) +{ + Q_D(QMediaPlaylistNavigator); + if (d->playbackMode == mode) + return; + + if (mode == QMediaPlaylist::Random) { + d->randomPositionsOffset = 0; + d->randomModePositions.append(d->currentPos); + } else if (d->playbackMode == QMediaPlaylist::Random) { + d->randomPositionsOffset = -1; + d->randomModePositions.clear(); + } + + d->playbackMode = mode; + + emit playbackModeChanged(mode); + emit surroundingItemsChanged(); +} + +/*! + Returns the playlist being navigated. + \since 1.0 +*/ + +QMediaPlaylistProvider *QMediaPlaylistNavigator::playlist() const +{ + return d_func()->playlist; +} + +/*! + Sets the \a playlist to navigate. + \since 1.0 +*/ +void QMediaPlaylistNavigator::setPlaylist(QMediaPlaylistProvider *playlist) +{ + Q_D(QMediaPlaylistNavigator); + + if (d->playlist == playlist) + return; + + if (d->playlist) { + d->playlist->disconnect(this); + } + + if (playlist) { + d->playlist = playlist; + } else { + //assign to shared readonly null playlist + d->playlist = _q_nullMediaPlaylist(); + } + + connect(d->playlist, SIGNAL(mediaInserted(int,int)), SLOT(_q_mediaInserted(int,int))); + connect(d->playlist, SIGNAL(mediaRemoved(int,int)), SLOT(_q_mediaRemoved(int,int))); + connect(d->playlist, SIGNAL(mediaChanged(int,int)), SLOT(_q_mediaChanged(int,int))); + + d->randomPositionsOffset = -1; + d->randomModePositions.clear(); + + if (d->currentPos != -1) { + d->currentPos = -1; + emit currentIndexChanged(-1); + } + + if (!d->currentItem.isNull()) { + d->currentItem = QMediaContent(); + emit activated(d->currentItem); //stop playback + } +} + +/*! \property QMediaPlaylistNavigator::currentItem + + Contains the media at the current position in the playlist. + + \since 1.0 + \sa currentIndex() +*/ + +QMediaContent QMediaPlaylistNavigator::currentItem() const +{ + return itemAt(d_func()->currentPos); +} + +/*! \fn QMediaContent QMediaPlaylistNavigator::nextItem(int steps) const + + Returns the media that is \a steps positions ahead of the current + position in the playlist. + + \since 1.0 + \sa nextIndex() +*/ +QMediaContent QMediaPlaylistNavigator::nextItem(int steps) const +{ + return itemAt(nextIndex(steps)); +} + +/*! + Returns the media that is \a steps positions behind the current + position in the playlist. + + \since 1.0 + \sa previousIndex() + */ +QMediaContent QMediaPlaylistNavigator::previousItem(int steps) const +{ + return itemAt(previousIndex(steps)); +} + +/*! + Returns the media at a \a position in the playlist. + \since 1.0 + */ +QMediaContent QMediaPlaylistNavigator::itemAt(int position) const +{ + return d_func()->playlist->media(position); +} + +/*! \property QMediaPlaylistNavigator::currentIndex + + Contains the position of the current media. + + If no media is current, the property contains -1. + + \since 1.0 + \sa nextIndex(), previousIndex() +*/ + +int QMediaPlaylistNavigator::currentIndex() const +{ + return d_func()->currentPos; +} + +/*! + Returns a position \a steps ahead of the current position + accounting for the playbackMode(). + + If the position is beyond the end of the playlist, this value + returned is -1. + + \since 1.0 + \sa currentIndex(), previousIndex(), playbackMode() +*/ + +int QMediaPlaylistNavigator::nextIndex(int steps) const +{ + return d_func()->nextItemPos(steps); +} + +/*! + + Returns a position \a steps behind the current position accounting + for the playbackMode(). + + If the position is prior to the beginning of the playlist this will + return -1. + + \since 1.0 + \sa currentIndex(), nextIndex(), playbackMode() +*/ +int QMediaPlaylistNavigator::previousIndex(int steps) const +{ + return d_func()->previousItemPos(steps); +} + +/*! + Advances to the next item in the playlist. + + \since 1.0 + \sa previous(), jump(), playbackMode() + */ +void QMediaPlaylistNavigator::next() +{ + Q_D(QMediaPlaylistNavigator); + + int nextPos = d->nextItemPos(); + + if ( playbackMode() == QMediaPlaylist::Random ) + d->randomPositionsOffset++; + + jump(nextPos); +} + +/*! + Returns to the previous item in the playlist, + + \since 1.0 + \sa next(), jump(), playbackMode() + */ +void QMediaPlaylistNavigator::previous() +{ + Q_D(QMediaPlaylistNavigator); + + int prevPos = d->previousItemPos(); + if ( playbackMode() == QMediaPlaylist::Random ) + d->randomPositionsOffset--; + + jump(prevPos); +} + +/*! + Jumps to a new \a position in the playlist. + \since 1.0 + */ +void QMediaPlaylistNavigator::jump(int position) +{ + Q_D(QMediaPlaylistNavigator); + + if (position<-1 || position>=d->playlist->mediaCount()) { + qWarning() << "QMediaPlaylistNavigator: Jump outside playlist range"; + position = -1; + } + + if (position != -1) + d->lastValidPos = position; + + if (playbackMode() == QMediaPlaylist::Random) { + if (d->randomModePositions[d->randomPositionsOffset] != position) { + d->randomModePositions.clear(); + d->randomModePositions.append(position); + d->randomPositionsOffset = 0; + } + } + + if (position != -1) + d->currentItem = d->playlist->media(position); + else + d->currentItem = QMediaContent(); + + if (position != d->currentPos) { + d->currentPos = position; + emit currentIndexChanged(d->currentPos); + emit surroundingItemsChanged(); + } + + emit activated(d->currentItem); +} + +/*! + \internal + \since 1.0 +*/ +void QMediaPlaylistNavigatorPrivate::_q_mediaInserted(int start, int end) +{ + Q_Q(QMediaPlaylistNavigator); + + if (currentPos >= start) { + currentPos = end-start+1; + q->jump(currentPos); + } + + //TODO: check if they really changed + emit q->surroundingItemsChanged(); +} + +/*! + \internal + \since 1.0 +*/ +void QMediaPlaylistNavigatorPrivate::_q_mediaRemoved(int start, int end) +{ + Q_Q(QMediaPlaylistNavigator); + + if (currentPos > end) { + currentPos = currentPos - end-start+1; + q->jump(currentPos); + } else if (currentPos >= start) { + //current item was removed + currentPos = qMin(start, playlist->mediaCount()-1); + q->jump(currentPos); + } + + //TODO: check if they really changed + emit q->surroundingItemsChanged(); +} + +/*! + \internal + \since 1.0 +*/ +void QMediaPlaylistNavigatorPrivate::_q_mediaChanged(int start, int end) +{ + Q_Q(QMediaPlaylistNavigator); + + if (currentPos >= start && currentPos<=end) { + QMediaContent src = playlist->media(currentPos); + if (src != currentItem) { + currentItem = src; + emit q->activated(src); + } + } + + //TODO: check if they really changed + emit q->surroundingItemsChanged(); +} + +/*! + \fn QMediaPlaylistNavigator::activated(const QMediaContent &media) + + Signals that the current \a media has changed. + \since 1.0 +*/ + +/*! + \fn QMediaPlaylistNavigator::currentIndexChanged(int position) + + Signals the \a position of the current media has changed. + \since 1.0 +*/ + +/*! + \fn QMediaPlaylistNavigator::playbackModeChanged(QMediaPlaylist::PlaybackMode mode) + + Signals that the playback \a mode has changed. + \since 1.0 +*/ + +/*! + \fn QMediaPlaylistNavigator::surroundingItemsChanged() + + Signals that media immediately surrounding the current position has changed. + \since 1.0 +*/ + +#include "moc_qmediaplaylistnavigator.cpp" +QT_END_NAMESPACE + diff --git a/src/multimedia/qmediaplaylistnavigator.h b/src/multimedia/qmediaplaylistnavigator.h new file mode 100644 index 000000000..72e452072 --- /dev/null +++ b/src/multimedia/qmediaplaylistnavigator.h @@ -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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMEDIAPLAYLISTNAVIGATOR_H +#define QMEDIAPLAYLISTNAVIGATOR_H + +#include "qmediaplaylistprovider.h" +#include "qmediaplaylist.h" +#include <QtCore/qobject.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + +class QMediaPlaylistNavigatorPrivate; +class Q_MULTIMEDIA_EXPORT QMediaPlaylistNavigator : public QObject +{ + Q_OBJECT + Q_PROPERTY(QMediaPlaylist::PlaybackMode playbackMode READ playbackMode WRITE setPlaybackMode NOTIFY playbackModeChanged) + Q_PROPERTY(int currentIndex READ currentIndex WRITE jump NOTIFY currentIndexChanged) + Q_PROPERTY(QMediaContent currentItem READ currentItem) + +public: + QMediaPlaylistNavigator(QMediaPlaylistProvider *playlist, QObject *parent = 0); + virtual ~QMediaPlaylistNavigator(); + + QMediaPlaylistProvider *playlist() const; + void setPlaylist(QMediaPlaylistProvider *playlist); + + QMediaPlaylist::PlaybackMode playbackMode() const; + + QMediaContent currentItem() const; + QMediaContent nextItem(int steps = 1) const; + QMediaContent previousItem(int steps = 1) const; + + QMediaContent itemAt(int position) const; + + int currentIndex() const; + int nextIndex(int steps = 1) const; + int previousIndex(int steps = 1) const; + +public Q_SLOTS: + void next(); + void previous(); + + void jump(int); + + void setPlaybackMode(QMediaPlaylist::PlaybackMode mode); + +Q_SIGNALS: + void activated(const QMediaContent &content); + void currentIndexChanged(int); + void playbackModeChanged(QMediaPlaylist::PlaybackMode mode); + + void surroundingItemsChanged(); + +protected: + QMediaPlaylistNavigatorPrivate *d_ptr; + +private: + Q_DISABLE_COPY(QMediaPlaylistNavigator) + Q_DECLARE_PRIVATE(QMediaPlaylistNavigator) + + Q_PRIVATE_SLOT(d_func(), void _q_mediaInserted(int start, int end)) + Q_PRIVATE_SLOT(d_func(), void _q_mediaRemoved(int start, int end)) + Q_PRIVATE_SLOT(d_func(), void _q_mediaChanged(int start, int end)) +}; + +QT_END_NAMESPACE + +QT_END_HEADER + + +#endif // QMEDIAPLAYLISTNAVIGATOR_H diff --git a/src/multimedia/qmediaplaylistprovider.cpp b/src/multimedia/qmediaplaylistprovider.cpp new file mode 100644 index 000000000..75e927b39 --- /dev/null +++ b/src/multimedia/qmediaplaylistprovider.cpp @@ -0,0 +1,329 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmediaplaylistprovider.h" +#include "qmediaplaylistprovider_p.h" + +#include <QtCore/qurl.h> + +QT_BEGIN_NAMESPACE + +/*! + \class QMediaPlaylistProvider + + \brief The QMediaPlaylistProvider class provides an abstract list of media. + \inmodule QtMultimedia + \since 1.0 + + \sa QMediaPlaylist +*/ + +/*! + Constructs a playlist provider with the given \a parent. +*/ +QMediaPlaylistProvider::QMediaPlaylistProvider(QObject *parent) + :QObject(parent), d_ptr(new QMediaPlaylistProviderPrivate) +{ +} + +/*! + \internal +*/ +QMediaPlaylistProvider::QMediaPlaylistProvider(QMediaPlaylistProviderPrivate &dd, QObject *parent) + :QObject(parent), d_ptr(&dd) +{ +} + +/*! + Destroys a playlist provider. +*/ +QMediaPlaylistProvider::~QMediaPlaylistProvider() +{ + delete d_ptr; +} + +/*! + \fn QMediaPlaylistProvider::mediaCount() const; + + Returns the size of playlist. + \since 1.0 +*/ + +/*! + \fn QMediaPlaylistProvider::media(int index) const; + + Returns the media at \a index in the playlist. + + If the index is invalid this will return a null media content. + \since 1.0 +*/ + + +/*! + Loads a playlist from from a URL \a location. If no playlist \a format is specified the loader + will inspect the URL or probe the headers to guess the format. + + New items are appended to playlist. + + Returns true if the provider supports the format and loading from the locations URL protocol, + otherwise this will return false. + \since 1.0 +*/ +bool QMediaPlaylistProvider::load(const QUrl &location, const char *format) +{ + Q_UNUSED(location); + Q_UNUSED(format); + return false; +} + +/*! + Loads a playlist from from an I/O \a device. If no playlist \a format is specified the loader + will probe the headers to guess the format. + + New items are appended to playlist. + + Returns true if the provider supports the format and loading from an I/O device, otherwise this + will return false. + \since 1.0 +*/ +bool QMediaPlaylistProvider::load(QIODevice * device, const char *format) +{ + Q_UNUSED(device); + Q_UNUSED(format); + return false; +} + +/*! + Saves the contents of a playlist to a URL \a location. If no playlist \a format is specified + the writer will inspect the URL to guess the format. + + Returns true if the playlist was saved successfully; and false otherwise. + \since 1.0 + */ +bool QMediaPlaylistProvider::save(const QUrl &location, const char *format) +{ + Q_UNUSED(location); + Q_UNUSED(format); + return false; +} + +/*! + Saves the contents of a playlist to an I/O \a device in the specified \a format. + + Returns true if the playlist was saved successfully; and false otherwise. + \since 1.0 +*/ +bool QMediaPlaylistProvider::save(QIODevice * device, const char *format) +{ + Q_UNUSED(device); + Q_UNUSED(format); + return false; +} + +/*! + Returns true if a playlist is read-only; otherwise returns false. + \since 1.0 +*/ +bool QMediaPlaylistProvider::isReadOnly() const +{ + return true; +} + +/*! + Append \a media to a playlist. + + Returns true if the media was appended; and false otherwise. + \since 1.0 +*/ +bool QMediaPlaylistProvider::addMedia(const QMediaContent &media) +{ + Q_UNUSED(media); + return false; +} + +/*! + Append multiple media \a items to a playlist. + + Returns true if the media items were appended; and false otherwise. + \since 1.0 +*/ +bool QMediaPlaylistProvider::addMedia(const QList<QMediaContent> &items) +{ + foreach(const QMediaContent &item, items) { + if (!addMedia(item)) + return false; + } + + return true; +} + +/*! + Inserts \a media into a playlist at \a position. + + Returns true if the media was inserted; and false otherwise. + \since 1.0 +*/ +bool QMediaPlaylistProvider::insertMedia(int position, const QMediaContent &media) +{ + Q_UNUSED(position); + Q_UNUSED(media); + return false; +} + +/*! + Inserts multiple media \a items into a playlist at \a position. + + Returns true if the media \a items were inserted; and false otherwise. + \since 1.0 +*/ +bool QMediaPlaylistProvider::insertMedia(int position, const QList<QMediaContent> &items) +{ + for (int i=0; i<items.count(); i++) { + if (!insertMedia(position+i,items.at(i))) + return false; + } + + return true; +} + + +/*! + Removes the media at \a position from a playlist. + + Returns true if the media was removed; and false otherwise. + \since 1.0 +*/ +bool QMediaPlaylistProvider::removeMedia(int position) +{ + Q_UNUSED(position); + return false; +} + +/*! + Removes the media between the given \a start and \a end positions from a playlist. + + Returns true if the media was removed; and false otherwise. + \since 1.0 + */ +bool QMediaPlaylistProvider::removeMedia(int start, int end) +{ + for (int pos=start; pos<=end; pos++) { + if (!removeMedia(pos)) + return false; + } + + return true; +} + +/*! + Removes all media from a playlist. + + Returns true if the media was removed; and false otherwise. + \since 1.0 +*/ +bool QMediaPlaylistProvider::clear() +{ + return removeMedia(0, mediaCount()-1); +} + +/*! + Shuffles the contents of a playlist. + \since 1.0 +*/ +void QMediaPlaylistProvider::shuffle() +{ +} + +/*! + \fn void QMediaPlaylistProvider::mediaAboutToBeInserted(int start, int end); + + Signals that new media is about to be inserted into a playlist between the \a start and \a end + positions. + \since 1.0 +*/ + +/*! + \fn void QMediaPlaylistProvider::mediaInserted(int start, int end); + + Signals that new media has been inserted into a playlist between the \a start and \a end + positions. + \since 1.0 +*/ + +/*! + \fn void QMediaPlaylistProvider::mediaAboutToBeRemoved(int start, int end); + + Signals that media is about to be removed from a playlist between the \a start and \a end + positions. + \since 1.0 +*/ + +/*! + \fn void QMediaPlaylistProvider::mediaRemoved(int start, int end); + + Signals that media has been removed from a playlist between the \a start and \a end positions. + \since 1.0 +*/ + +/*! + \fn void QMediaPlaylistProvider::mediaChanged(int start, int end); + + Signals that media in playlist between the \a start and \a end positions inclusive has changed. + \since 1.0 +*/ + +/*! + \fn void QMediaPlaylistProvider::loaded() + + Signals that a load() finished successfully. + \since 1.0 +*/ + +/*! + \fn void QMediaPlaylistProvider::loadFailed(QMediaPlaylist::Error error, const QString& errorMessage) + + Signals that a load failed() due to an \a error. The \a errorMessage provides more information. + \since 1.0 +*/ + +#include "moc_qmediaplaylistprovider.cpp" +QT_END_NAMESPACE + diff --git a/src/multimedia/qmediaplaylistprovider.h b/src/multimedia/qmediaplaylistprovider.h new file mode 100644 index 000000000..79167e8ba --- /dev/null +++ b/src/multimedia/qmediaplaylistprovider.h @@ -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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMEDIAPLAYLISTPROVIDER_H +#define QMEDIAPLAYLISTPROVIDER_H + +#include <QObject> + +#include "qmediacontent.h" +#include "qmediaplaylist.h" + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + +class QString; +QT_END_NAMESPACE + +QT_BEGIN_NAMESPACE + +class QMediaPlaylistProviderPrivate; +class Q_MULTIMEDIA_EXPORT QMediaPlaylistProvider : public QObject +{ +Q_OBJECT +public: + QMediaPlaylistProvider(QObject *parent=0); + virtual ~QMediaPlaylistProvider(); + + virtual bool load(const QUrl &location, const char *format = 0); + virtual bool load(QIODevice * device, const char *format = 0); + virtual bool save(const QUrl &location, const char *format = 0); + virtual bool save(QIODevice * device, const char *format); + + virtual int mediaCount() const = 0; + virtual QMediaContent media(int index) const = 0; + + virtual bool isReadOnly() const; + + virtual bool addMedia(const QMediaContent &content); + virtual bool addMedia(const QList<QMediaContent> &contentList); + virtual bool insertMedia(int index, const QMediaContent &content); + virtual bool insertMedia(int index, const QList<QMediaContent> &content); + virtual bool removeMedia(int pos); + virtual bool removeMedia(int start, int end); + virtual bool clear(); + +public Q_SLOTS: + virtual void shuffle(); + +Q_SIGNALS: + void mediaAboutToBeInserted(int start, int end); + void mediaInserted(int start, int end); + + void mediaAboutToBeRemoved(int start, int end); + void mediaRemoved(int start, int end); + + void mediaChanged(int start, int end); + + void loaded(); + void loadFailed(QMediaPlaylist::Error, const QString& errorMessage); + +protected: + QMediaPlaylistProviderPrivate *d_ptr; + QMediaPlaylistProvider(QMediaPlaylistProviderPrivate &dd, QObject *parent); + +private: + Q_DECLARE_PRIVATE(QMediaPlaylistProvider) +}; + +QT_END_NAMESPACE + +QT_END_HEADER + + +#endif // QMEDIAPLAYLISTPROVIDER_H diff --git a/src/multimedia/qmediaplaylistprovider_p.h b/src/multimedia/qmediaplaylistprovider_p.h new file mode 100644 index 000000000..71fb86f20 --- /dev/null +++ b/src/multimedia/qmediaplaylistprovider_p.h @@ -0,0 +1,80 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMEDIAPLAYLISTPROVIDER_P_H +#define QMEDIAPLAYLISTPROVIDER_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qmediaplaylist.h" + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + +class QMediaPlaylistProviderPrivate +{ +public: + QMediaPlaylistProviderPrivate() + {} + virtual ~QMediaPlaylistProviderPrivate() + {} +}; + +QT_END_NAMESPACE + +QT_END_HEADER + + + +#endif // QMEDIAPLAYLISTSOURCE_P_H diff --git a/src/multimedia/qmediaplaylistsourcecontrol.cpp b/src/multimedia/qmediaplaylistsourcecontrol.cpp new file mode 100644 index 000000000..ca90feda2 --- /dev/null +++ b/src/multimedia/qmediaplaylistsourcecontrol.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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <qmediaplaylistsourcecontrol.h> +#include <qmediacontrol_p.h> + +QT_BEGIN_NAMESPACE + +/*! + \class QMediaPlaylistSourceControl + \inmodule QtMultimedia + \ingroup multimedia-serv + \since 1.0 + + + \brief The QMediaPlaylistSourceControl class provides access to the playlist playback + functionality of a QMediaService. + + This control allows QMediaPlaylist to be passed directly to the service + instead of playing media sources one by one. This control should be + implemented if backend benefits from knowing the next media source to be + played, for example for preloading, cross fading or gap-less playback. + + If QMediaPlaylistSourceControl is provided, the backend must listen for + current playlist item changes to load corresponding media source and + advance the playlist with QMediaPlaylist::next() when playback of the + current media is finished. + + The interface name of QMediaPlaylistSourceControl is \c com.nokia.Qt.QMediaPlaylistSourceControl/1.0 as + defined in QMediaPlaylistSourceControl_iid. + + \sa QMediaService::requestControl(), QMediaPlayer +*/ + +/*! + \macro QMediaPlaylistSourceControl_iid + + \c com.nokia.Qt.QMediaPlaylistSourceControl/1.0 + + Defines the interface name of the QMediaPlaylistSourceControl class. + + \relates QMediaPlaylistSourceControl +*/ + +/*! + Create a new playlist source control object with the given \a parent. +*/ +QMediaPlaylistSourceControl::QMediaPlaylistSourceControl(QObject *parent): + QMediaControl(*new QMediaControlPrivate, parent) +{ +} + +/*! + Destroys the playlist control. +*/ +QMediaPlaylistSourceControl::~QMediaPlaylistSourceControl() +{ +} + + +/*! + \fn QMediaPlaylistSourceControl::playlist() const + + Returns the current playlist. + Should return a null pointer if no playlist is assigned. + \since 1.0 +*/ + +/*! + \fn QMediaPlaylistSourceControl::setPlaylist(QMediaPlaylist *playlist) + + Set the playlist of this media player to \a playlist. + If a null pointer is passed, the playlist source should be disabled. + + The current media should be replaced with the current item of the media playlist. + \since 1.0 +*/ + + +/*! + \fn QMediaPlaylistSourceControl::playlistChanged(QMediaPlaylist* playlist) + + Signal emitted when the playlist has changed to \a playlist. + \since 1.0 +*/ + +#include "moc_qmediaplaylistsourcecontrol.cpp" +QT_END_NAMESPACE + diff --git a/src/multimedia/qmediaplaylistsourcecontrol.h b/src/multimedia/qmediaplaylistsourcecontrol.h new file mode 100644 index 000000000..040bb6431 --- /dev/null +++ b/src/multimedia/qmediaplaylistsourcecontrol.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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#ifndef QMEDIAPLAYLISTSOURCECONTROL_H +#define QMEDIAPLAYLISTSOURCECONTROL_H + +#include <qmediacontrol.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + +class QMediaPlaylist; + +class Q_MULTIMEDIA_EXPORT QMediaPlaylistSourceControl : public QMediaControl +{ + Q_OBJECT + +public: + virtual ~QMediaPlaylistSourceControl(); + + virtual QMediaPlaylist *playlist() const = 0; + virtual void setPlaylist(QMediaPlaylist *) = 0; + +Q_SIGNALS: + void playlistChanged(QMediaPlaylist* playlist); + +protected: + QMediaPlaylistSourceControl(QObject* parent = 0); +}; + +#define QMediaPlaylistSourceControl_iid "com.nokia.Qt.QMediaPlaylistSourceControl/1.0" +Q_MEDIA_DECLARE_CONTROL(QMediaPlaylistSourceControl, QMediaPlaylistSourceControl_iid) + +QT_END_NAMESPACE + +QT_END_HEADER + + +#endif // QMEDIAPLAYLISTCONTROL_H diff --git a/src/multimedia/qmediapluginloader.cpp b/src/multimedia/qmediapluginloader.cpp new file mode 100644 index 000000000..32f336959 --- /dev/null +++ b/src/multimedia/qmediapluginloader.cpp @@ -0,0 +1,213 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmediapluginloader_p.h" +#include <QtCore/qcoreapplication.h> +#include <QtCore/qpluginloader.h> +#include <QtCore/qdir.h> +#include <QtCore/qdebug.h> + +#include "qmediaserviceproviderplugin.h" + +#if defined(Q_OS_MAC) +# include <CoreFoundation/CoreFoundation.h> +#endif + +QT_BEGIN_NAMESPACE + +typedef QMap<QString,QObjectList> ObjectListMap; +Q_GLOBAL_STATIC(ObjectListMap, staticMediaPlugins); + + +QMediaPluginLoader::QMediaPluginLoader(const char *iid, const QString &location, Qt::CaseSensitivity): + m_iid(iid) +{ + m_location = QString::fromLatin1("/%1").arg(location); + load(); +} + +QStringList QMediaPluginLoader::keys() const +{ + return m_instances.keys(); +} + +QObject* QMediaPluginLoader::instance(QString const &key) +{ + return m_instances.value(key).value(0); +} + +QList<QObject*> QMediaPluginLoader::instances(QString const &key) +{ + return m_instances.value(key); +} + +//to be used for testing purposes only +void QMediaPluginLoader::setStaticPlugins(const QString &location, const QObjectList& objects) +{ + staticMediaPlugins()->insert(QString::fromLatin1("/%1").arg(location), objects); +} + +QStringList QMediaPluginLoader::availablePlugins() const +{ + QStringList paths; + QStringList plugins; + +#if defined(Q_OS_MAC) + QString imageSuffix(qgetenv("DYLD_IMAGE_SUFFIX")); + + // Bundle plugin directory + CFBundleRef mainBundle = CFBundleGetMainBundle(); + if (mainBundle != 0) { + CFURLRef baseUrl = CFBundleCopyBundleURL(mainBundle); + CFURLRef pluginUrlPart = CFBundleCopyBuiltInPlugInsURL(mainBundle); + CFStringRef pluginPathPart = CFURLCopyFileSystemPath(pluginUrlPart, kCFURLPOSIXPathStyle); + CFURLRef pluginUrl = CFURLCreateCopyAppendingPathComponent(0, baseUrl, pluginPathPart, true); + CFStringRef pluginPath = CFURLCopyFileSystemPath(pluginUrl, kCFURLPOSIXPathStyle); + + CFIndex length = CFStringGetLength(pluginPath); + UniChar buffer[length]; + CFStringGetCharacters(pluginPath, CFRangeMake(0, length), buffer); + + paths << QString(reinterpret_cast<const QChar *>(buffer), length); + + CFRelease(pluginPath); + CFRelease(pluginUrl); + CFRelease(pluginPathPart); + CFRelease(pluginUrlPart); + CFRelease(baseUrl); + } +#endif + + // Qt paths + paths << QCoreApplication::libraryPaths(); + + foreach (const QString &path, paths) { + QDir typeDir(path + m_location); + foreach (const QString &file, typeDir.entryList(QDir::Files)) { +#if defined(Q_OS_MAC) + if (!imageSuffix.isEmpty()) { // Only add appropriate images + if (file.lastIndexOf(imageSuffix, -6) == -1) + continue; + } else { // Ignore any images with common suffixes + if (file.endsWith(QLatin1String("_debug.dylib")) || + file.endsWith(QLatin1String("_profile.dylib"))) + continue; + } +#elif defined(Q_OS_UNIX) + // Ignore separate debug files + if (file.endsWith(QLatin1String(".debug"))) + continue; +#elif defined(Q_OS_WIN) + // Ignore non-dlls + if (!file.endsWith(QLatin1String(".dll"), Qt::CaseInsensitive)) + continue; +#endif + plugins << typeDir.absoluteFilePath(file); + } + } + + return plugins; +} + +void QMediaPluginLoader::load() +{ + if (!m_instances.isEmpty()) + return; + +#if !defined QT_NO_DEBUG + const bool showDebug = qgetenv("QT_DEBUG_PLUGINS").toInt() > 0; +#endif + + if (staticMediaPlugins() && staticMediaPlugins()->contains(m_location)) { + foreach(QObject *o, staticMediaPlugins()->value(m_location)) { + if (o != 0 && o->qt_metacast(m_iid) != 0) { + QFactoryInterface* p = qobject_cast<QFactoryInterface*>(o); + if (p != 0) { + foreach (QString const &key, p->keys()) + m_instances[key].append(o); + } + } + } + } else { + QSet<QString> loadedPlugins; + + foreach (const QString &plugin, availablePlugins()) { + QString fileName = QFileInfo(plugin).fileName(); + //don't try to load plugin with the same name if it's already loaded + if (loadedPlugins.contains(fileName)) { +#if !defined QT_NO_DEBUG + if (showDebug) + qDebug() << "Skip loading plugin" << plugin; +#endif + continue; + } + + QPluginLoader loader(plugin); + + QObject *o = loader.instance(); + if (o != 0 && o->qt_metacast(m_iid) != 0) { + QFactoryInterface* p = qobject_cast<QFactoryInterface*>(o); + if (p != 0) { + foreach (const QString &key, p->keys()) + m_instances[key].append(o); + + loadedPlugins.insert(fileName); +#if !defined QT_NO_DEBUG + if (showDebug) + qDebug() << "Loaded plugin" << plugin << "services:" << p->keys(); +#endif + } + + continue; + } else { +#if !defined QT_NO_DEBUG + if (showDebug) + qWarning() << "QMediaPluginLoader: Failed to load plugin: " << plugin << loader.errorString(); +#endif + } + + delete o; + } + } +} + +QT_END_NAMESPACE + diff --git a/src/multimedia/qmediapluginloader_p.h b/src/multimedia/qmediapluginloader_p.h new file mode 100644 index 000000000..1800a41e7 --- /dev/null +++ b/src/multimedia/qmediapluginloader_p.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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMEDIAPLUGINLOADER_H +#define QMEDIAPLUGINLOADER_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <qtmultimediadefs.h> +#include <QtCore/qobject.h> +#include <QtCore/qstring.h> +#include <QtCore/qstringlist.h> +#include <QtCore/qmap.h> + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + +class QMediaServiceProviderPlugin; + +class Q_AUTOTEST_EXPORT QMediaPluginLoader +{ +public: + QMediaPluginLoader(const char *iid, + const QString &suffix = QString(), + Qt::CaseSensitivity = Qt::CaseSensitive); + + QStringList keys() const; + QObject* instance(QString const &key); + QList<QObject*> instances(QString const &key); + + static void setStaticPlugins(const QString &location, const QObjectList& objects); + +private: + void load(); + QStringList availablePlugins() const; + + QByteArray m_iid; + QString m_location; + QMap<QString, QList<QObject *> > m_instances; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + + +#endif // QMEDIAPLUGINLOADER_H diff --git a/src/multimedia/qmediarecorder.cpp b/src/multimedia/qmediarecorder.cpp new file mode 100644 index 000000000..bcbae5708 --- /dev/null +++ b/src/multimedia/qmediarecorder.cpp @@ -0,0 +1,904 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmediarecorder.h" + +#include <qmediarecordercontrol.h> +#include <qmediaobject_p.h> +#include <qmediaservice.h> +#include <qmediaserviceprovider.h> +#include <qmetadatawritercontrol.h> +#include <qaudioencodercontrol.h> +#include <qvideoencodercontrol.h> +#include <qmediacontainercontrol.h> +#include <qcamera.h> +#include <qcameracontrol.h> + +#include <QtCore/qdebug.h> +#include <QtCore/qurl.h> +#include <QtCore/qstringlist.h> +#include <QtCore/qmetaobject.h> + +#include <qaudioformat.h> + +QT_BEGIN_NAMESPACE + +/*! + \class QMediaRecorder + \inmodule QtMultimedia + \ingroup multimedia + \since 1.0 + + + \brief The QMediaRecorder class is used for the recording of media content. + + The QMediaRecorder class is a high level media recording class. It's not + intended to be used alone but for accessing the media recording functions + of other media objects, like QRadioTuner, or QAudioCaptureSource. + + \snippet doc/src/snippets/multimedia-snippets/media.cpp Media recorder + + \sa QAudioCaptureSource +*/ + +namespace +{ +class MediaRecorderRegisterMetaTypes +{ +public: + MediaRecorderRegisterMetaTypes() + { + qRegisterMetaType<QMediaRecorder::State>("QMediaRecorder::State"); + qRegisterMetaType<QMediaRecorder::Error>("QMediaRecorder::Error"); + } +} _registerRecorderMetaTypes; +} + + +class QMediaRecorderPrivate +{ + Q_DECLARE_NON_CONST_PUBLIC(QMediaRecorder) + +public: + QMediaRecorderPrivate(); + + QMediaObject *mediaObject; + + QMediaRecorderControl *control; + QMediaContainerControl *formatControl; + QAudioEncoderControl *audioControl; + QVideoEncoderControl *videoControl; + QMetaDataWriterControl *metaDataControl; + + QTimer* notifyTimer; + + QMediaRecorder::State state; + QMediaRecorder::Error error; + QString errorString; + + void _q_stateChanged(QMediaRecorder::State state); + void _q_error(int error, const QString &errorString); + void _q_serviceDestroyed(); + void _q_notify(); + void _q_updateNotifyInterval(int ms); + + QMediaRecorder *q_ptr; +}; + +QMediaRecorderPrivate::QMediaRecorderPrivate(): + mediaObject(0), + control(0), + formatControl(0), + audioControl(0), + videoControl(0), + metaDataControl(0), + notifyTimer(0), + state(QMediaRecorder::StoppedState), + error(QMediaRecorder::NoError) +{ +} + +#define ENUM_NAME(c,e,v) (c::staticMetaObject.enumerator(c::staticMetaObject.indexOfEnumerator(e)).valueToKey((v))) + +void QMediaRecorderPrivate::_q_stateChanged(QMediaRecorder::State ps) +{ + Q_Q(QMediaRecorder); + + if (ps == QMediaRecorder::RecordingState) + notifyTimer->start(); + else + notifyTimer->stop(); + +// qDebug() << "Recorder state changed:" << ENUM_NAME(QMediaRecorder,"State",ps); + if (state != ps) { + emit q->stateChanged(ps); + } + + state = ps; +} + + +void QMediaRecorderPrivate::_q_error(int error, const QString &errorString) +{ + Q_Q(QMediaRecorder); + + this->error = QMediaRecorder::Error(error); + this->errorString = errorString; + + emit q->error(this->error); +} + +void QMediaRecorderPrivate::_q_serviceDestroyed() +{ + mediaObject = 0; + control = 0; + formatControl = 0; + audioControl = 0; + videoControl = 0; + metaDataControl = 0; +} + +void QMediaRecorderPrivate::_q_notify() +{ + emit q_func()->durationChanged(q_func()->duration()); +} + +void QMediaRecorderPrivate::_q_updateNotifyInterval(int ms) +{ + notifyTimer->setInterval(ms); +} + + +/*! + Constructs a media recorder which records the media produced by \a mediaObject. + + The \a parent is passed to QMediaObject. + \since 1.0 +*/ + +QMediaRecorder::QMediaRecorder(QMediaObject *mediaObject, QObject *parent): + QObject(parent), + d_ptr(new QMediaRecorderPrivate) +{ + Q_D(QMediaRecorder); + d->q_ptr = this; + setMediaObject(mediaObject); + + d->notifyTimer = new QTimer(this); + d->notifyTimer->setInterval(mediaObject->notifyInterval()); + connect(d->notifyTimer, SIGNAL(timeout()), SLOT(_q_notify())); + connect(mediaObject, SIGNAL(notifyIntervalChanged(int)), SLOT(_q_updateNotifyInterval(int))); +} + +/*! + Destroys a media recorder object. +*/ + +QMediaRecorder::~QMediaRecorder() +{ +} + +/*! + Returns the QMediaObject instance that this QMediaRecorder is bound too, + or 0 otherwise. + \since 1.0 +*/ +QMediaObject *QMediaRecorder::mediaObject() const +{ + return d_func()->mediaObject; +} + +/*! + \internal + \since 1.0 +*/ +bool QMediaRecorder::setMediaObject(QMediaObject *object) +{ + Q_D(QMediaRecorder); + + if (object == d->mediaObject) + return true; + + if (d->mediaObject) { + if (d->control) { + disconnect(d->control, SIGNAL(stateChanged(QMediaRecorder::State)), + this, SLOT(_q_stateChanged(QMediaRecorder::State))); + + disconnect(d->control, SIGNAL(mutedChanged(bool)), + this, SIGNAL(mutedChanged(bool))); + + disconnect(d->control, SIGNAL(durationChanged(qint64)), + this, SIGNAL(durationChanged(qint64))); + + disconnect(d->control, SIGNAL(error(int,QString)), + this, SLOT(_q_error(int,QString))); + } + + QMediaService *service = d->mediaObject->service(); + + if (service) { + disconnect(service, SIGNAL(destroyed()), this, SLOT(_q_serviceDestroyed())); + + if (d->control) + service->releaseControl(d->control); + if (d->formatControl) + service->releaseControl(d->formatControl); + if (d->audioControl) + service->releaseControl(d->audioControl); + if (d->videoControl) + service->releaseControl(d->videoControl); + if (d->metaDataControl) { + disconnect(d->metaDataControl, SIGNAL(metaDataChanged()), + this, SIGNAL(metaDataChanged())); + disconnect(d->metaDataControl, SIGNAL(metaDataAvailableChanged(bool)), + this, SIGNAL(metaDataAvailableChanged(bool))); + disconnect(d->metaDataControl, SIGNAL(writableChanged(bool)), + this, SIGNAL(metaDataWritableChanged(bool))); + + service->releaseControl(d->metaDataControl); + } + } + } + + d->control = 0; + d->formatControl = 0; + d->audioControl = 0; + d->videoControl = 0; + d->metaDataControl = 0; + + d->mediaObject = object; + + if (d->mediaObject) { + QMediaService *service = d->mediaObject->service(); + + if (service) { + d->control = qobject_cast<QMediaRecorderControl*>(service->requestControl(QMediaRecorderControl_iid)); + + if (d->control) { + d->formatControl = qobject_cast<QMediaContainerControl *>(service->requestControl(QMediaContainerControl_iid)); + d->audioControl = qobject_cast<QAudioEncoderControl *>(service->requestControl(QAudioEncoderControl_iid)); + d->videoControl = qobject_cast<QVideoEncoderControl *>(service->requestControl(QVideoEncoderControl_iid)); + + QMediaControl *control = service->requestControl(QMetaDataWriterControl_iid); + if (control) { + d->metaDataControl = qobject_cast<QMetaDataWriterControl *>(control); + if (!d->metaDataControl) { + service->releaseControl(control); + } else { + connect(d->metaDataControl, + SIGNAL(metaDataChanged()), + SIGNAL(metaDataChanged())); + connect(d->metaDataControl, + SIGNAL(metaDataAvailableChanged(bool)), + SIGNAL(metaDataAvailableChanged(bool))); + connect(d->metaDataControl, + SIGNAL(writableChanged(bool)), + SIGNAL(metaDataWritableChanged(bool))); + } + } + + connect(d->control, SIGNAL(stateChanged(QMediaRecorder::State)), + this, SLOT(_q_stateChanged(QMediaRecorder::State))); + + connect(d->control, SIGNAL(mutedChanged(bool)), + this, SIGNAL(mutedChanged(bool))); + + connect(d->control, SIGNAL(durationChanged(qint64)), + this, SIGNAL(durationChanged(qint64))); + + connect(d->control, SIGNAL(error(int,QString)), + this, SLOT(_q_error(int,QString))); + + connect(service, SIGNAL(destroyed()), this, SLOT(_q_serviceDestroyed())); + + + return true; + } + } + + d->mediaObject = 0; + return false; + } + + return true; +} + +/*! + \property QMediaRecorder::outputLocation + \brief the destination location of media content. + + Setting the location can fail, for example when the service supports only + local file system locations but a network URL was passed. If the service + does not support media recording this setting the output location will + always fail. + + The \a location can be relative or empty; + in this case the recorder uses the system specific place and file naming scheme. + After recording has stated, QMediaRecorder::outputLocation() returns the actual output location. + \since 1.0 +*/ + +/*! + Returns true if media recorder service ready to use. + \since 1.0 +*/ +bool QMediaRecorder::isAvailable() const +{ + if (d_func()->control != NULL) + return true; + else + return false; +} + +/*! + Returns the availability error code. + \since 1.0 +*/ +QtMultimedia::AvailabilityError QMediaRecorder::availabilityError() const +{ + if (d_func()->control != NULL) + return QtMultimedia::NoError; + else + return QtMultimedia::ServiceMissingError; +} + +QUrl QMediaRecorder::outputLocation() const +{ + return d_func()->control ? d_func()->control->outputLocation() : QUrl(); +} + +bool QMediaRecorder::setOutputLocation(const QUrl &location) +{ + Q_D(QMediaRecorder); + return d->control ? d->control->setOutputLocation(location) : false; +} + +/*! + Returns the current media recorder state. + + \since 1.0 + \sa QMediaRecorder::State +*/ + +QMediaRecorder::State QMediaRecorder::state() const +{ + return d_func()->control ? QMediaRecorder::State(d_func()->control->state()) : StoppedState; +} + +/*! + Returns the current error state. + + \since 1.0 + \sa errorString() +*/ + +QMediaRecorder::Error QMediaRecorder::error() const +{ + return d_func()->error; +} + +/*! + Returns a string describing the current error state. + + \since 1.0 + \sa error() +*/ + +QString QMediaRecorder::errorString() const +{ + return d_func()->errorString; +} + +/*! + \property QMediaRecorder::duration + + \brief the recorded media duration in milliseconds. + \since 1.0 +*/ + +qint64 QMediaRecorder::duration() const +{ + return d_func()->control ? d_func()->control->duration() : 0; +} + +/*! + \property QMediaRecorder::muted + + \brief whether a recording audio stream is muted. + \since 1.0 +*/ + +bool QMediaRecorder::isMuted() const +{ + return d_func()->control ? d_func()->control->isMuted() : 0; +} + +void QMediaRecorder::setMuted(bool muted) +{ + Q_D(QMediaRecorder); + + if (d->control) + d->control->setMuted(muted); +} + +/*! + Returns a list of MIME types of supported container formats. + \since 1.0 +*/ +QStringList QMediaRecorder::supportedContainers() const +{ + return d_func()->formatControl ? + d_func()->formatControl->supportedContainers() : QStringList(); +} + +/*! + Returns a description of a container format \a mimeType. + \since 1.0 +*/ +QString QMediaRecorder::containerDescription(const QString &mimeType) const +{ + return d_func()->formatControl ? + d_func()->formatControl->containerDescription(mimeType) : QString(); +} + +/*! + Returns the MIME type of the selected container format. + \since 1.0 +*/ + +QString QMediaRecorder::containerMimeType() const +{ + return d_func()->formatControl ? + d_func()->formatControl->containerMimeType() : QString(); +} + +/*! + Returns a list of supported audio codecs. + \since 1.0 +*/ +QStringList QMediaRecorder::supportedAudioCodecs() const +{ + return d_func()->audioControl ? + d_func()->audioControl->supportedAudioCodecs() : QStringList(); +} + +/*! + Returns a description of an audio \a codec. + \since 1.0 +*/ +QString QMediaRecorder::audioCodecDescription(const QString &codec) const +{ + return d_func()->audioControl ? + d_func()->audioControl->codecDescription(codec) : QString(); +} + +/*! + Returns a list of supported audio sample rates. + + If non null audio \a settings parameter is passed, the returned list is + reduced to sample rates supported with partial settings applied. + + This can be used to query the list of sample rates, supported by specific + audio codec. + + If the encoder supports arbitrary sample rates within the supported rates + range, *\a continuous is set to true, otherwise *\a continuous is set to + false. + \since 1.0 +*/ + +QList<int> QMediaRecorder::supportedAudioSampleRates(const QAudioEncoderSettings &settings, bool *continuous) const +{ + if (continuous) + *continuous = false; + + return d_func()->audioControl ? + d_func()->audioControl->supportedSampleRates(settings, continuous) : QList<int>(); +} + +/*! + Returns a list of resolutions video can be encoded at. + + If non null video \a settings parameter is passed, the returned list is + reduced to resolution supported with partial settings like video codec or + framerate applied. + + If the encoder supports arbitrary resolutions within the supported range, + *\a continuous is set to true, otherwise *\a continuous is set to false. + + \since 1.0 + \sa QVideoEncoderSettings::resolution() +*/ +QList<QSize> QMediaRecorder::supportedResolutions(const QVideoEncoderSettings &settings, bool *continuous) const +{ + if (continuous) + *continuous = false; + + return d_func()->videoControl ? + d_func()->videoControl->supportedResolutions(settings, continuous) : QList<QSize>(); +} + +/*! + Returns a list of frame rates video can be encoded at. + + If non null video \a settings parameter is passed, the returned list is + reduced to frame rates supported with partial settings like video codec or + resolution applied. + + If the encoder supports arbitrary frame rates within the supported range, + *\a continuous is set to true, otherwise *\a continuous is set to false. + + \since 1.0 + \sa QVideoEncoderSettings::frameRate() +*/ +QList<qreal> QMediaRecorder::supportedFrameRates(const QVideoEncoderSettings &settings, bool *continuous) const +{ + if (continuous) + *continuous = false; + + return d_func()->videoControl ? + d_func()->videoControl->supportedFrameRates(settings, continuous) : QList<qreal>(); +} + +/*! + Returns a list of supported video codecs. + \since 1.0 +*/ +QStringList QMediaRecorder::supportedVideoCodecs() const +{ + return d_func()->videoControl ? + d_func()->videoControl->supportedVideoCodecs() : QStringList(); +} + +/*! + Returns a description of a video \a codec. + + \since 1.0 + \sa setEncodingSettings() +*/ +QString QMediaRecorder::videoCodecDescription(const QString &codec) const +{ + return d_func()->videoControl ? + d_func()->videoControl->videoCodecDescription(codec) : QString(); +} + +/*! + Returns the audio encoder settings being used. + + \since 1.0 + \sa setEncodingSettings() +*/ + +QAudioEncoderSettings QMediaRecorder::audioSettings() const +{ + return d_func()->audioControl ? + d_func()->audioControl->audioSettings() : QAudioEncoderSettings(); +} + +/*! + Returns the video encoder settings being used. + + \since 1.0 + \sa setEncodingSettings() +*/ + +QVideoEncoderSettings QMediaRecorder::videoSettings() const +{ + return d_func()->videoControl ? + d_func()->videoControl->videoSettings() : QVideoEncoderSettings(); +} + +/*! + Sets the \a audio and \a video encoder settings and \a container format MIME type. + + If some parameters are not specified, or null settings are passed, the + encoder will choose default encoding parameters, depending on media + source properties. + While setEncodingSettings is optional, the backend can preload + encoding pipeline to improve recording startup time. + + It's only possible to change settings when the encoder is in the + QMediaEncoder::StoppedState state. + + \since 1.0 + \sa audioSettings(), videoSettings(), containerMimeType() +*/ + +void QMediaRecorder::setEncodingSettings(const QAudioEncoderSettings &audio, + const QVideoEncoderSettings &video, + const QString &container) +{ + Q_D(QMediaRecorder); + + QCamera *camera = qobject_cast<QCamera*>(d->mediaObject); + if (camera && camera->captureMode() == QCamera::CaptureVideo) { + QMetaObject::invokeMethod(camera, + "_q_preparePropertyChange", + Qt::DirectConnection, + Q_ARG(int, QCameraControl::VideoEncodingSettings)); + } + + if (d->audioControl) + d->audioControl->setAudioSettings(audio); + + if (d->videoControl) + d->videoControl->setVideoSettings(video); + + if (d->formatControl) + d->formatControl->setContainerMimeType(container); + + if (d->control) + d->control->applySettings(); +} + + +/*! + Start recording. + + This is an asynchronous call, with signal + stateCahnged(QMediaRecorder::RecordingState) being emitted when recording + started, otherwise the error() signal is emitted. + \since 1.0 +*/ + +void QMediaRecorder::record() +{ + Q_D(QMediaRecorder); + + // reset error + d->error = NoError; + d->errorString = QString(); + + if (d->control) + d->control->record(); +} + +/*! + Pause recording. + \since 1.0 +*/ + +void QMediaRecorder::pause() +{ + Q_D(QMediaRecorder); + if (d->control) + d->control->pause(); +} + +/*! + Stop recording. + \since 1.0 +*/ + +void QMediaRecorder::stop() +{ + Q_D(QMediaRecorder); + if (d->control) + d->control->stop(); +} + +/*! + \enum QMediaRecorder::State + + \value StoppedState The recorder is not active. + \value RecordingState The recorder is currently active and producing data. + \value PausedState The recorder is paused. +*/ + +/*! + \enum QMediaRecorder::Error + + \value NoError No Errors. + \value ResourceError Device is not ready or not available. + \value FormatError Current format is not supported. +*/ + +/*! + \fn QMediaRecorder::stateChanged(State state) + + Signals that a media recorder's \a state has changed. + \since 1.0 +*/ + +/*! + \fn QMediaRecorder::durationChanged(qint64 duration) + + Signals that the \a duration of the recorded media has changed. + \since 1.0 +*/ + +/*! + \fn QMediaRecorder::error(QMediaRecorder::Error error) + + Signals that an \a error has occurred. + \since 1.0 +*/ + +/*! + \fn QMediaRecorder::mutedChanged(bool muted) + + Signals that the \a muted state has changed. If true the recording is being muted. + \since 1.0 +*/ + +/*! + \property QMediaRecorder::metaDataAvailable + \brief whether access to a media object's meta-data is available. + + If this is true there is meta-data available, otherwise there is no meta-data available. + \since 1.0 +*/ + +bool QMediaRecorder::isMetaDataAvailable() const +{ + Q_D(const QMediaRecorder); + + return d->metaDataControl + ? d->metaDataControl->isMetaDataAvailable() + : false; +} + +/*! + \fn QMediaRecorder::metaDataAvailableChanged(bool available) + + Signals that the \a available state of a media object's meta-data has changed. + \since 1.0 +*/ + +/*! + \property QMediaRecorder::metaDataWritable + \brief whether a media object's meta-data is writable. + + If this is true the meta-data is writable, otherwise the meta-data is read-only. + \since 1.0 +*/ + +bool QMediaRecorder::isMetaDataWritable() const +{ + Q_D(const QMediaRecorder); + + return d->metaDataControl + ? d->metaDataControl->isWritable() + : false; +} + +/*! + \fn QMediaRecorder::metaDataWritableChanged(bool writable) + + Signals that the \a writable state of a media object's meta-data has changed. + \since 1.0 +*/ + +/*! + Returns the value associated with a meta-data \a key. + \since 1.0 +*/ +QVariant QMediaRecorder::metaData(QtMultimedia::MetaData key) const +{ + Q_D(const QMediaRecorder); + + return d->metaDataControl + ? d->metaDataControl->metaData(key) + : QVariant(); +} + +/*! + Sets a \a value for a meta-data \a key. + + \note To ensure that meta data is set corretly, it should be set before starting the recording. + Once the recording is stopped, any meta data set will be attached to the next recording. + \since 1.0 +*/ +void QMediaRecorder::setMetaData(QtMultimedia::MetaData key, const QVariant &value) +{ + Q_D(QMediaRecorder); + + if (d->metaDataControl) + d->metaDataControl->setMetaData(key, value); +} + +/*! + Returns a list of keys there is meta-data available for. + \since 1.0 +*/ +QList<QtMultimedia::MetaData> QMediaRecorder::availableMetaData() const +{ + Q_D(const QMediaRecorder); + + return d->metaDataControl + ? d->metaDataControl->availableMetaData() + : QList<QtMultimedia::MetaData>(); +} + +/*! + \fn QMediaRecorder::metaDataChanged() + + Signals that a media object's meta-data has changed. + \since 1.0 +*/ + +/*! + Returns the value associated with a meta-data \a key. + + The naming and type of extended meta-data is not standardized, so the values and meaning + of keys may vary between backends. + \since 1.0 +*/ +QVariant QMediaRecorder::extendedMetaData(const QString &key) const +{ + Q_D(const QMediaRecorder); + + return d->metaDataControl + ? d->metaDataControl->extendedMetaData(key) + : QVariant(); +} + +/*! + Sets a \a value for a meta-data \a key. + + The naming and type of extended meta-data is not standardized, so the values and meaning + of keys may vary between backends. + \since 1.0 +*/ +void QMediaRecorder::setExtendedMetaData(const QString &key, const QVariant &value) +{ + Q_D(QMediaRecorder); + + if (d->metaDataControl) + d->metaDataControl->setExtendedMetaData(key, value); +} + +/*! + Returns a list of keys there is extended meta-data available for. + \since 1.0 +*/ +QStringList QMediaRecorder::availableExtendedMetaData() const +{ + Q_D(const QMediaRecorder); + + return d->metaDataControl + ? d->metaDataControl->availableExtendedMetaData() + : QStringList(); +} + +#include "moc_qmediarecorder.cpp" +QT_END_NAMESPACE + diff --git a/src/multimedia/qmediarecorder.h b/src/multimedia/qmediarecorder.h new file mode 100644 index 000000000..fbd47ddde --- /dev/null +++ b/src/multimedia/qmediarecorder.h @@ -0,0 +1,197 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMEDIARECORDER_H +#define QMEDIARECORDER_H + +#include <qmediaobject.h> +#include <qmediaserviceprovider.h> +#include <qmediaencodersettings.h> +#include <qmediabindableinterface.h> +#include <qmediaenumdebug.h> + +#include <QtCore/qpair.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + +class QUrl; +class QSize; +class QAudioFormat; +QT_END_NAMESPACE + +QT_BEGIN_NAMESPACE + +class QMediaRecorderService; +class QAudioEncoderSettings; +class QVideoEncoderSettings; + +class QMediaRecorderPrivate; +class Q_MULTIMEDIA_EXPORT QMediaRecorder : public QObject, public QMediaBindableInterface +{ + Q_OBJECT + Q_INTERFACES(QMediaBindableInterface) + Q_ENUMS(State) + Q_ENUMS(Error) + Q_PROPERTY(qint64 duration READ duration NOTIFY durationChanged) + Q_PROPERTY(QUrl outputLocation READ outputLocation WRITE setOutputLocation) + Q_PROPERTY(bool muted READ isMuted WRITE setMuted NOTIFY mutedChanged) + Q_PROPERTY(bool metaDataAvailable READ isMetaDataAvailable NOTIFY metaDataAvailableChanged) + Q_PROPERTY(bool metaDataWritable READ isMetaDataWritable NOTIFY metaDataWritableChanged) +public: + + enum State + { + StoppedState, + RecordingState, + PausedState + }; + + enum Error + { + NoError, + ResourceError, + FormatError + }; + + QMediaRecorder(QMediaObject *mediaObject, QObject *parent = 0); + ~QMediaRecorder(); + + QMediaObject *mediaObject() const; + + bool isAvailable() const; + QtMultimedia::AvailabilityError availabilityError() const; + + QUrl outputLocation() const; + bool setOutputLocation(const QUrl &location); + + State state() const; + + Error error() const; + QString errorString() const; + + qint64 duration() const; + + bool isMuted() const; + + QStringList supportedContainers() const; + QString containerDescription(const QString &containerMimeType) const; + + QStringList supportedAudioCodecs() const; + QString audioCodecDescription(const QString &codecName) const; + + QList<int> supportedAudioSampleRates(const QAudioEncoderSettings &settings = QAudioEncoderSettings(), + bool *continuous = 0) const; + + QStringList supportedVideoCodecs() const; + QString videoCodecDescription(const QString &codecName) const; + + QList<QSize> supportedResolutions(const QVideoEncoderSettings &settings = QVideoEncoderSettings(), + bool *continuous = 0) const; + + QList<qreal> supportedFrameRates(const QVideoEncoderSettings &settings = QVideoEncoderSettings(), + bool *continuous = 0) const; + + QAudioEncoderSettings audioSettings() const; + QVideoEncoderSettings videoSettings() const; + QString containerMimeType() const; + + void setEncodingSettings(const QAudioEncoderSettings &audioSettings, + const QVideoEncoderSettings &videoSettings = QVideoEncoderSettings(), + const QString &containerMimeType = QString()); + + + bool isMetaDataAvailable() const; + bool isMetaDataWritable() const; + + QVariant metaData(QtMultimedia::MetaData key) const; + void setMetaData(QtMultimedia::MetaData key, const QVariant &value); + QList<QtMultimedia::MetaData> availableMetaData() const; + + QVariant extendedMetaData(const QString &key) const; + void setExtendedMetaData(const QString &key, const QVariant &value); + QStringList availableExtendedMetaData() const; + +public Q_SLOTS: + void record(); + void pause(); + void stop(); + void setMuted(bool muted); + +Q_SIGNALS: + void stateChanged(QMediaRecorder::State state); + void durationChanged(qint64 duration); + void mutedChanged(bool muted); + + void error(QMediaRecorder::Error error); + + void metaDataAvailableChanged(bool available); + void metaDataWritableChanged(bool writable); + void metaDataChanged(); + +protected: + bool setMediaObject(QMediaObject *object); + +private: + QMediaRecorderPrivate *d_ptr; + Q_DISABLE_COPY(QMediaRecorder) + Q_DECLARE_PRIVATE(QMediaRecorder) + Q_PRIVATE_SLOT(d_func(), void _q_stateChanged(QMediaRecorder::State)) + Q_PRIVATE_SLOT(d_func(), void _q_error(int, const QString &)) + Q_PRIVATE_SLOT(d_func(), void _q_serviceDestroyed()) + Q_PRIVATE_SLOT(d_func(), void _q_notify()) + Q_PRIVATE_SLOT(d_func(), void _q_updateNotifyInterval(int)) +}; + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(QMediaRecorder::State) +Q_DECLARE_METATYPE(QMediaRecorder::Error) + +Q_MEDIA_ENUM_DEBUG(QMediaRecorder, State) +Q_MEDIA_ENUM_DEBUG(QMediaRecorder, Error) + +QT_END_HEADER + +#endif // QMEDIARECORDER_H diff --git a/src/multimedia/qmediarecordercontrol.cpp b/src/multimedia/qmediarecordercontrol.cpp new file mode 100644 index 000000000..ffc51021b --- /dev/null +++ b/src/multimedia/qmediarecordercontrol.cpp @@ -0,0 +1,209 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmediarecordercontrol.h" + +QT_BEGIN_NAMESPACE + + +/*! + \class QMediaRecorderControl + \inmodule QtMultimedia + \ingroup multimedia-serv + \since 1.0 + + + \brief The QMediaRecorderControl class provides access to the recording + functionality of a QMediaService. + + If a QMediaService can record media it will implement QMediaRecorderControl. + This control provides a means to set the \l {outputLocation()}{output location}, + and \l {record()}{start}, \l {pause()}{pause} and \l {stop()}{stop} + recording. It also provides feedback on the \l {duration()}{duration} + of the recording. + + The functionality provided by this control is exposed to application + code through the QMediaRecorder class. + + The interface name of QMediaRecorderControl is \c com.nokia.Qt.QMediaRecorderControl/1.0 as + defined in QMediaRecorderControl_iid. + + \sa QMediaService::requestControl(), QMediaRecorder + +*/ + +/*! + \macro QMediaRecorderControl_iid + + \c com.nokia.Qt.QMediaRecorderControl/1.0 + + Defines the interface name of the QMediaRecorderControl class. + + \relates QMediaRecorderControl +*/ + +/*! + Constructs a media recorder control with the given \a parent. +*/ + +QMediaRecorderControl::QMediaRecorderControl(QObject* parent) + : QMediaControl(parent) +{ +} + +/*! + Destroys a media recorder control. +*/ + +QMediaRecorderControl::~QMediaRecorderControl() +{ +} + +/*! + \fn QUrl QMediaRecorderControl::outputLocation() const + + Returns the current output location being used. + \since 1.0 +*/ + +/*! + \fn bool QMediaRecorderControl::setOutputLocation(const QUrl &location) + + Sets the output \a location and returns if this operation is successful. + If file at the output location already exists, it should be overwritten. + + The \a location can be relative or empty; + in this case the service should use the system specific place and file naming scheme. + After recording has stated, QMediaRecorderControl::outputLocation() should return the actual output location. + \since 1.0 +*/ + +/*! + \fn int QMediaRecorderControl::state() const + + Return the current recording state. + \since 1.0 +*/ + +/*! + \fn qint64 QMediaRecorderControl::duration() const + + Return the current duration in milliseconds. + \since 1.0 +*/ + +/*! + \fn void QMediaRecorderControl::record() + + Start recording. + \since 1.0 +*/ + +/*! + \fn void QMediaRecorderControl::pause() + + Pause recording. + \since 1.0 +*/ + +/*! + \fn void QMediaRecorderControl::stop() + + Stop recording. + \since 1.0 +*/ + +/*! + \fn void QMediaRecorderControl::applySettings() + + Commits the encoder settings and performs pre-initialization to reduce delays when recording + is started. + \since 1.0 +*/ + +/*! + \fn bool QMediaRecorderControl::isMuted() const + + Returns true if the recorder is muted, and false if it is not. + \since 1.0 +*/ + +/*! + \fn void QMediaRecorderControl::setMuted(bool muted) + + Sets the \a muted state of a media recorder. + \since 1.0 +*/ + + +/*! + \fn void QMediaRecorderControl::stateChanged(QMediaRecorder::State state) + + Signals that the \a state of a media recorder has changed. + \since 1.0 +*/ + +/*! + \fn void QMediaRecorderControl::durationChanged(qint64 duration) + + Signals that the \a duration of the recorded media has changed. + + This only emitted when there is a discontinuous change in the duration such as being reset to 0. + \since 1.0 +*/ + +/*! + \fn void QMediaRecorderControl::mutedChanged(bool muted) + + Signals that the \a muted state of a media recorder has changed. + \since 1.0 +*/ + +/*! + \fn void QMediaRecorderControl::error(int error, const QString &errorString) + + Signals that an \a error has occurred. The \a errorString describes the error. + \since 1.0 +*/ + +#include "moc_qmediarecordercontrol.cpp" +QT_END_NAMESPACE + diff --git a/src/multimedia/qmediarecordercontrol.h b/src/multimedia/qmediarecordercontrol.h new file mode 100644 index 000000000..26f244c08 --- /dev/null +++ b/src/multimedia/qmediarecordercontrol.h @@ -0,0 +1,101 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMEDIARECORDERCONTROL_H +#define QMEDIARECORDERCONTROL_H + +#include "qmediacontrol.h" +#include "qmediarecorder.h" + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + +class QUrl; +QT_END_NAMESPACE + +QT_BEGIN_NAMESPACE + +class Q_MULTIMEDIA_EXPORT QMediaRecorderControl : public QMediaControl +{ + Q_OBJECT + +public: + virtual ~QMediaRecorderControl(); + + virtual QUrl outputLocation() const = 0; + virtual bool setOutputLocation(const QUrl &location) = 0; + + virtual QMediaRecorder::State state() const = 0; + + virtual qint64 duration() const = 0; + + virtual bool isMuted() const = 0; + + virtual void applySettings() = 0; + +Q_SIGNALS: + void stateChanged(QMediaRecorder::State state); + void durationChanged(qint64 position); + void mutedChanged(bool muted); + void error(int error, const QString &errorString); + +public Q_SLOTS: + virtual void record() = 0; + virtual void pause() = 0; + virtual void stop() = 0; + virtual void setMuted(bool muted) = 0; + +protected: + QMediaRecorderControl(QObject* parent = 0); +}; + +#define QMediaRecorderControl_iid "com.nokia.Qt.QMediaRecorderControl/1.0" +Q_MEDIA_DECLARE_CONTROL(QMediaRecorderControl, QMediaRecorderControl_iid) + +QT_END_NAMESPACE + +QT_END_HEADER + + +#endif diff --git a/src/multimedia/qmediaresource.cpp b/src/multimedia/qmediaresource.cpp new file mode 100644 index 000000000..a80168830 --- /dev/null +++ b/src/multimedia/qmediaresource.cpp @@ -0,0 +1,440 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmediaresource.h" + +#include <QtCore/qsize.h> +#include <QtCore/qurl.h> +#include <QtCore/qvariant.h> + +QT_BEGIN_NAMESPACE + +/*! + \class QMediaResource + + \brief The QMediaResource class provides a description of a media resource. + \inmodule QtMultimedia + \ingroup multimedia + \since 1.0 + + A media resource is composed of a \l {url()}{URL} containing the + location of the resource and a set of properties that describe the + format of the resource. The properties provide a means to assess a + resource without first attempting to load it, and in situations where + media be represented by multiple alternative representations provide a + means to select the appropriate resource. + + Media made available by a remote services can often be available in + multiple encodings or quality levels, this allows a client to select + an appropriate resource based on considerations such as codecs supported, + network bandwidth, and display constraints. QMediaResource includes + information such as the \l {mimeType()}{MIME type}, \l {audioCodec()}{audio} + and \l {videoCodec()}{video} codecs, \l {audioBitRate()}{audio} and + \l {videoBitRate()}{video} bit rates, and \l {resolution()}{resolution} + so these constraints and others can be evaluated. + + The only mandatory property of a QMediaResource is the url(). + + \sa QMediaContent +*/ + +/*! + \typedef QMediaResourceList + + Synonym for \c QList<QMediaResource> +*/ + +/*! + Constructs a null media resource. +*/ +QMediaResource::QMediaResource() +{ +} + +/*! + Constructs a media resource with the given \a mimeType from a \a url. + \since 1.0 +*/ +QMediaResource::QMediaResource(const QUrl &url, const QString &mimeType) +{ + values.insert(Url, url); + values.insert(MimeType, mimeType); +} + +/*! + Constructs a media resource with the given \a mimeType from a network \a request. + \since 1.0 +*/ +QMediaResource::QMediaResource(const QNetworkRequest &request, const QString &mimeType) +{ + values.insert(Request, QVariant::fromValue(request)); + values.insert(Url, request.url()); + values.insert(MimeType, mimeType); +} + +/*! + Constructs a copy of a media resource \a other. + \since 1.0 +*/ +QMediaResource::QMediaResource(const QMediaResource &other) + : values(other.values) +{ +} + +/*! + Assigns the value of \a other to a media resource. + \since 1.0 +*/ +QMediaResource &QMediaResource::operator =(const QMediaResource &other) +{ + values = other.values; + + return *this; +} + +/*! + Destroys a media resource. +*/ +QMediaResource::~QMediaResource() +{ +} + + +/*! + Compares a media resource to \a other. + + Returns true if the resources are identical, and false otherwise. + \since 1.0 +*/ +bool QMediaResource::operator ==(const QMediaResource &other) const +{ + // Compare requests directly as QNetworkRequests are "custom types". + foreach (int key, values.keys()) { + switch (key) { + case Request: + if (request() != other.request()) + return false; + break; + default: + if (values.value(key) != other.values.value(key)) + return false; + } + } + return true; +} + +/*! + Compares a media resource to \a other. + + Returns true if they are different, and false otherwise. + \since 1.0 +*/ +bool QMediaResource::operator !=(const QMediaResource &other) const +{ + return !(*this == other); +} + +/*! + Identifies if a media resource is null. + + Returns true if the resource is null, and false otherwise. + \since 1.0 +*/ +bool QMediaResource::isNull() const +{ + return values.isEmpty(); +} + +/*! + Returns the URL of a media resource. + \since 1.0 +*/ +QUrl QMediaResource::url() const +{ + return qvariant_cast<QUrl>(values.value(Url)); +} + +/*! + Returns the network request associated with this media resource. + \since 1.0 +*/ +QNetworkRequest QMediaResource::request() const +{ + if(values.contains(Request)) + return qvariant_cast<QNetworkRequest>(values.value(Request)); + + return QNetworkRequest(url()); +} + +/*! + Returns the MIME type of a media resource. + + This may be null if the MIME type is unknown. + \since 1.0 +*/ +QString QMediaResource::mimeType() const +{ + return qvariant_cast<QString>(values.value(MimeType)); +} + +/*! + Returns the language of a media resource as an ISO 639-2 code. + + This may be null if the language is unknown. + \since 1.0 +*/ +QString QMediaResource::language() const +{ + return qvariant_cast<QString>(values.value(Language)); +} + +/*! + Sets the \a language of a media resource. + \since 1.0 +*/ +void QMediaResource::setLanguage(const QString &language) +{ + if (!language.isNull()) + values.insert(Language, language); + else + values.remove(Language); +} + +/*! + Returns the audio codec of a media resource. + + This may be null if the media resource does not contain an audio stream, or the codec is + unknown. + \since 1.0 +*/ +QString QMediaResource::audioCodec() const +{ + return qvariant_cast<QString>(values.value(AudioCodec)); +} + +/*! + Sets the audio \a codec of a media resource. + \since 1.0 +*/ +void QMediaResource::setAudioCodec(const QString &codec) +{ + if (!codec.isNull()) + values.insert(AudioCodec, codec); + else + values.remove(AudioCodec); +} + +/*! + Returns the video codec of a media resource. + + This may be null if the media resource does not contain a video stream, or the codec is + unknonwn. + \since 1.0 +*/ +QString QMediaResource::videoCodec() const +{ + return qvariant_cast<QString>(values.value(VideoCodec)); +} + +/*! + Sets the video \a codec of media resource. + \since 1.0 +*/ +void QMediaResource::setVideoCodec(const QString &codec) +{ + if (!codec.isNull()) + values.insert(VideoCodec, codec); + else + values.remove(VideoCodec); +} + +/*! + Returns the size in bytes of a media resource. + + This may be zero if the size is unknown. + \since 1.0 +*/ +qint64 QMediaResource::dataSize() const +{ + return qvariant_cast<qint64>(values.value(DataSize)); +} + +/*! + Sets the \a size in bytes of a media resource. + \since 1.0 +*/ +void QMediaResource::setDataSize(const qint64 size) +{ + if (size != 0) + values.insert(DataSize, size); + else + values.remove(DataSize); +} + +/*! + Returns the bit rate in bits per second of a media resource's audio stream. + + This may be zero if the bit rate is unknown, or the resource contains no audio stream. + \since 1.0 +*/ +int QMediaResource::audioBitRate() const +{ + return values.value(AudioBitRate).toInt(); +} + +/*! + Sets the bit \a rate in bits per second of a media resource's video stream. + \since 1.0 +*/ +void QMediaResource::setAudioBitRate(int rate) +{ + if (rate != 0) + values.insert(AudioBitRate, rate); + else + values.remove(AudioBitRate); +} + +/*! + Returns the audio sample rate of a media resource. + + This may be zero if the sample size is unknown, or the resource contains no audio stream. + \since 1.0 +*/ +int QMediaResource::sampleRate() const +{ + return qvariant_cast<int>(values.value(SampleRate)); +} + +/*! + Sets the audio \a sampleRate of a media resource. + \since 1.0 +*/ +void QMediaResource::setSampleRate(int sampleRate) +{ + if (sampleRate != 0) + values.insert(SampleRate, sampleRate); + else + values.remove(SampleRate); +} + +/*! + Returns the number of audio channels in a media resource. + + This may be zero if the sample size is unknown, or the resource contains no audio stream. + \since 1.0 +*/ +int QMediaResource::channelCount() const +{ + return qvariant_cast<int>(values.value(ChannelCount)); +} + +/*! + Sets the number of audio \a channels in a media resource. + \since 1.0 +*/ +void QMediaResource::setChannelCount(int channels) +{ + if (channels != 0) + values.insert(ChannelCount, channels); + else + values.remove(ChannelCount); +} + +/*! + Returns the bit rate in bits per second of a media resource's video stream. + + This may be zero if the bit rate is unknown, or the resource contains no video stream. + \since 1.0 +*/ +int QMediaResource::videoBitRate() const +{ + return values.value(VideoBitRate).toInt(); +} + +/*! + Sets the bit \a rate in bits per second of a media resource's video stream. + \since 1.0 +*/ +void QMediaResource::setVideoBitRate(int rate) +{ + if (rate != 0) + values.insert(VideoBitRate, rate); + else + values.remove(VideoBitRate); +} + +/*! + Returns the resolution in pixels of a media resource. + + This may be null is the resolution is unknown, or the resource contains no pixel data (i.e. the + resource is an audio stream. + \since 1.0 +*/ +QSize QMediaResource::resolution() const +{ + return qvariant_cast<QSize>(values.value(Resolution)); +} + +/*! + Sets the \a resolution in pixels of a media resource. + \since 1.0 +*/ +void QMediaResource::setResolution(const QSize &resolution) +{ + if (resolution.width() != -1 || resolution.height() != -1) + values.insert(Resolution, resolution); + else + values.remove(Resolution); +} + +/*! + Sets the \a width and \a height in pixels of a media resource. + \since 1.0 +*/ +void QMediaResource::setResolution(int width, int height) +{ + if (width != -1 || height != -1) + values.insert(Resolution, QSize(width, height)); + else + values.remove(Resolution); +} +QT_END_NAMESPACE + diff --git a/src/multimedia/qmediaresource.h b/src/multimedia/qmediaresource.h new file mode 100644 index 000000000..b06c61dcb --- /dev/null +++ b/src/multimedia/qmediaresource.h @@ -0,0 +1,134 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMEDIARESOURCE_H +#define QMEDIARESOURCE_H + +#include <QtCore/qmap.h> +#include <QtCore/qmetatype.h> +#include <QtNetwork/qnetworkrequest.h> + +#include <qtmultimediadefs.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + +class Q_MULTIMEDIA_EXPORT QMediaResource +{ +public: + QMediaResource(); + QMediaResource(const QUrl &url, const QString &mimeType = QString()); + QMediaResource(const QNetworkRequest &request, const QString &mimeType = QString()); + QMediaResource(const QMediaResource &other); + QMediaResource &operator =(const QMediaResource &other); + ~QMediaResource(); + + bool isNull() const; + + bool operator ==(const QMediaResource &other) const; + bool operator !=(const QMediaResource &other) const; + + QUrl url() const; + QNetworkRequest request() const; + QString mimeType() const; + + QString language() const; + void setLanguage(const QString &language); + + QString audioCodec() const; + void setAudioCodec(const QString &codec); + + QString videoCodec() const; + void setVideoCodec(const QString &codec); + + qint64 dataSize() const; + void setDataSize(const qint64 size); + + int audioBitRate() const; + void setAudioBitRate(int rate); + + int sampleRate() const; + void setSampleRate(int frequency); + + int channelCount() const; + void setChannelCount(int channels); + + int videoBitRate() const; + void setVideoBitRate(int rate); + + QSize resolution() const; + void setResolution(const QSize &resolution); + void setResolution(int width, int height); + + +private: + enum Property + { + Url, + Request, + MimeType, + Language, + AudioCodec, + VideoCodec, + DataSize, + AudioBitRate, + VideoBitRate, + SampleRate, + ChannelCount, + Resolution + }; + QMap<int, QVariant> values; +}; + +typedef QList<QMediaResource> QMediaResourceList; + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(QMediaResource) +Q_DECLARE_METATYPE(QMediaResourceList) + +QT_END_HEADER + +#endif diff --git a/src/multimedia/qmediaservice.cpp b/src/multimedia/qmediaservice.cpp new file mode 100644 index 000000000..d97b3613c --- /dev/null +++ b/src/multimedia/qmediaservice.cpp @@ -0,0 +1,151 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmediaservice.h" +#include "qmediaservice_p.h" + +#include <QtCore/qtimer.h> + + + +QT_BEGIN_NAMESPACE + + +/*! + \class QMediaService + \brief The QMediaService class provides a common base class for media + service implementations. + \inmodule QtMultimedia + \ingroup multimedia-serv + \since 1.0 + + + Media services provide implementations of the functionality promised + by media objects, and allow multiple providers to implement a QMediaObject. + + To provide the functionality of a QMediaObject media services implement + QMediaControl interfaces. Services typically implement one core media + control which provides the core feature of a media object, and some + number of additional controls which provide either optional features of + the media object, or features of a secondary media object or peripheral + object. + + A pointer to media service's QMediaControl implementation can be obtained + by passing the control's interface name to the requestControl() function. + + \snippet doc/src/snippets/multimedia-snippets/media.cpp Request control + + Media objects can use services loaded dynamically from plug-ins or + implemented statically within an applications. Plug-in based services + should also implement the QMediaServiceProviderPlugin interface. Static + services should implement the QMediaServiceProvider interface. + + \sa QMediaObject, QMediaControl, QMediaServiceProvider, QMediaServiceProviderPlugin +*/ + +/*! + Construct a media service with the given \a parent. This class is meant as a + base class for Multimedia services so this constructor is protected. +*/ + +QMediaService::QMediaService(QObject *parent) + : QObject(parent) + , d_ptr(new QMediaServicePrivate) +{ + d_ptr->q_ptr = this; +} + +/*! + \internal +*/ +QMediaService::QMediaService(QMediaServicePrivate &dd, QObject *parent) + : QObject(parent) + , d_ptr(&dd) +{ + d_ptr->q_ptr = this; +} + +/*! + Destroys a media service. +*/ + +QMediaService::~QMediaService() +{ + delete d_ptr; +} + +/*! + \fn QMediaControl* QMediaService::requestControl(const char *interface) + + Returns a pointer to the media control implementing \a interface. + + 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. + \since 1.0 +*/ + +/*! + \fn T QMediaService::requestControl() + + Returns a pointer to the media control of type T implemented by a media service. + + 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. + \since 1.0 +*/ + +/*! + \fn void QMediaService::releaseControl(QMediaControl *control); + + Releases a \a control back to the service. + \since 1.0 +*/ + +#include "moc_qmediaservice.cpp" + +QT_END_NAMESPACE + diff --git a/src/multimedia/qmediaservice.h b/src/multimedia/qmediaservice.h new file mode 100644 index 000000000..64aa7099f --- /dev/null +++ b/src/multimedia/qmediaservice.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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QABSTRACTMEDIASERVICE_H +#define QABSTRACTMEDIASERVICE_H + +#include <qtmultimediadefs.h> +#include <QtCore/qobject.h> +#include <QtCore/qstringlist.h> + +#include "qmediacontrol.h" + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + +class QMediaServicePrivate; +class Q_MULTIMEDIA_EXPORT QMediaService : public QObject +{ + Q_OBJECT + +public: + ~QMediaService(); + + virtual QMediaControl* requestControl(const char *name) = 0; + +#ifndef QT_NO_MEMBER_TEMPLATES + template <typename T> inline T requestControl() { + if (QMediaControl *control = requestControl(qmediacontrol_iid<T>())) { + if (T typedControl = qobject_cast<T>(control)) + return typedControl; + releaseControl(control); + } + return 0; + } +#endif + + virtual void releaseControl(QMediaControl *control) = 0; + +protected: + QMediaService(QObject* parent); + QMediaService(QMediaServicePrivate &dd, QObject *parent); + + QMediaServicePrivate *d_ptr; + +private: + Q_DECLARE_PRIVATE(QMediaService) +}; + +QT_END_NAMESPACE + +QT_END_HEADER + + +#endif // QABSTRACTMEDIASERVICE_H + diff --git a/src/multimedia/qmediaservice_p.h b/src/multimedia/qmediaservice_p.h new file mode 100644 index 000000000..83fd7287f --- /dev/null +++ b/src/multimedia/qmediaservice_p.h @@ -0,0 +1,80 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QABSTRACTMEDIASERVICE_P_H +#define QABSTRACTMEDIASERVICE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + +class QAudioDeviceControl; + +class QMediaServicePrivate +{ +public: + QMediaServicePrivate(): q_ptr(0) {} + virtual ~QMediaServicePrivate() {} + + QMediaService *q_ptr; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + + + +#endif diff --git a/src/multimedia/qmediaserviceprovider.cpp b/src/multimedia/qmediaserviceprovider.cpp new file mode 100644 index 000000000..0017349c4 --- /dev/null +++ b/src/multimedia/qmediaserviceprovider.cpp @@ -0,0 +1,783 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtCore/qdebug.h> +#include <QtCore/qmap.h> + +#include "qmediaservice.h" +#include "qmediaserviceprovider.h" +#include "qmediaserviceproviderplugin.h" +#include "qmediapluginloader_p.h" +#include "qmediaplayer.h" + +QT_BEGIN_NAMESPACE + +class QMediaServiceProviderHintPrivate : public QSharedData +{ +public: + QMediaServiceProviderHintPrivate(QMediaServiceProviderHint::Type type) + :type(type), features(0) + { + } + + QMediaServiceProviderHintPrivate(const QMediaServiceProviderHintPrivate &other) + :QSharedData(other), + type(other.type), + device(other.device), + mimeType(other.mimeType), + codecs(other.codecs), + features(other.features) + { + } + + ~QMediaServiceProviderHintPrivate() + { + } + + QMediaServiceProviderHint::Type type; + QByteArray device; + QString mimeType; + QStringList codecs; + QMediaServiceProviderHint::Features features; +}; + +/*! + \class QMediaServiceProviderHint + + \brief The QMediaServiceProviderHint class describes what is required of a QMediaService. + + \inmodule QtMultimedia + \ingroup multimedia-serv + \since 1.0 + + The QMediaServiceProvider class uses hints to select an appropriate media service. +*/ + +/*! + \enum QMediaServiceProviderHint::Feature + + Enumerates features a media service may provide. + + \value LowLatencyPlayback + The service is expected to play simple audio formats, + but playback should start without significant delay. + Such playback service can be used for beeps, ringtones, etc. + + \value RecordingSupport + The service provides audio or video recording functions. + + \value StreamPlayback + The service is capable of playing QIODevice based streams. + + \value VideoSurface + The service is capable of renderering to a QAbstractVideoSurface + output. + + \value BackgroundPlayback + The service is capable of doing playback in the background +*/ + +/*! + \enum QMediaServiceProviderHint::Type + + Enumerates the possible types of media service provider hint. + + \value Null En empty hint, use the default service. + \value ContentType Select media service most suitable for certain content type. + \value Device Select media service which supports certain device. + \value SupportedFeatures Select media service supporting the set of optional features. +*/ + + +/*! + Constructs an empty media service provider hint. +*/ +QMediaServiceProviderHint::QMediaServiceProviderHint() + :d(new QMediaServiceProviderHintPrivate(Null)) +{ +} + +/*! + Constructs a ContentType media service provider hint. + + This type of hint describes a service that is able to play content of a specific MIME \a type + encoded with one or more of the listed \a codecs. + \since 1.0 +*/ +QMediaServiceProviderHint::QMediaServiceProviderHint(const QString &type, const QStringList& codecs) + :d(new QMediaServiceProviderHintPrivate(ContentType)) +{ + d->mimeType = type; + d->codecs = codecs; +} + +/*! + Constructs a Device media service provider hint. + + This type of hint describes a media service that utilizes a specific \a device. + \since 1.0 +*/ +QMediaServiceProviderHint::QMediaServiceProviderHint(const QByteArray &device) + :d(new QMediaServiceProviderHintPrivate(Device)) +{ + d->device = device; +} + +/*! + Constructs a SupportedFeatures media service provider hint. + + This type of hint describes a service which supports a specific set of \a features. + \since 1.0 +*/ +QMediaServiceProviderHint::QMediaServiceProviderHint(QMediaServiceProviderHint::Features features) + :d(new QMediaServiceProviderHintPrivate(SupportedFeatures)) +{ + d->features = features; +} + +/*! + Constructs a copy of the media service provider hint \a other. + \since 1.0 +*/ +QMediaServiceProviderHint::QMediaServiceProviderHint(const QMediaServiceProviderHint &other) + :d(other.d) +{ +} + +/*! + Destroys a media service provider hint. +*/ +QMediaServiceProviderHint::~QMediaServiceProviderHint() +{ +} + +/*! + Assigns the value \a other to a media service provider hint. + \since 1.0 +*/ +QMediaServiceProviderHint& QMediaServiceProviderHint::operator=(const QMediaServiceProviderHint &other) +{ + d = other.d; + return *this; +} + +/*! + Identifies if \a other is of equal value to a media service provider hint. + + Returns true if the hints are equal, and false if they are not. + \since 1.0 +*/ +bool QMediaServiceProviderHint::operator == (const QMediaServiceProviderHint &other) const +{ + return (d == other.d) || + (d->type == other.d->type && + d->device == other.d->device && + d->mimeType == other.d->mimeType && + d->codecs == other.d->codecs && + d->features == other.d->features); +} + +/*! + Identifies if \a other is not of equal value to a media service provider hint. + + Returns true if the hints are not equal, and false if they are. + \since 1.0 +*/ +bool QMediaServiceProviderHint::operator != (const QMediaServiceProviderHint &other) const +{ + return !(*this == other); +} + +/*! + Returns true if a media service provider is null. + \since 1.0 +*/ +bool QMediaServiceProviderHint::isNull() const +{ + return d->type == Null; +} + +/*! + Returns the type of a media service provider hint. + \since 1.0 +*/ +QMediaServiceProviderHint::Type QMediaServiceProviderHint::type() const +{ + return d->type; +} + +/*! + Returns the mime type of the media a service is expected to be able play. + \since 1.0 +*/ +QString QMediaServiceProviderHint::mimeType() const +{ + return d->mimeType; +} + +/*! + Returns a list of codes a media service is expected to be able to decode. + \since 1.0 +*/ +QStringList QMediaServiceProviderHint::codecs() const +{ + return d->codecs; +} + +/*! + Returns the name of a device a media service is expected to utilize. + \since 1.0 +*/ +QByteArray QMediaServiceProviderHint::device() const +{ + return d->device; +} + +/*! + Returns a set of features a media service is expected to provide. + \since 1.0 +*/ +QMediaServiceProviderHint::Features QMediaServiceProviderHint::features() const +{ + return d->features; +} + + +Q_GLOBAL_STATIC_WITH_ARGS(QMediaPluginLoader, loader, + (QMediaServiceProviderFactoryInterface_iid, QLatin1String("mediaservice"), Qt::CaseInsensitive)) + + +class QPluginServiceProvider : public QMediaServiceProvider +{ + QMap<QMediaService*, QMediaServiceProviderPlugin*> pluginMap; + +public: + QMediaService* requestService(const QByteArray &type, const QMediaServiceProviderHint &hint) + { + QString key(QLatin1String(type.constData())); + + QList<QMediaServiceProviderPlugin *>plugins; + foreach (QObject *obj, loader()->instances(key)) { + QMediaServiceProviderPlugin *plugin = + qobject_cast<QMediaServiceProviderPlugin*>(obj); + if (plugin) + plugins << plugin; + } + + if (!plugins.isEmpty()) { + QMediaServiceProviderPlugin *plugin = 0; + + switch (hint.type()) { + case QMediaServiceProviderHint::Null: + plugin = plugins[0]; + //special case for media player, if low latency was not asked, + //prefer services not offering it, since they are likely to support + //more formats + if (type == QByteArray(Q_MEDIASERVICE_MEDIAPLAYER)) { + foreach (QMediaServiceProviderPlugin *currentPlugin, plugins) { + QMediaServiceFeaturesInterface *iface = + qobject_cast<QMediaServiceFeaturesInterface*>(currentPlugin); + + if (!iface || !(iface->supportedFeatures(type) & + QMediaServiceProviderHint::LowLatencyPlayback)) { + plugin = currentPlugin; + break; + } + + } + } + break; + case QMediaServiceProviderHint::SupportedFeatures: + plugin = plugins[0]; + foreach (QMediaServiceProviderPlugin *currentPlugin, plugins) { + QMediaServiceFeaturesInterface *iface = + qobject_cast<QMediaServiceFeaturesInterface*>(currentPlugin); + + if (iface) { + if ((iface->supportedFeatures(type) & hint.features()) == hint.features()) { + plugin = currentPlugin; + break; + } + } + } + break; + case QMediaServiceProviderHint::Device: { + foreach (QMediaServiceProviderPlugin *currentPlugin, plugins) { + QMediaServiceSupportedDevicesInterface *iface = + qobject_cast<QMediaServiceSupportedDevicesInterface*>(currentPlugin); + + if (!iface) { + // the plugin may support the device, + // but this choice still can be overridden + plugin = currentPlugin; + } else { + if (iface->devices(type).contains(hint.device())) { + plugin = currentPlugin; + break; + } + } + } + } + break; + case QMediaServiceProviderHint::ContentType: { + QtMultimedia::SupportEstimate estimate = QtMultimedia::NotSupported; + foreach (QMediaServiceProviderPlugin *currentPlugin, plugins) { + QtMultimedia::SupportEstimate currentEstimate = QtMultimedia::MaybeSupported; + QMediaServiceSupportedFormatsInterface *iface = + qobject_cast<QMediaServiceSupportedFormatsInterface*>(currentPlugin); + + if (iface) + currentEstimate = iface->hasSupport(hint.mimeType(), hint.codecs()); + + if (currentEstimate > estimate) { + estimate = currentEstimate; + plugin = currentPlugin; + + if (currentEstimate == QtMultimedia::PreferredService) + break; + } + } + } + break; + } + + if (plugin != 0) { + QMediaService *service = plugin->create(key); + if (service != 0) + pluginMap.insert(service, plugin); + + return service; + } + } + + qWarning() << "defaultServiceProvider::requestService(): no service found for -" << key; + return 0; + } + + void releaseService(QMediaService *service) + { + if (service != 0) { + QMediaServiceProviderPlugin *plugin = pluginMap.take(service); + + if (plugin != 0) + plugin->release(service); + } + } + + QtMultimedia::SupportEstimate hasSupport(const QByteArray &serviceType, + const QString &mimeType, + const QStringList& codecs, + int flags) const + { + QList<QObject*> instances = loader()->instances(QLatin1String(serviceType)); + + if (instances.isEmpty()) + return QtMultimedia::NotSupported; + + bool allServicesProvideInterface = true; + QtMultimedia::SupportEstimate supportEstimate = QtMultimedia::NotSupported; + + foreach(QObject *obj, instances) { + QMediaServiceSupportedFormatsInterface *iface = + qobject_cast<QMediaServiceSupportedFormatsInterface*>(obj); + + + if (flags) { + QMediaServiceFeaturesInterface *iface = + qobject_cast<QMediaServiceFeaturesInterface*>(obj); + + if (iface) { + QMediaServiceProviderHint::Features features = iface->supportedFeatures(serviceType); + + //if low latency playback was asked, skip services known + //not to provide low latency playback + if ((flags & QMediaPlayer::LowLatency) && + !(features & QMediaServiceProviderHint::LowLatencyPlayback)) + continue; + + //the same for QIODevice based streams support + if ((flags & QMediaPlayer::StreamPlayback) && + !(features & QMediaServiceProviderHint::StreamPlayback)) + continue; + } + } + + if (iface) + supportEstimate = qMax(supportEstimate, iface->hasSupport(mimeType, codecs)); + else + allServicesProvideInterface = false; + } + + //don't return PreferredService + supportEstimate = qMin(supportEstimate, QtMultimedia::ProbablySupported); + + //Return NotSupported only if no services are available of serviceType + //or all the services returned NotSupported, otherwise return at least MaybeSupported + if (!allServicesProvideInterface) + supportEstimate = qMax(QtMultimedia::MaybeSupported, supportEstimate); + + return supportEstimate; + } + + QStringList supportedMimeTypes(const QByteArray &serviceType, int flags) const + { + QList<QObject*> instances = loader()->instances(QLatin1String(serviceType)); + + QStringList supportedTypes; + + foreach(QObject *obj, instances) { + QMediaServiceSupportedFormatsInterface *iface = + qobject_cast<QMediaServiceSupportedFormatsInterface*>(obj); + + + if (flags) { + QMediaServiceFeaturesInterface *iface = + qobject_cast<QMediaServiceFeaturesInterface*>(obj); + + if (iface) { + QMediaServiceProviderHint::Features features = iface->supportedFeatures(serviceType); + + // If low latency playback was asked for, skip MIME types from services known + // not to provide low latency playback + if ((flags & QMediaPlayer::LowLatency) && + !(features & QMediaServiceProviderHint::LowLatencyPlayback)) + continue; + + //the same for QIODevice based streams support + if ((flags & QMediaPlayer::StreamPlayback) && + !(features & QMediaServiceProviderHint::StreamPlayback)) + continue; + + //the same for QAbstractVideoSurface support + if ((flags & QMediaPlayer::VideoSurface) && + !(features & QMediaServiceProviderHint::VideoSurface)) + continue; + } + } + + if (iface) { + supportedTypes << iface->supportedMimeTypes(); + } + } + + // Multiple services may support the same MIME type + supportedTypes.removeDuplicates(); + + return supportedTypes; + } + + QList<QByteArray> devices(const QByteArray &serviceType) const + { + QList<QByteArray> res; + + foreach (QObject *obj, loader()->instances(QLatin1String(serviceType))) { + QMediaServiceSupportedDevicesInterface *iface = + qobject_cast<QMediaServiceSupportedDevicesInterface*>(obj); + + if (iface) { + res.append(iface->devices(serviceType)); + } + } + + return res; + } + + QString deviceDescription(const QByteArray &serviceType, const QByteArray &device) + { + foreach (QObject *obj, loader()->instances(QLatin1String(serviceType))) { + QMediaServiceSupportedDevicesInterface *iface = + qobject_cast<QMediaServiceSupportedDevicesInterface*>(obj); + + if (iface) { + if (iface->devices(serviceType).contains(device)) + return iface->deviceDescription(serviceType, device); + } + } + + return QString(); + } +}; + +Q_GLOBAL_STATIC(QPluginServiceProvider, pluginProvider); + +/*! + \class QMediaServiceProvider + + \brief The QMediaServiceProvider class provides an abstract allocator for media services. + \since 1.0 +*/ + +/*! + \fn QMediaServiceProvider::requestService(const QByteArray &type, const QMediaServiceProviderHint &hint) + + Requests an instance of a \a type service which best matches the given \a + hint. + + Returns a pointer to the requested service, or a null pointer if there is + no suitable service. + + The returned service must be released with releaseService when it is + finished with. + \since 1.0 +*/ + +/*! + \fn QMediaServiceProvider::releaseService(QMediaService *service) + + Releases a media \a service requested with requestService(). + \since 1.0 +*/ + +/*! + \fn QtMultimedia::SupportEstimate QMediaServiceProvider::hasSupport(const QByteArray &serviceType, const QString &mimeType, const QStringList& codecs, int flags) const + + Returns how confident a media service provider is that is can provide a \a + serviceType service that is able to play media of a specific \a mimeType + that is encoded using the listed \a codecs while adhering to constraints + identified in \a flags. + \since 1.0 +*/ +QtMultimedia::SupportEstimate QMediaServiceProvider::hasSupport(const QByteArray &serviceType, + const QString &mimeType, + const QStringList& codecs, + int flags) const +{ + Q_UNUSED(serviceType); + Q_UNUSED(mimeType); + Q_UNUSED(codecs); + Q_UNUSED(flags); + + return QtMultimedia::MaybeSupported; +} + +/*! + \fn QStringList QMediaServiceProvider::supportedMimeTypes(const QByteArray &serviceType, int flags) const + + Returns a list of MIME types supported by the service provider for the + specified \a serviceType. + + The resultant list is restricted to MIME types which can be supported given + the constraints in \a flags. + \since 1.0 +*/ +QStringList QMediaServiceProvider::supportedMimeTypes(const QByteArray &serviceType, int flags) const +{ + Q_UNUSED(serviceType); + Q_UNUSED(flags); + + return QStringList(); +} + +/*! + Returns the list of devices related to \a service type. + \since 1.0 +*/ +QList<QByteArray> QMediaServiceProvider::devices(const QByteArray &service) const +{ + Q_UNUSED(service); + return QList<QByteArray>(); +} + +/*! + Returns the description of \a device related to \a serviceType, suitable for use by + an application for display. + \since 1.0 +*/ +QString QMediaServiceProvider::deviceDescription(const QByteArray &serviceType, const QByteArray &device) +{ + Q_UNUSED(serviceType); + Q_UNUSED(device); + return QString(); +} + + +#ifdef QT_BUILD_INTERNAL + +static QMediaServiceProvider *qt_defaultMediaServiceProvider = 0; + +/*! + Sets a media service \a provider as the default. + + \internal + \since 1.0 +*/ +void QMediaServiceProvider::setDefaultServiceProvider(QMediaServiceProvider *provider) +{ + qt_defaultMediaServiceProvider = provider; +} + +#endif + +/*! + Returns a default provider of media services. +*/ +QMediaServiceProvider *QMediaServiceProvider::defaultServiceProvider() +{ +#ifdef QT_BUILD_INTERNAL + return qt_defaultMediaServiceProvider != 0 + ? qt_defaultMediaServiceProvider + : static_cast<QMediaServiceProvider *>(pluginProvider()); +#else + return pluginProvider(); +#endif +} + +/*! + \class QMediaServiceProviderPlugin + + \brief The QMediaServiceProviderPlugin class interface provides an interface for QMediaService + plug-ins. + \since 1.0 + + A media service provider plug-in may implement one or more of + QMediaServiceSupportedFormatsInterface, + QMediaServiceSupportedDevicesInterface, and QMediaServiceFeaturesInterface + to identify the features it supports. +*/ + +/*! + \fn QMediaServiceProviderPlugin::keys() const + + Returns a list of keys for media services a plug-in can create. + \since 1.0 +*/ + +/*! + \fn QMediaServiceProviderPlugin::create(const QString &key) + + Constructs a new instance of the QMediaService identified by \a key. + + The QMediaService returned must be destroyed with release(). + \since 1.0 +*/ + +/*! + \fn QMediaServiceProviderPlugin::release(QMediaService *service) + + Destroys a media \a service constructed with create(). + \since 1.0 +*/ + + +/*! + \class QMediaServiceSupportedFormatsInterface + \brief The QMediaServiceSupportedFormatsInterface class interface + identifies if a media service plug-in supports a media format. + \since 1.0 + + A QMediaServiceProviderPlugin may implement this interface. +*/ + +/*! + \fn QMediaServiceSupportedFormatsInterface::~QMediaServiceSupportedFormatsInterface() + + Destroys a media service supported formats interface. +*/ + +/*! + \fn QMediaServiceSupportedFormatsInterface::hasSupport(const QString &mimeType, const QStringList& codecs) const + + Returns the level of support a media service plug-in has for a \a mimeType + and set of \a codecs. + \since 1.0 +*/ + +/*! + \fn QMediaServiceSupportedFormatsInterface::supportedMimeTypes() const + + Returns a list of MIME types supported by the media service plug-in. + \since 1.0 +*/ + +/*! + \class QMediaServiceSupportedDevicesInterface + \brief The QMediaServiceSupportedDevicesInterface class interface + identifies the devices supported by a media service plug-in. + \since 1.0 + + A QMediaServiceProviderPlugin may implement this interface. +*/ + +/*! + \fn QMediaServiceSupportedDevicesInterface::~QMediaServiceSupportedDevicesInterface() + + Destroys a media service supported devices interface. +*/ + +/*! + \fn QMediaServiceSupportedDevicesInterface::devices(const QByteArray &service) const + + Returns a list of devices supported by a plug-in \a service. + \since 1.0 +*/ + +/*! + \fn QMediaServiceSupportedDevicesInterface::deviceDescription(const QByteArray &service, const QByteArray &device) + + Returns a description of a \a device supported by a plug-in \a service. + \since 1.0 +*/ + +/*! + \class QMediaServiceFeaturesInterface + \brief The QMediaServiceFeaturesInterface class interface identifies + features supported by a media service plug-in. + \since 1.0 + + A QMediaServiceProviderPlugin may implement this interface. +*/ + +/*! + \fn QMediaServiceFeaturesInterface::~QMediaServiceFeaturesInterface() + + Destroys a media service features interface. +*/ +/*! + \fn QMediaServiceFeaturesInterface::supportedFeatures(const QByteArray &service) const + + Returns a set of features supported by a plug-in \a service. + \since 1.0 +*/ + +#include "moc_qmediaserviceprovider.cpp" +#include "moc_qmediaserviceproviderplugin.cpp" +QT_END_NAMESPACE + diff --git a/src/multimedia/qmediaserviceprovider.h b/src/multimedia/qmediaserviceprovider.h new file mode 100644 index 000000000..8ad2e2f6c --- /dev/null +++ b/src/multimedia/qmediaserviceprovider.h @@ -0,0 +1,186 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMEDIASERVICEPROVIDER_H +#define QMEDIASERVICEPROVIDER_H + +#include <QtCore/qobject.h> +#include <QtCore/qshareddata.h> +#include <qtmultimediadefs.h> +#include "qtmedianamespace.h" + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + +class QMediaService; + +class QMediaServiceProviderHintPrivate; +class Q_MULTIMEDIA_EXPORT QMediaServiceProviderHint +{ +public: + enum Type { Null, ContentType, Device, SupportedFeatures }; + + enum Feature { + LowLatencyPlayback = 0x01, + RecordingSupport = 0x02, + StreamPlayback = 0x04, + VideoSurface = 0x08, + BackgroundPlayback = 0x10, + }; + Q_DECLARE_FLAGS(Features, Feature) + + QMediaServiceProviderHint(); + QMediaServiceProviderHint(const QString &mimeType, const QStringList& codecs); + QMediaServiceProviderHint(const QByteArray &device); + QMediaServiceProviderHint(Features features); + QMediaServiceProviderHint(const QMediaServiceProviderHint &other); + ~QMediaServiceProviderHint(); + + QMediaServiceProviderHint& operator=(const QMediaServiceProviderHint &other); + + bool operator == (const QMediaServiceProviderHint &other) const; + bool operator != (const QMediaServiceProviderHint &other) const; + + bool isNull() const; + + Type type() const; + + QString mimeType() const; + QStringList codecs() const; + + QByteArray device() const; + + Features features() const; + + //to be extended, if necessary + +private: + QSharedDataPointer<QMediaServiceProviderHintPrivate> d; +}; + +Q_DECLARE_OPERATORS_FOR_FLAGS(QMediaServiceProviderHint::Features) + +class Q_MULTIMEDIA_EXPORT QMediaServiceProvider : public QObject +{ + Q_OBJECT + +public: + virtual QMediaService* requestService(const QByteArray &type, const QMediaServiceProviderHint &hint = QMediaServiceProviderHint()) = 0; + virtual void releaseService(QMediaService *service) = 0; + + virtual QtMultimedia::SupportEstimate hasSupport(const QByteArray &serviceType, + const QString &mimeType, + const QStringList& codecs, + int flags = 0) const; + virtual QStringList supportedMimeTypes(const QByteArray &serviceType, int flags = 0) const; + + virtual QList<QByteArray> devices(const QByteArray &serviceType) const; + virtual QString deviceDescription(const QByteArray &serviceType, const QByteArray &device); + + static QMediaServiceProvider* defaultServiceProvider(); + +#ifdef QT_BUILD_INTERNAL + static void setDefaultServiceProvider(QMediaServiceProvider *provider); +#endif +}; + +/*! + Service with support for media playback + Required Controls: QMediaPlayerControl + Optional Controls: QMediaPlaylistControl, QAudioDeviceControl + Video Output Controls (used by QWideoWidget and QGraphicsVideoItem): + Required: QVideoOutputControl + Optional: QVideoWindowControl, QVideoRendererControl, QVideoWidgetControl +*/ +#define Q_MEDIASERVICE_MEDIAPLAYER "com.nokia.qt.mediaplayer" + +/*! + Service with support for background media playback + Required Controls: QMediaPlayerControl, QMediaBackgroundPlaybackControl + Optional Controls: QMediaPlaylistControl, QAudioDeviceControl +*/ +#define Q_MEDIASERVICE_BACKGROUNDMEDIAPLAYER "com.nokia.qt.backgroundmediaplayer" + +/*! + Service with support for recording from audio sources + Required Controls: QAudioDeviceControl + Recording Controls (QMediaRecorder): + Required: QMediaRecorderControl + Recommended: QAudioEncoderControl + Optional: QMediaContainerControl +*/ +#define Q_MEDIASERVICE_AUDIOSOURCE "com.nokia.qt.audiosource" + +/*! + Service with support for camera use. + Required Controls: QCameraControl + Optional Controls: QCameraExposureControl, QCameraFocusControl, QCameraImageProcessingControl + Still Capture Controls: QCameraImageCaptureControl + Video Capture Controls (QMediaRecorder): + Required: QMediaRecorderControl + Recommended: QAudioEncoderControl, QVideoEncoderControl, QMediaContainerControl + Viewfinder Video Output Controls (used by QCameraViewfinder and QGraphicsVideoItem): + Required: QVideoOutputControl + Optional: QVideoWindowControl, QVideoRendererControl, QVideoWidgetControl +*/ +#define Q_MEDIASERVICE_CAMERA "com.nokia.qt.camera" + +/*! + Service with support for radio tuning. + Required Controls: QRadioTunerControl + Recording Controls (Optional, used by QMediaRecorder): + Required: QMediaRecorderControl + Recommended: QAudioEncoderControl + Optional: QMediaContainerControl +*/ +#define Q_MEDIASERVICE_RADIO "com.nokia.qt.radio" + + +QT_END_NAMESPACE + +QT_END_HEADER + + +#endif // QMEDIASERVICEPROVIDER_H diff --git a/src/multimedia/qmediaserviceproviderplugin.h b/src/multimedia/qmediaserviceproviderplugin.h new file mode 100644 index 000000000..669723e2b --- /dev/null +++ b/src/multimedia/qmediaserviceproviderplugin.h @@ -0,0 +1,129 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMEDIASERVICEPROVIDERPLUGIN_H +#define QMEDIASERVICEPROVIDERPLUGIN_H + +#include <QtCore/qstringlist.h> +#include <QtCore/qplugin.h> +#include <QtCore/qfactoryinterface.h> +#include <qtmultimediadefs.h> +#include "qmediaserviceprovider.h" + +#ifdef Q_MOC_RUN +# pragma Q_MOC_EXPAND_MACROS +#endif + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + +class QMediaService; + +struct Q_MULTIMEDIA_EXPORT QMediaServiceProviderFactoryInterface : public QFactoryInterface +{ + virtual QStringList keys() const = 0; + virtual QMediaService* create(QString const& key) = 0; + virtual void release(QMediaService *service) = 0; +}; + +#define QMediaServiceProviderFactoryInterface_iid \ + "com.nokia.Qt.QMediaServiceProviderFactoryInterface/1.0" +Q_DECLARE_INTERFACE(QMediaServiceProviderFactoryInterface, QMediaServiceProviderFactoryInterface_iid) + + +struct Q_MULTIMEDIA_EXPORT QMediaServiceSupportedFormatsInterface +{ + virtual ~QMediaServiceSupportedFormatsInterface() {} + virtual QtMultimedia::SupportEstimate hasSupport(const QString &mimeType, const QStringList& codecs) const = 0; + virtual QStringList supportedMimeTypes() const = 0; +}; + +#define QMediaServiceSupportedFormatsInterface_iid \ + "com.nokia.Qt.QMediaServiceSupportedFormatsInterface/1.0" +Q_DECLARE_INTERFACE(QMediaServiceSupportedFormatsInterface, QMediaServiceSupportedFormatsInterface_iid) + + +struct Q_MULTIMEDIA_EXPORT QMediaServiceSupportedDevicesInterface +{ + virtual ~QMediaServiceSupportedDevicesInterface() {} + virtual QList<QByteArray> devices(const QByteArray &service) const = 0; + virtual QString deviceDescription(const QByteArray &service, const QByteArray &device) = 0; +}; + +#define QMediaServiceSupportedDevicesInterface_iid \ + "com.nokia.Qt.QMediaServiceSupportedDevicesInterface/1.0" +Q_DECLARE_INTERFACE(QMediaServiceSupportedDevicesInterface, QMediaServiceSupportedDevicesInterface_iid) + + + +struct Q_MULTIMEDIA_EXPORT QMediaServiceFeaturesInterface +{ + virtual ~QMediaServiceFeaturesInterface() {} + virtual QMediaServiceProviderHint::Features supportedFeatures(const QByteArray &service) const = 0; +}; + +#define QMediaServiceFeaturesInterface_iid \ + "com.nokia.Qt.QMediaServiceFeaturesInterface/1.0" +Q_DECLARE_INTERFACE(QMediaServiceFeaturesInterface, QMediaServiceFeaturesInterface_iid) + + +class Q_MULTIMEDIA_EXPORT QMediaServiceProviderPlugin : public QObject, public QMediaServiceProviderFactoryInterface +{ + Q_OBJECT + Q_INTERFACES(QMediaServiceProviderFactoryInterface:QFactoryInterface) + +public: + virtual QStringList keys() const = 0; + virtual QMediaService* create(const QString& key) = 0; + virtual void release(QMediaService *service) = 0; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + + + +#endif // QMEDIASERVICEPROVIDERPLUGIN_H diff --git a/src/multimedia/qmediastreamscontrol.cpp b/src/multimedia/qmediastreamscontrol.cpp new file mode 100644 index 000000000..65614b612 --- /dev/null +++ b/src/multimedia/qmediastreamscontrol.cpp @@ -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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmediastreamscontrol.h" +#include "qmediacontrol_p.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QMediaStreamsControl + \preliminary + + \inmodule QtMultimedia + \ingroup multimedia-serv + \brief The QMediaStreamsControl class provides a media stream selection control. + + \since 1.0 + + The QMediaStreamsControl class provides descriptions of the available media streams + and allows individual streams to be activated and deactivated. + + The interface name of QMediaStreamsControl is \c com.nokia.Qt.MediaStreamsControl as + defined in QMediaStreamsControl_iid. + + \sa QMediaService::requestControl() +*/ + +/*! + \macro QMediaStreamsControl_iid + + \c com.nokia.Qt.MediaStreamsControl + + Defines the interface name of the QMediaStreamsControl class. + + \relates QMediaStreamsControl + \since 1.0 +*/ + +/*! + Constructs a new media streams control with the given \a parent. +*/ +QMediaStreamsControl::QMediaStreamsControl(QObject *parent) + :QMediaControl(*new QMediaControlPrivate, parent) +{ +} + +/*! + Destroys a media streams control. +*/ +QMediaStreamsControl::~QMediaStreamsControl() +{ +} + +/*! + \enum QMediaStreamsControl::StreamType + + Media stream type. + + \value AudioStream Audio stream. + \value VideoStream Video stream. + \value SubPictureStream Subpicture or teletext stream. + \value UnknownStream The stream type is unknown. + \value DataStream +*/ + +/*! + \fn QMediaStreamsControl::streamCount() + + Returns the number of media streams. + \since 1.0 +*/ + +/*! + \fn QMediaStreamsControl::streamType(int stream) + + Return the type of a media \a stream. + \since 1.0 +*/ + +/*! + \fn QMediaStreamsControl::metaData(int stream, QtMultimedia::MetaData key) + + Returns the meta-data value of \a key for a given \a stream. + + Useful metadata keya are QtMultimedia::Title, QtMultimedia::Description and QtMultimedia::Language. + \since 1.0 +*/ + +/*! + \fn QMediaStreamsControl::isActive(int stream) + + Returns true if the media \a stream is active. + \since 1.0 +*/ + +/*! + \fn QMediaStreamsControl::setActive(int stream, bool state) + + Sets the active \a state of a media \a stream. + + 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. + \since 1.0 +*/ + +/*! + \fn QMediaStreamsControl::streamsChanged() + + The signal is emitted when the available streams list is changed. + \since 1.0 +*/ + +/*! + \fn QMediaStreamsControl::activeStreamsChanged() + + The signal is emitted when the active streams list is changed. + \since 1.0 +*/ + +#include "moc_qmediastreamscontrol.cpp" +QT_END_NAMESPACE + diff --git a/src/multimedia/qmediastreamscontrol.h b/src/multimedia/qmediastreamscontrol.h new file mode 100644 index 000000000..bbd8a2a43 --- /dev/null +++ b/src/multimedia/qmediastreamscontrol.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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#ifndef QMEDIASTREAMSCONTROL_H +#define QMEDIASTREAMSCONTROL_H + +#include "qmediacontrol.h" +#include "qtmedianamespace.h" +#include "qtmultimediadefs.h" +#include <qmediaenumdebug.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + +class Q_MULTIMEDIA_EXPORT QMediaStreamsControl : public QMediaControl +{ + Q_OBJECT + Q_ENUMS(SteamType) +public: + enum StreamType { UnknownStream, VideoStream, AudioStream, SubPictureStream, DataStream }; + + virtual ~QMediaStreamsControl(); + + virtual int streamCount() = 0; + virtual StreamType streamType(int streamNumber) = 0; + + virtual QVariant metaData(int streamNumber, QtMultimedia::MetaData key) = 0; + + virtual bool isActive(int streamNumber) = 0; + virtual void setActive(int streamNumber, bool state) = 0; + +Q_SIGNALS: + void streamsChanged(); + void activeStreamsChanged(); + +protected: + QMediaStreamsControl(QObject *parent = 0); +}; + +#define QMediaStreamsControl_iid "com.nokia.Qt.QMediaStreamsControl/1.0" +Q_MEDIA_DECLARE_CONTROL(QMediaStreamsControl, QMediaStreamsControl_iid) + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(QMediaStreamsControl::StreamType) + +Q_MEDIA_ENUM_DEBUG(QMediaStreamsControl, StreamType) + +QT_END_HEADER + +#endif // QMEDIASTREAMSCONTROL_H + diff --git a/src/multimedia/qmediatimerange.cpp b/src/multimedia/qmediatimerange.cpp new file mode 100644 index 000000000..34252de37 --- /dev/null +++ b/src/multimedia/qmediatimerange.cpp @@ -0,0 +1,759 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtCore/qdebug.h> + +#include "qmediatimerange.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QMediaTimeInterval + \brief The QMediaTimeInterval class represents a time interval with integer precision. + \inmodule QtMultimedia + \ingroup multimedia + \since 1.0 + + An interval is specified by an inclusive start() and end() time. These + must be set in the constructor, as this is an immutable class. The + specific units of time represented by the class have not been defined - it + is suitable for any times which can be represented by a signed 64 bit + integer. + + The isNormal() method determines if a time interval is normal (a normal + time interval has start() <= end()). An abnormal interval can be converted + in to a normal interval by calling the normalized() method. + + The contains() method determines if a specified time lies within the time + interval. + + The translated() method returns a time interval which has been translated + forwards or backwards through time by a specified offset. + + \sa QMediaTimeRange +*/ + +/*! + \fn QMediaTimeInterval::QMediaTimeInterval() + + Constructs an empty interval. +*/ +QMediaTimeInterval::QMediaTimeInterval() + : s(0) + , e(0) +{ + +} + +/*! + \fn QMediaTimeInterval::QMediaTimeInterval(qint64 start, qint64 end) + + Constructs an interval with the specified \a start and \a end times. + \since 1.0 +*/ +QMediaTimeInterval::QMediaTimeInterval(qint64 start, qint64 end) + : s(start) + , e(end) +{ + +} + +/*! + \fn QMediaTimeInterval::QMediaTimeInterval(const QMediaTimeInterval &other) + + Constructs an interval by taking a copy of \a other. + \since 1.0 +*/ +QMediaTimeInterval::QMediaTimeInterval(const QMediaTimeInterval &other) + : s(other.s) + , e(other.e) +{ + +} + +/*! + \fn QMediaTimeInterval::start() const + + Returns the start time of the interval. + + \since 1.0 + \sa end() +*/ +qint64 QMediaTimeInterval::start() const +{ + return s; +} + +/*! + \fn QMediaTimeInterval::end() const + + Returns the end time of the interval. + + \since 1.0 + \sa start() +*/ +qint64 QMediaTimeInterval::end() const +{ + return e; +} + +/*! + \fn QMediaTimeInterval::contains(qint64 time) const + + Returns true if the time interval contains the specified \a time. + That is, start() <= time <= end(). + \since 1.0 +*/ +bool QMediaTimeInterval::contains(qint64 time) const +{ + return isNormal() ? (s <= time && time <= e) + : (e <= time && time <= s); +} + +/*! + \fn QMediaTimeInterval::isNormal() const + + Returns true if this time interval is normal. + A normal time interval has start() <= end(). + + \since 1.0 + \sa normalized() +*/ +bool QMediaTimeInterval::isNormal() const +{ + return s <= e; +} + +/*! + \fn QMediaTimeInterval::normalized() const + + Returns a normalized version of this interval. + + If the start() time of the interval is greater than the end() time, + then the returned interval has the start and end times swapped. + \since 1.0 +*/ +QMediaTimeInterval QMediaTimeInterval::normalized() const +{ + if(s > e) + return QMediaTimeInterval(e, s); + + return *this; +} + +/*! + \fn QMediaTimeInterval::translated(qint64 offset) const + + Returns a copy of this time interval, translated by a value of \a offset. + An interval can be moved forward through time with a positive offset, or backward + through time with a negative offset. + \since 1.0 +*/ +QMediaTimeInterval QMediaTimeInterval::translated(qint64 offset) const +{ + return QMediaTimeInterval(s + offset, e + offset); +} + +/*! + \fn operator==(const QMediaTimeInterval &a, const QMediaTimeInterval &b) + \relates QMediaTimeRange + + Returns true if \a a is exactly equal to \a b. + \since 1.0 +*/ +bool operator==(const QMediaTimeInterval &a, const QMediaTimeInterval &b) +{ + return a.start() == b.start() && a.end() == b.end(); +} + +/*! + \fn operator!=(const QMediaTimeInterval &a, const QMediaTimeInterval &b) + \relates QMediaTimeRange + + Returns true if \a a is not exactly equal to \a b. + \since 1.0 +*/ +bool operator!=(const QMediaTimeInterval &a, const QMediaTimeInterval &b) +{ + return a.start() != b.start() || a.end() != b.end(); +} + +class QMediaTimeRangePrivate : public QSharedData +{ +public: + + QMediaTimeRangePrivate(); + QMediaTimeRangePrivate(const QMediaTimeRangePrivate &other); + QMediaTimeRangePrivate(const QMediaTimeInterval &interval); + + QList<QMediaTimeInterval> intervals; + + void addInterval(const QMediaTimeInterval &interval); + void removeInterval(const QMediaTimeInterval &interval); +}; + +QMediaTimeRangePrivate::QMediaTimeRangePrivate() + : QSharedData() +{ + +} + +QMediaTimeRangePrivate::QMediaTimeRangePrivate(const QMediaTimeRangePrivate &other) + : QSharedData() + , intervals(other.intervals) +{ + +} + +QMediaTimeRangePrivate::QMediaTimeRangePrivate(const QMediaTimeInterval &interval) + : QSharedData() +{ + if(interval.isNormal()) + intervals << interval; +} + +void QMediaTimeRangePrivate::addInterval(const QMediaTimeInterval &interval) +{ + // Handle normalized intervals only + if(!interval.isNormal()) + return; + + // Find a place to insert the interval + int i; + for (i = 0; i < intervals.count(); i++) { + // Insert before this element + if(interval.s < intervals[i].s) { + intervals.insert(i, interval); + break; + } + } + + // Interval needs to be added to the end of the list + if (i == intervals.count()) + intervals.append(interval); + + // Do we need to correct the element before us? + if(i > 0 && intervals[i - 1].e >= interval.s - 1) + i--; + + // Merge trailing ranges + while (i < intervals.count() - 1 + && intervals[i].e >= intervals[i + 1].s - 1) { + intervals[i].e = qMax(intervals[i].e, intervals[i + 1].e); + intervals.removeAt(i + 1); + } +} + +void QMediaTimeRangePrivate::removeInterval(const QMediaTimeInterval &interval) +{ + // Handle normalized intervals only + if(!interval.isNormal()) + return; + + for (int i = 0; i < intervals.count(); i++) { + QMediaTimeInterval r = intervals[i]; + + if (r.e < interval.s) { + // Before the removal interval + continue; + } else if (interval.e < r.s) { + // After the removal interval - stop here + break; + } else if (r.s < interval.s && interval.e < r.e) { + // Split case - a single range has a chunk removed + intervals[i].e = interval.s -1; + addInterval(QMediaTimeInterval(interval.e + 1, r.e)); + break; + } else if (r.s < interval.s) { + // Trimming Tail Case + intervals[i].e = interval.s - 1; + } else if (interval.e < r.e) { + // Trimming Head Case - we can stop after this + intervals[i].s = interval.e + 1; + break; + } else { + // Complete coverage case + intervals.removeAt(i); + --i; + } + } +} + +/*! + \class QMediaTimeRange + \brief The QMediaTimeRange class represents a set of zero or more disjoint + time intervals. + \ingroup multimedia + \since 1.0 + + \reentrant + + The earliestTime(), latestTime(), intervals() and isEmpty() + methods are used to get information about the current time range. + + The addInterval(), removeInterval() and clear() methods are used to modify + the current time range. + + When adding or removing intervals from the time range, existing intervals + within the range may be expanded, trimmed, deleted, merged or split to ensure + that all intervals within the time range remain distinct and disjoint. As a + consequence, all intervals added or removed from a time range must be + \l{QMediaTimeInterval::isNormal()}{normal}. + + \sa QMediaTimeInterval +*/ + +/*! + \fn QMediaTimeRange::QMediaTimeRange() + + Constructs an empty time range. +*/ +QMediaTimeRange::QMediaTimeRange() + : d(new QMediaTimeRangePrivate) +{ + +} + +/*! + \fn QMediaTimeRange::QMediaTimeRange(qint64 start, qint64 end) + + Constructs a time range that contains an initial interval from + \a start to \a end inclusive. + + If the interval is not \l{QMediaTimeInterval::isNormal()}{normal}, + the resulting time range will be empty. + + \since 1.0 + \sa addInterval() +*/ +QMediaTimeRange::QMediaTimeRange(qint64 start, qint64 end) + : d(new QMediaTimeRangePrivate(QMediaTimeInterval(start, end))) +{ + +} + +/*! + \fn QMediaTimeRange::QMediaTimeRange(const QMediaTimeInterval &interval) + + Constructs a time range that contains an intitial interval, \a interval. + + If \a interval is not \l{QMediaTimeInterval::isNormal()}{normal}, + the resulting time range will be empty. + + \since 1.0 + \sa addInterval() +*/ +QMediaTimeRange::QMediaTimeRange(const QMediaTimeInterval &interval) + : d(new QMediaTimeRangePrivate(interval)) +{ + +} + +/*! + \fn QMediaTimeRange::QMediaTimeRange(const QMediaTimeRange &range) + + Constructs a time range by copying another time \a range. + \since 1.0 +*/ +QMediaTimeRange::QMediaTimeRange(const QMediaTimeRange &range) + : d(range.d) +{ + +} + +/*! + \fn QMediaTimeRange::~QMediaTimeRange() + + Destructor. +*/ +QMediaTimeRange::~QMediaTimeRange() +{ + +} + +/*! + \fn QMediaTimeRange::operator=(const QMediaTimeRange &other) + + Takes a copy of the \a other time range and returns itself. + \since 1.0 +*/ +QMediaTimeRange &QMediaTimeRange::operator=(const QMediaTimeRange &other) +{ + d = other.d; + return *this; +} + +/*! + \fn QMediaTimeRange::operator=(const QMediaTimeInterval &interval) + + Sets the time range to a single continuous interval, \a interval. + \since 1.0 +*/ +QMediaTimeRange &QMediaTimeRange::operator=(const QMediaTimeInterval &interval) +{ + d = new QMediaTimeRangePrivate(interval); + return *this; +} + +/*! + \fn QMediaTimeRange::earliestTime() const + + Returns the earliest time within the time range. + + For empty time ranges, this value is equal to zero. + + \since 1.0 + \sa latestTime() +*/ +qint64 QMediaTimeRange::earliestTime() const +{ + if (!d->intervals.isEmpty()) + return d->intervals[0].s; + + return 0; +} + +/*! + \fn QMediaTimeRange::latestTime() const + + Returns the latest time within the time range. + + For empty time ranges, this value is equal to zero. + + \since 1.0 + \sa earliestTime() +*/ +qint64 QMediaTimeRange::latestTime() const +{ + if (!d->intervals.isEmpty()) + return d->intervals[d->intervals.count() - 1].e; + + return 0; +} + +/*! + \fn QMediaTimeRange::addInterval(qint64 start, qint64 end) + \overload + + Adds the interval specified by \a start and \a end + to the time range. + + \since 1.0 + \sa addInterval() +*/ +void QMediaTimeRange::addInterval(qint64 start, qint64 end) +{ + d->addInterval(QMediaTimeInterval(start, end)); +} + +/*! + \fn QMediaTimeRange::addInterval(const QMediaTimeInterval &interval) + + Adds the specified \a interval to the time range. + + Adding intervals which are not \l{QMediaTimeInterval::isNormal()}{normal} + is invalid, and will be ignored. + + If the specified interval is adjacent to, or overlaps existing + intervals within the time range, these intervals will be merged. + + This operation takes \l{linear time} + + \since 1.0 + \sa removeInterval() +*/ +void QMediaTimeRange::addInterval(const QMediaTimeInterval &interval) +{ + d->addInterval(interval); +} + +/*! + \fn QMediaTimeRange::addTimeRange(const QMediaTimeRange &range) + + Adds each of the intervals in \a range to this time range. + + Equivalent to calling addInterval() for each interval in \a range. + \since 1.0 +*/ +void QMediaTimeRange::addTimeRange(const QMediaTimeRange &range) +{ + foreach(const QMediaTimeInterval &i, range.intervals()) { + d->addInterval(i); + } +} + +/*! + \fn QMediaTimeRange::removeInterval(qint64 start, qint64 end) + \overload + + Removes the interval specified by \a start and \a end + from the time range. + + \since 1.0 + \sa removeInterval() +*/ +void QMediaTimeRange::removeInterval(qint64 start, qint64 end) +{ + d->removeInterval(QMediaTimeInterval(start, end)); +} + +/*! + \fn QMediaTimeRange::removeInterval(const QMediaTimeInterval &interval) + + Removes the specified \a interval from the time range. + + Removing intervals which are not \l{QMediaTimeInterval::isNormal()}{normal} + is invalid, and will be ignored. + + Intervals within the time range will be trimmed, split or deleted + such that no intervals within the time range include any part of the + target interval. + + This operation takes \l{linear time} + + \since 1.0 + \sa addInterval() +*/ +void QMediaTimeRange::removeInterval(const QMediaTimeInterval &interval) +{ + d->removeInterval(interval); +} + +/*! + \fn QMediaTimeRange::removeTimeRange(const QMediaTimeRange &range) + + Removes each of the intervals in \a range from this time range. + + Equivalent to calling removeInterval() for each interval in \a range. + \since 1.0 +*/ +void QMediaTimeRange::removeTimeRange(const QMediaTimeRange &range) +{ + foreach(const QMediaTimeInterval &i, range.intervals()) { + d->removeInterval(i); + } +} + +/*! + \fn QMediaTimeRange::operator+=(const QMediaTimeRange &other) + + Adds each interval in \a other to the time range and returns the result. + \since 1.0 +*/ +QMediaTimeRange& QMediaTimeRange::operator+=(const QMediaTimeRange &other) +{ + addTimeRange(other); + return *this; +} + +/*! + \fn QMediaTimeRange::operator+=(const QMediaTimeInterval &interval) + + Adds the specified \a interval to the time range and returns the result. + \since 1.0 +*/ +QMediaTimeRange& QMediaTimeRange::operator+=(const QMediaTimeInterval &interval) +{ + addInterval(interval); + return *this; +} + +/*! + \fn QMediaTimeRange::operator-=(const QMediaTimeRange &other) + + Removes each interval in \a other from the time range and returns the result. + \since 1.0 +*/ +QMediaTimeRange& QMediaTimeRange::operator-=(const QMediaTimeRange &other) +{ + removeTimeRange(other); + return *this; +} + +/*! + \fn QMediaTimeRange::operator-=(const QMediaTimeInterval &interval) + + Removes the specified \a interval from the time range and returns the result. + \since 1.0 +*/ +QMediaTimeRange& QMediaTimeRange::operator-=(const QMediaTimeInterval &interval) +{ + removeInterval(interval); + return *this; +} + +/*! + \fn QMediaTimeRange::clear() + + Removes all intervals from the time range. + + \since 1.0 + \sa removeInterval() +*/ +void QMediaTimeRange::clear() +{ + d->intervals.clear(); +} + +/*! + \fn QMediaTimeRange::intervals() const + + Returns the list of intervals covered by this time range. + \since 1.0 +*/ +QList<QMediaTimeInterval> QMediaTimeRange::intervals() const +{ + return d->intervals; +} + +/*! + \fn QMediaTimeRange::isEmpty() const + + Returns true if there are no intervals within the time range. + + \since 1.0 + \sa intervals() +*/ +bool QMediaTimeRange::isEmpty() const +{ + return d->intervals.isEmpty(); +} + +/*! + \fn QMediaTimeRange::isContinuous() const + + Returns true if the time range consists of a continuous interval. + That is, there is one or fewer disjoint intervals within the time range. + \since 1.0 +*/ +bool QMediaTimeRange::isContinuous() const +{ + return (d->intervals.count() <= 1); +} + +/*! + \fn QMediaTimeRange::contains(qint64 time) const + + Returns true if the specified \a time lies within the time range. + \since 1.0 +*/ +bool QMediaTimeRange::contains(qint64 time) const +{ + for (int i = 0; i < d->intervals.count(); i++) { + if (d->intervals[i].contains(time)) + return true; + + if (time < d->intervals[i].s) + break; + } + + return false; +} + +/*! + \fn operator==(const QMediaTimeRange &a, const QMediaTimeRange &b) + \relates QMediaTimeRange + + Returns true if all intervals in \a a are present in \a b. + \since 1.0 +*/ +bool operator==(const QMediaTimeRange &a, const QMediaTimeRange &b) +{ + if (a.intervals().count() != b.intervals().count()) + return false; + + for (int i = 0; i < a.intervals().count(); i++) + { + if(a.intervals()[i] != b.intervals()[i]) + return false; + } + + return true; +} + +/*! + \fn operator!=(const QMediaTimeRange &a, const QMediaTimeRange &b) + \relates QMediaTimeRange + + Returns true if one or more intervals in \a a are not present in \a b. + \since 1.0 +*/ +bool operator!=(const QMediaTimeRange &a, const QMediaTimeRange &b) +{ + return !(a == b); +} + +/*! + \fn operator+(const QMediaTimeRange &r1, const QMediaTimeRange &r2) + + Returns a time range containing the union between \a r1 and \a r2. + \since 1.0 + */ +QMediaTimeRange operator+(const QMediaTimeRange &r1, const QMediaTimeRange &r2) +{ + return (QMediaTimeRange(r1) += r2); +} + +/*! + \fn operator-(const QMediaTimeRange &r1, const QMediaTimeRange &r2) + + Returns a time range containing \a r2 subtracted from \a r1. + \since 1.0 + */ +QMediaTimeRange operator-(const QMediaTimeRange &r1, const QMediaTimeRange &r2) +{ + return (QMediaTimeRange(r1) -= r2); +} + +#ifndef QT_NO_DEBUG_STREAM +QDebug operator<<(QDebug dbg, const QMediaTimeRange &range) +{ + dbg.nospace() << "QMediaTimeRange( "; + foreach (const QMediaTimeInterval &interval, range.intervals()) { + dbg.nospace() << "(" << interval.start() << ", " << interval.end() << ") "; + } + dbg.space() << ")"; + return dbg; +} +#endif + +QT_END_NAMESPACE + diff --git a/src/multimedia/qmediatimerange.h b/src/multimedia/qmediatimerange.h new file mode 100644 index 000000000..d506bbe52 --- /dev/null +++ b/src/multimedia/qmediatimerange.h @@ -0,0 +1,140 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMEDIATIMERANGE_H +#define QMEDIATIMERANGE_H + +#include <qtmultimediadefs.h> +#include "qtmedianamespace.h" +#include <QtCore/qshareddata.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + +class QMediaTimeRangePrivate; + +class Q_MULTIMEDIA_EXPORT QMediaTimeInterval +{ +public: + QMediaTimeInterval(); + QMediaTimeInterval(qint64 start, qint64 end); + QMediaTimeInterval(const QMediaTimeInterval&); + + qint64 start() const; + qint64 end() const; + + bool contains(qint64 time) const; + + bool isNormal() const; + QMediaTimeInterval normalized() const; + QMediaTimeInterval translated(qint64 offset) const; + +private: + friend class QMediaTimeRangePrivate; + friend class QMediaTimeRange; + + qint64 s; + qint64 e; +}; + +Q_MULTIMEDIA_EXPORT bool operator==(const QMediaTimeInterval&, const QMediaTimeInterval&); +Q_MULTIMEDIA_EXPORT bool operator!=(const QMediaTimeInterval&, const QMediaTimeInterval&); + +class Q_MULTIMEDIA_EXPORT QMediaTimeRange +{ +public: + + QMediaTimeRange(); + QMediaTimeRange(qint64 start, qint64 end); + QMediaTimeRange(const QMediaTimeInterval&); + QMediaTimeRange(const QMediaTimeRange &range); + ~QMediaTimeRange(); + + QMediaTimeRange &operator=(const QMediaTimeRange&); + QMediaTimeRange &operator=(const QMediaTimeInterval&); + + qint64 earliestTime() const; + qint64 latestTime() const; + + QList<QMediaTimeInterval> intervals() const; + bool isEmpty() const; + bool isContinuous() const; + + bool contains(qint64 time) const; + + void addInterval(qint64 start, qint64 end); + void addInterval(const QMediaTimeInterval &interval); + void addTimeRange(const QMediaTimeRange&); + + void removeInterval(qint64 start, qint64 end); + void removeInterval(const QMediaTimeInterval &interval); + void removeTimeRange(const QMediaTimeRange&); + + QMediaTimeRange& operator+=(const QMediaTimeRange&); + QMediaTimeRange& operator+=(const QMediaTimeInterval&); + QMediaTimeRange& operator-=(const QMediaTimeRange&); + QMediaTimeRange& operator-=(const QMediaTimeInterval&); + + void clear(); + +private: + QSharedDataPointer<QMediaTimeRangePrivate> d; +}; + +Q_MULTIMEDIA_EXPORT bool operator==(const QMediaTimeRange&, const QMediaTimeRange&); +Q_MULTIMEDIA_EXPORT bool operator!=(const QMediaTimeRange&, const QMediaTimeRange&); +Q_MULTIMEDIA_EXPORT QMediaTimeRange operator+(const QMediaTimeRange&, const QMediaTimeRange&); +Q_MULTIMEDIA_EXPORT QMediaTimeRange operator-(const QMediaTimeRange&, const QMediaTimeRange&); + +#ifndef QT_NO_DEBUG_STREAM +Q_MULTIMEDIA_EXPORT QDebug operator<<(QDebug, const QMediaTimeRange &); +#endif + +QT_END_NAMESPACE + +QT_END_HEADER + + +#endif // QMEDIATIMERANGE_H diff --git a/src/multimedia/qmetadatareadercontrol.cpp b/src/multimedia/qmetadatareadercontrol.cpp new file mode 100644 index 000000000..a15cf6d7e --- /dev/null +++ b/src/multimedia/qmetadatareadercontrol.cpp @@ -0,0 +1,163 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <qmediacontrol_p.h> +#include <qmetadatareadercontrol.h> + +QT_BEGIN_NAMESPACE + + +/*! + \class QMetaDataReaderControl + \inmodule QtMultimedia + \ingroup multimedia-serv + \since 1.0 + + + \brief The QMetaDataReaderControl class provides read access to the + meta-data of a QMediaService's media. + + If a QMediaService can provide read or write access to the meta-data of + its current media it will implement QMetaDataReaderControl. This control + provides functions for both retrieving and setting meta-data values. + Meta-data may be addressed by the well defined keys in the + QtMultimedia::MetaData enumeration using the metaData() functions, or by + string keys using the extendedMetaData() functions. + + The functionality provided by this control is exposed to application + code by the meta-data members of QMediaObject, and so meta-data access + is potentially available in any of the media object classes. Any media + service may implement QMetaDataReaderControl. + + The interface name of QMetaDataReaderControl is + \c com.nokia.Qt.QMetaDataReaderControl/1.0 as defined in + QMetaDataReaderControl_iid. + + \sa QMediaService::requestControl(), QMediaObject +*/ + +/*! + \macro QMetaDataReaderControl_iid + + \c com.nokia.Qt.QMetaDataReaderControl/1.0 + + Defines the interface name of the QMetaDataReaderControl class. + + \relates QMetaDataReaderControl +*/ + +/*! + Construct a QMetaDataReaderControl with \a parent. This class is meant as a base class + for service specific meta data providers so this constructor is protected. +*/ + +QMetaDataReaderControl::QMetaDataReaderControl(QObject *parent): + QMediaControl(*new QMediaControlPrivate, parent) +{ +} + +/*! + Destroy the meta-data object. +*/ + +QMetaDataReaderControl::~QMetaDataReaderControl() +{ +} + +/*! + \fn bool QMetaDataReaderControl::isMetaDataAvailable() const + + Identifies if meta-data is available from a media service. + + Returns true if the meta-data is available and false otherwise. + \since 1.0 +*/ + +/*! + \fn QVariant QMetaDataReaderControl::metaData(QtMultimedia::MetaData key) const + + Returns the meta-data for the given \a key. + \since 1.0 +*/ + +/*! + \fn QMetaDataReaderControl::availableMetaData() const + + Returns a list of keys there is meta-data available for. + \since 1.0 +*/ + +/*! + \fn QMetaDataReaderControl::extendedMetaData(const QString &key) const + + Returns the metaData for an abitrary string \a key. + + The valid selection of keys for extended meta-data is determined by the provider and the meaning + and type may differ between providers. + \since 1.0 +*/ + +/*! + \fn QMetaDataReaderControl::availableExtendedMetaData() const + + Returns a list of keys there is extended meta-data available for. + \since 1.0 +*/ + + +/*! + \fn void QMetaDataReaderControl::metaDataChanged() + + Signal the changes of meta-data. + \since 1.0 +*/ + +/*! + \fn void QMetaDataReaderControl::metaDataAvailableChanged(bool available) + + Signal the availability of meta-data has changed, \a available will + be true if the multimedia object has meta-data. + \since 1.0 +*/ + +#include "moc_qmetadatareadercontrol.cpp" +QT_END_NAMESPACE + diff --git a/src/multimedia/qmetadatareadercontrol.h b/src/multimedia/qmetadatareadercontrol.h new file mode 100644 index 000000000..0d370b5c4 --- /dev/null +++ b/src/multimedia/qmetadatareadercontrol.h @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMETADATAREADERCONTROL_H +#define QMETADATAREADERCONTROL_H + +#include <qmediacontrol.h> +#include <qmediaobject.h> + +#include <qmediaresource.h> + +#include <qtmultimediadefs.h> +#include "qtmedianamespace.h" + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + + +class Q_MULTIMEDIA_EXPORT QMetaDataReaderControl : public QMediaControl +{ + Q_OBJECT +public: + ~QMetaDataReaderControl(); + + virtual bool isMetaDataAvailable() const = 0; + + virtual QVariant metaData(QtMultimedia::MetaData key) const = 0; + virtual QList<QtMultimedia::MetaData> availableMetaData() const = 0; + + virtual QVariant extendedMetaData(const QString &key) const = 0; + virtual QStringList availableExtendedMetaData() const = 0; + +Q_SIGNALS: + void metaDataChanged(); + + void metaDataAvailableChanged(bool available); + +protected: + QMetaDataReaderControl(QObject *parent = 0); +}; + +#define QMetaDataReaderControl_iid "com.nokia.Qt.QMetaDataReaderControl/1.0" +Q_MEDIA_DECLARE_CONTROL(QMetaDataReaderControl, QMetaDataReaderControl_iid) + +QT_END_NAMESPACE + +QT_END_HEADER + + +#endif // QMETADATAPROVIDER_H diff --git a/src/multimedia/qmetadatawritercontrol.cpp b/src/multimedia/qmetadatawritercontrol.cpp new file mode 100644 index 000000000..0888bcfae --- /dev/null +++ b/src/multimedia/qmetadatawritercontrol.cpp @@ -0,0 +1,195 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <qmediacontrol_p.h> +#include <qmetadatawritercontrol.h> + +QT_BEGIN_NAMESPACE + + +/*! + \class QMetaDataWriterControl + \inmodule QtMultimedia + \ingroup multimedia-serv + \since 1.0 + + + \brief The QMetaDataWriterControl class provides write access to the + meta-data of a QMediaService's media. + + If a QMediaService can provide write access to the meta-data of its + current media it will implement QMetaDataWriterControl. This control + provides functions for both retrieving and setting meta-data values. + Meta-data may be addressed by the well defined keys in the + QtMultimedia::MetaData enumeration using the metaData() functions, or + by string keys using the extendedMetaData() functions. + + The functionality provided by this control is exposed to application code + by the meta-data members of QMediaObject, and so meta-data access is + potentially available in any of the media object classes. Any media + service may implement QMetaDataControl. + + The interface name of QMetaDataWriterControl is \c com.nokia.Qt.QMetaDataWriterControl/1.0 as + defined in QMetaDataWriterControl_iid. + + \sa QMediaService::requestControl(), QMediaObject +*/ + +/*! + \macro QMetaDataWriterControl_iid + + \c com.nokia.Qt.QMetaDataWriterControl/1.0 + + Defines the interface name of the QMetaDataWriterControl class. + + \relates QMetaDataWriterControl +*/ + +/*! + Construct a QMetaDataWriterControl with \a parent. This class is meant as a base class + for service specific meta data providers so this constructor is protected. +*/ + +QMetaDataWriterControl::QMetaDataWriterControl(QObject *parent): + QMediaControl(*new QMediaControlPrivate, parent) +{ +} + +/*! + Destroy the meta-data writer control. +*/ + +QMetaDataWriterControl::~QMetaDataWriterControl() +{ +} + +/*! + \fn bool QMetaDataWriterControl::isMetaDataAvailable() const + + Identifies if meta-data is available from a media service. + + Returns true if the meta-data is available and false otherwise. + \since 1.0 +*/ + +/*! + \fn bool QMetaDataWriterControl::isWritable() const + + Identifies if a media service's meta-data can be edited. + + Returns true if the meta-data is writable and false otherwise. + \since 1.0 +*/ + +/*! + \fn QVariant QMetaDataWriterControl::metaData(QtMultimedia::MetaData key) const + + Returns the meta-data for the given \a key. + \since 1.0 +*/ + +/*! + \fn void QMetaDataWriterControl::setMetaData(QtMultimedia::MetaData key, const QVariant &value) + + Sets the \a value of the meta-data element with the given \a key. + \since 1.0 +*/ + +/*! + \fn QMetaDataWriterControl::availableMetaData() const + + Returns a list of keys there is meta-data available for. +*/ + +/*! + \fn QMetaDataWriterControl::extendedMetaData(const QString &key) const + + Returns the meta-data for an abitrary string \a key. + + The valid selection of keys for extended meta-data is determined by the provider and the meaning + and type may differ between providers. + \since 1.0 +*/ + +/*! + \fn QMetaDataWriterControl::setExtendedMetaData(const QString &key, const QVariant &value) + + Change the value of the meta-data element with an abitrary string \a key to \a value. + + The valid selection of keys for extended meta-data is determined by the provider and the meaning + and type may differ between providers. + \since 1.0 +*/ + +/*! + \fn QMetaDataWriterControl::availableExtendedMetaData() const + + Returns a list of keys there is extended meta-data available for. + \since 1.0 +*/ + + +/*! + \fn void QMetaDataWriterControl::metaDataChanged() + + Signal the changes of meta-data. + \since 1.0 +*/ + +/*! + \fn void QMetaDataWriterControl::metaDataAvailableChanged(bool available) + + Signal the availability of meta-data has changed, \a available will + be true if the multimedia object has meta-data. + \since 1.0 +*/ + +/*! + \fn void QMetaDataWriterControl::writableChanged(bool writable) + + Signal a change in the writable status of meta-data, \a writable will be + true if meta-data elements can be added or adjusted. + \since 1.0 +*/ + +#include "moc_qmetadatawritercontrol.cpp" +QT_END_NAMESPACE + diff --git a/src/multimedia/qmetadatawritercontrol.h b/src/multimedia/qmetadatawritercontrol.h new file mode 100644 index 000000000..3f8b8c3f4 --- /dev/null +++ b/src/multimedia/qmetadatawritercontrol.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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMETADATAWRITERCONTROL_H +#define QMETADATAWRITERCONTROL_H + +#include "qmediacontrol.h" +#include "qmediaobject.h" + +#include "qmediaresource.h" + +#include <qtmultimediadefs.h> +#include "qtmedianamespace.h" + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + + +class Q_MULTIMEDIA_EXPORT QMetaDataWriterControl : public QMediaControl +{ + Q_OBJECT +public: + ~QMetaDataWriterControl(); + + virtual bool isWritable() const = 0; + virtual bool isMetaDataAvailable() const = 0; + + virtual QVariant metaData(QtMultimedia::MetaData key) const = 0; + virtual void setMetaData(QtMultimedia::MetaData key, const QVariant &value) = 0; + virtual QList<QtMultimedia::MetaData> availableMetaData() const = 0; + + virtual QVariant extendedMetaData(const QString &key) const = 0; + virtual void setExtendedMetaData(const QString &key, const QVariant &value) = 0; + virtual QStringList availableExtendedMetaData() const = 0; + + +Q_SIGNALS: + void metaDataChanged(); + + void writableChanged(bool writable); + void metaDataAvailableChanged(bool available); + +protected: + QMetaDataWriterControl(QObject *parent = 0); +}; + +#define QMetaDataWriterControl_iid "com.nokia.Qt.QMetaDataWriterControl/1.0" +Q_MEDIA_DECLARE_CONTROL(QMetaDataWriterControl, QMetaDataWriterControl_iid) + +QT_END_NAMESPACE + +QT_END_HEADER + + +#endif diff --git a/src/multimedia/qradiotuner.cpp b/src/multimedia/qradiotuner.cpp new file mode 100644 index 000000000..25f76b83a --- /dev/null +++ b/src/multimedia/qradiotuner.cpp @@ -0,0 +1,614 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qradiotuner.h" +#include "qmediaservice.h" +#include "qmediaobject_p.h" +#include "qradiotunercontrol.h" + +#include <QPair> + + +QT_BEGIN_NAMESPACE + +/*! + \class QRadioTuner + \brief The QRadioTuner class provides an interface to the systems analog radio device. + + \inmodule QtMultimedia + \ingroup multimedia + \since 1.0 + + You can control the systems analog radio device using this interface, for example: + + \snippet doc/src/snippets/multimedia-snippets/media.cpp Radio tuner + + The radio object will emit signals for any changes in state such as: + bandChanged(), frequencyChanged(), stereoStatusChanged(), searchingChanged(), + signalStrengthChanged(), volumeChanged(), mutedChanged(). + + You can change between the frequency bands using setBand() however it is recommended + that you check to make sure the band is available first using isBandSupported(). + +*/ + + +class QRadioTunerPrivate : public QMediaObjectPrivate +{ +public: + QRadioTunerPrivate():provider(0), control(0) {} + QMediaServiceProvider *provider; + QRadioTunerControl* control; +}; + + + +/*! + Constructs a radio tuner based on a media service allocated by a media service \a provider. + + The \a parent is passed to QMediaObject. + \since 1.0 +*/ + +QRadioTuner::QRadioTuner(QObject *parent, QMediaServiceProvider* provider): + QMediaObject(*new QRadioTunerPrivate, parent, provider->requestService(Q_MEDIASERVICE_RADIO)) +{ + Q_D(QRadioTuner); + + d->provider = provider; + + if (d->service != 0) { + d->control = qobject_cast<QRadioTunerControl*>(d->service->requestControl(QRadioTunerControl_iid)); + if (d->control != 0) { + connect(d->control, SIGNAL(stateChanged(QRadioTuner::State)), SIGNAL(stateChanged(QRadioTuner::State))); + connect(d->control, SIGNAL(bandChanged(QRadioTuner::Band)), SIGNAL(bandChanged(QRadioTuner::Band))); + connect(d->control, SIGNAL(frequencyChanged(int)), SIGNAL(frequencyChanged(int))); + connect(d->control, SIGNAL(stereoStatusChanged(bool)), SIGNAL(stereoStatusChanged(bool))); + connect(d->control, SIGNAL(searchingChanged(bool)), SIGNAL(searchingChanged(bool))); + connect(d->control, SIGNAL(signalStrengthChanged(int)), SIGNAL(signalStrengthChanged(int))); + connect(d->control, SIGNAL(volumeChanged(int)), SIGNAL(volumeChanged(int))); + connect(d->control, SIGNAL(mutedChanged(bool)), SIGNAL(mutedChanged(bool))); + connect(d->control, SIGNAL(error(QRadioTuner::Error)), SIGNAL(error(QRadioTuner::Error))); + } + } +} + +/*! + Destroys a radio tuner. +*/ + +QRadioTuner::~QRadioTuner() +{ + Q_D(QRadioTuner); + + if (d->service && d->control) + d->service->releaseControl(d->control); + + d->provider->releaseService(d->service); +} + +/*! + Returns true if the radio tuner service is ready to use. + \since 1.0 +*/ +bool QRadioTuner::isAvailable() const +{ + if (d_func()->control != NULL) + return d_func()->control->isAvailable(); + else + return false; +} + +/*! + Returns the availability error state. + \since 1.0 +*/ +QtMultimedia::AvailabilityError QRadioTuner::availabilityError() const +{ + if (d_func()->control != NULL) + return d_func()->control->availabilityError(); + else + return QtMultimedia::ServiceMissingError; +} + +/*! + \property QRadioTuner::state + Return the current radio tuner state. + + \since 1.0 + \sa QRadioTuner::State +*/ + +QRadioTuner::State QRadioTuner::state() const +{ + return d_func()->control ? + d_func()->control->state() : QRadioTuner::StoppedState; +} + +/*! + \property QRadioTuner::band + \brief the frequency band a radio tuner is tuned to. + + \since 1.0 + \sa QRadioTuner::Band +*/ + +QRadioTuner::Band QRadioTuner::band() const +{ + Q_D(const QRadioTuner); + + if (d->control != 0) + return d->control->band(); + + return QRadioTuner::FM; +} + +/*! + \property QRadioTuner::frequency + \brief the frequency in Hertz a radio tuner is tuned to. + \since 1.0 +*/ + +int QRadioTuner::frequency() const +{ + Q_D(const QRadioTuner); + + if (d->control != 0) + return d->control->frequency(); + + return 0; +} + +/*! + Returns the number of Hertz to increment the frequency by when stepping through frequencies + within a given \a band. + \since 1.0 +*/ + +int QRadioTuner::frequencyStep(QRadioTuner::Band band) const +{ + Q_D(const QRadioTuner); + + if(d->control != 0) + return d->control->frequencyStep(band); + + return 0; +} + +/*! + Returns a frequency \a band's minimum and maximum frequency. + \since 1.0 +*/ + +QPair<int,int> QRadioTuner::frequencyRange(QRadioTuner::Band band) const +{ + Q_D(const QRadioTuner); + + if(d->control != 0) + return d->control->frequencyRange(band); + + return qMakePair<int,int>(0,0); +} + +/*! + \property QRadioTuner::stereo + \brief whether a radio tuner is receiving a stereo signal. + \since 1.0 +*/ + +bool QRadioTuner::isStereo() const +{ + Q_D(const QRadioTuner); + + if (d->control != 0) + return d->control->isStereo(); + + return false; +} + + +/*! + \property QRadioTuner::stereoMode + \brief the stereo mode of a radio tuner. + \since 1.0 +*/ + +QRadioTuner::StereoMode QRadioTuner::stereoMode() const +{ + Q_D(const QRadioTuner); + + if (d->control != 0) + return d->control->stereoMode(); + + return QRadioTuner::Auto; +} + +void QRadioTuner::setStereoMode(QRadioTuner::StereoMode mode) +{ + Q_D(QRadioTuner); + + if (d->control != 0) + return d->control->setStereoMode(mode); +} + +/*! + Identifies if a frequency \a band is supported by a radio tuner. + + Returns true if the band is supported, and false if it is not. + \since 1.0 +*/ + +bool QRadioTuner::isBandSupported(QRadioTuner::Band band) const +{ + Q_D(const QRadioTuner); + + if (d->control != 0) + return d->control->isBandSupported(band); + + return false; +} + +/*! + Activate the radio device. + \since 1.0 +*/ + +void QRadioTuner::start() +{ + Q_D(const QRadioTuner); + + if (d->control != 0) + d->control->start(); +} + +/*! + Deactivate the radio device. + \since 1.0 +*/ + +void QRadioTuner::stop() +{ + Q_D(const QRadioTuner); + + if (d->control != 0) + d->control->stop(); +} + +/*! + \property QRadioTuner::signalStrength + \brief the strength of the current radio signal as a percentage. + \since 1.0 +*/ + +int QRadioTuner::signalStrength() const +{ + Q_D(const QRadioTuner); + + if (d->control != 0) + return d->control->signalStrength(); + + return 0; +} + +/*! + \property QRadioTuner::volume + \brief the volume of a radio tuner's audio output as a percentage. + \since 1.0 +*/ + + +int QRadioTuner::volume() const +{ + Q_D(const QRadioTuner); + + if (d->control != 0) + return d->control->volume(); + + return 0; +} + +/*! + \property QRadioTuner::muted + \brief whether a radio tuner's audio output is muted. + \since 1.0 +*/ + +bool QRadioTuner::isMuted() const +{ + Q_D(const QRadioTuner); + + if (d->control != 0) + return d->control->isMuted(); + + return false; +} + +/*! + Sets a radio tuner's frequency \a band. + + Changing the band will reset the \l frequency to the new band's minimum frequency. + \since 1.0 +*/ + +void QRadioTuner::setBand(QRadioTuner::Band band) +{ + Q_D(QRadioTuner); + + if (d->control != 0) + d->control->setBand(band); +} + +/*! + Sets a radio tuner's \a frequency. + + If the tuner is set to a frequency outside the current \l band, the band will be changed to + one occupied by the new frequency. + \since 1.0 +*/ + +void QRadioTuner::setFrequency(int frequency) +{ + Q_D(QRadioTuner); + + if (d->control != 0) + d->control->setFrequency(frequency); +} + +void QRadioTuner::setVolume(int volume) +{ + Q_D(QRadioTuner); + + if (d->control != 0) + d->control->setVolume(volume); +} + +void QRadioTuner::setMuted(bool muted) +{ + Q_D(QRadioTuner); + + if (d->control != 0) + d->control->setMuted(muted); +} + +/*! + \property QRadioTuner::searching + \brief whether a radio tuner is currently scanning for a signal. + + \sa searchForward(), searchBackward(), cancelSearch() + \since 1.0 +*/ + +bool QRadioTuner::isSearching() const +{ + Q_D(const QRadioTuner); + + if (d->control != 0) + return d->control->isSearching(); + + return false; +} + +/*! + Starts a forward scan for a signal, starting from the current \l frequency. + + \since 1.0 + \sa searchBackward(), cancelSearch(), searching +*/ + +void QRadioTuner::searchForward() +{ + Q_D(QRadioTuner); + + if (d->control != 0) + d->control->searchForward(); +} + +/*! + Starts a backwards scan for a signal, starting from the current \l frequency. + + \since 1.0 + \sa searchForward(), cancelSearch(), searching +*/ + +void QRadioTuner::searchBackward() +{ + Q_D(QRadioTuner); + + if (d->control != 0) + d->control->searchBackward(); +} + +/*! + Stops scanning for a signal. + + \since 1.0 + \sa searchForward(), searchBackward(), searching +*/ + +void QRadioTuner::cancelSearch() +{ + Q_D(QRadioTuner); + + if (d->control != 0) + d->control->cancelSearch(); +} + +/*! + Returns the error state of a radio tuner. + + \since 1.0 + \sa errorString() +*/ + +QRadioTuner::Error QRadioTuner::error() const +{ + Q_D(const QRadioTuner); + + if (d->control != 0) + return d->control->error(); + + return QRadioTuner::ResourceError; +} + +/*! + Returns a description of a radio tuner's error state. + + \since 1.0 + \sa error() +*/ + +QString QRadioTuner::errorString() const +{ + Q_D(const QRadioTuner); + + if (d->control != 0) + return d->control->errorString(); + + return QString(); +} + +/*! + \fn void QRadioTuner::bandChanged(QRadioTuner::Band band) + + Signals a radio tuner's \a band has changed. + \since 1.0 +*/ + +/*! + \fn void QRadioTuner::frequencyChanged(int frequency) + + Signals that the \a frequency a radio tuner is tuned to has changed. + \since 1.0 +*/ + +/*! + \fn void QRadioTuner::mutedChanged(bool muted) + + Signals that the \a muted state of a radio tuner's audio output has changed. + \since 1.0 +*/ + +/*! + \fn void QRadioTuner::volumeChanged(int volume) + + Signals that the \a volume of a radio tuner's audio output has changed. + \since 1.0 +*/ + +/*! + \fn void QRadioTuner::searchingChanged(bool searching) + + Signals that the \a searching state of a radio tuner has changed. + \since 1.0 +*/ + +/*! + \fn void QRadioTuner::stereoStatusChanged(bool stereo) + + Signals that the \a stereo state of a radio tuner has changed. + \since 1.0 +*/ + +/*! + \fn void QRadioTuner::signalStrengthChanged(int strength) + + Signals that the \a strength of the signal received by a radio tuner has changed. + \since 1.0 +*/ + +/*! + \fn void QRadioTuner::error(QRadioTuner::Error error) + + Signals that an \a error occurred. + \since 1.0 +*/ + +/*! + \enum QRadioTuner::State + + Enumerates radio tuner states. + + \value ActiveState The tuner is started and active. + \value StoppedState The tuner device is stopped. +*/ + + +/*! + \enum QRadioTuner::Band + + Enumerates radio frequency bands. + + \value AM 520 to 1610 kHz, 9 or 10kHz channel spacing, extended 1610 to 1710 kHz + \value FM 87.5 to 108.0 MHz, except Japan 76-90 MHz + \value SW 1.711 to 30.0 MHz, divided into 15 bands. 5kHz channel spacing + \value LW 148.5 to 283.5 kHz, 9kHz channel spacing (Europe, Africa, Asia) + \value FM2 range not defined, used when area supports more than one FM range. +*/ + +/*! + \enum QRadioTuner::Error + + Enumerates radio tuner error conditions. + + \value NoError No errors have occurred. + \value ResourceError There is no radio service available. + \value OpenError Unable to open radio device. + \value OutOfRangeError An attempt to set a frequency or band that is not supported by radio device. +*/ + +/*! + \enum QRadioTuner::StereoMode + + Enumerates radio tuner policy for receiving stereo signals. + + \value Auto Uses the stereo mode matching the station. + \value ForceStereo Provide stereo mode, converting if required. + \value ForceMono Provide mono mode, converting if required. +*/ + +/*! \fn void QRadioTuner::stateChanged(QRadioTuner::State state) + This signal is emitted when the state changes to \a state. + \since 1.0 + */ + +#include "moc_qradiotuner.cpp" +QT_END_NAMESPACE + diff --git a/src/multimedia/qradiotuner.h b/src/multimedia/qradiotuner.h new file mode 100644 index 000000000..78852638c --- /dev/null +++ b/src/multimedia/qradiotuner.h @@ -0,0 +1,158 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QRADIOTUNER_H +#define QRADIOTUNER_H + +#include <QtCore/qobject.h> + +#include "qmediaobject.h" +#include "qmediaserviceprovider.h" +#include <qmediaenumdebug.h> + +#include <QPair> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + +class QRadioTunerPrivate; +class Q_MULTIMEDIA_EXPORT QRadioTuner : public QMediaObject +{ + Q_OBJECT + Q_PROPERTY(State state READ state NOTIFY stateChanged) + Q_PROPERTY(Band band READ band WRITE setBand NOTIFY bandChanged) + Q_PROPERTY(int frequency READ frequency WRITE setFrequency NOTIFY frequencyChanged) + Q_PROPERTY(bool stereo READ isStereo NOTIFY stereoStatusChanged) + Q_PROPERTY(StereoMode stereoMode READ stereoMode WRITE setStereoMode) + Q_PROPERTY(int signalStrength READ signalStrength NOTIFY signalStrengthChanged) + Q_PROPERTY(int volume READ volume WRITE setVolume NOTIFY volumeChanged) + Q_PROPERTY(bool muted READ isMuted WRITE setMuted NOTIFY mutedChanged) + Q_PROPERTY(bool searching READ isSearching NOTIFY searchingChanged) + Q_ENUMS(State) + Q_ENUMS(Band) + Q_ENUMS(Error) + Q_ENUMS(StereoMode) + +public: + enum State { ActiveState, StoppedState }; + enum Band { AM, FM, SW, LW, FM2 }; + enum Error { NoError, ResourceError, OpenError, OutOfRangeError }; + enum StereoMode { ForceStereo, ForceMono, Auto }; + + QRadioTuner(QObject *parent = 0, QMediaServiceProvider *provider = QMediaServiceProvider::defaultServiceProvider()); + ~QRadioTuner(); + + bool isAvailable() const; + QtMultimedia::AvailabilityError availabilityError() const; + + State state() const; + + Band band() const; + + bool isBandSupported(Band b) const; + + int frequency() const; + int frequencyStep(Band band) const; + QPair<int,int> frequencyRange(Band band) const; + + bool isStereo() const; + void setStereoMode(QRadioTuner::StereoMode mode); + StereoMode stereoMode() const; + + int signalStrength() const; + + int volume() const; + bool isMuted() const; + + bool isSearching() const; + + Error error() const; + QString errorString() const; + +public Q_SLOTS: + void searchForward(); + void searchBackward(); + void cancelSearch(); + + void setBand(Band band); + void setFrequency(int frequency); + + void setVolume(int volume); + void setMuted(bool muted); + + void start(); + void stop(); + +Q_SIGNALS: + void stateChanged(QRadioTuner::State state); + void bandChanged(QRadioTuner::Band band); + void frequencyChanged(int frequency); + void stereoStatusChanged(bool stereo); + void searchingChanged(bool searching); + void signalStrengthChanged(int signalStrength); + void volumeChanged(int volume); + void mutedChanged(bool muted); + void error(QRadioTuner::Error error); + +private: + Q_DISABLE_COPY(QRadioTuner) + Q_DECLARE_PRIVATE(QRadioTuner) +}; + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(QRadioTuner::State) +Q_DECLARE_METATYPE(QRadioTuner::Band) +Q_DECLARE_METATYPE(QRadioTuner::Error) +Q_DECLARE_METATYPE(QRadioTuner::StereoMode) + +Q_MEDIA_ENUM_DEBUG(QRadioTuner, State) +Q_MEDIA_ENUM_DEBUG(QRadioTuner, Band) +Q_MEDIA_ENUM_DEBUG(QRadioTuner, Error) +Q_MEDIA_ENUM_DEBUG(QRadioTuner, StereoMode) + +QT_END_HEADER + +#endif // QRADIOPLAYER_H diff --git a/src/multimedia/qradiotunercontrol.cpp b/src/multimedia/qradiotunercontrol.cpp new file mode 100644 index 000000000..97ffd2396 --- /dev/null +++ b/src/multimedia/qradiotunercontrol.cpp @@ -0,0 +1,364 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <qtmultimediadefs.h> +#include "qradiotunercontrol.h" +#include "qmediacontrol_p.h" + +QT_BEGIN_NAMESPACE + + +/*! + \class QRadioTunerControl + \inmodule QtMultimedia + \ingroup multimedia-serv + \since 1.0 + + + \brief The QRadioTunerControl class provides access to the radio tuning + functionality of a QMediaService. + + If a QMediaService can tune an analog radio device it will implement + QRadioTunerControl. This control provides a means to tune a radio device + to a specific \l {setFrequency()}{frequency} as well as search \l + {searchForward()}{forwards} and \l {searchBackward()}{backwards} for a + signal. + + The functionality provided by this control is exposed to application code + through the QRadioTuner class. + + The interface name of QRadioTunerControl is \c com.nokia.Qt.QRadioTunerControl/1.0 as + defined in QRadioTunerControl_iid. + + \sa QMediaService::requestControl(), QRadioTuner +*/ + +/*! + \macro QRadioTunerControl_iid + + \c com.nokia.Qt.QRadioTunerControl/1.0 + + Defines the interface name of the QRadioTunerControl class. + + \relates QRadioTunerControl +*/ + +/*! + Constructs a radio tuner control with the given \a parent. +*/ + +QRadioTunerControl::QRadioTunerControl(QObject *parent): + QMediaControl(*new QMediaControlPrivate, parent) +{ +} + +/*! + Destroys a radio tuner control. +*/ + +QRadioTunerControl::~QRadioTunerControl() +{ +} + +/*! + \fn bool QRadioTunerControl::isAvailable() const + + Returns true if the radio service is ready to use. + \since 1.0 +*/ + +/*! + \fn QtMultimedia::AvailabilityError QRadioTunerControl::availabilityError() const + + Returns the error state of the radio service. + \since 1.0 +*/ + +/*! + \fn QRadioTuner::State QRadioTunerControl::state() const + + Returns the current radio tuner state. + \since 1.0 +*/ + +/*! + \fn QRadioTuner::Band QRadioTunerControl::band() const + + Returns the frequency band a radio tuner is tuned to. + \since 1.0 +*/ + +/*! + \fn void QRadioTunerControl::bandChanged(QRadioTuner::Band band) + + Signals that the frequency \a band a radio tuner is tuned to has changed. + \since 1.0 +*/ + +/*! + \fn void QRadioTunerControl::setBand(QRadioTuner::Band band) + + Sets the frequecy \a band a radio tuner is tuned to. + + Changing the frequency band will reset the frequency to the minimum frequency of the new band. + \since 1.0 +*/ + +/*! + \fn bool QRadioTunerControl::isBandSupported(QRadioTuner::Band band) const + + Identifies if a frequency \a band is supported. + + Returns true if the band is supported, and false if it is not. + \since 1.0 +*/ + +/*! + \fn int QRadioTunerControl::frequency() const + + Returns the frequency a radio tuner is tuned to. + \since 1.0 +*/ + +/*! + \fn int QRadioTunerControl::frequencyStep(QRadioTuner::Band band) const + + Returns the number of Hertz to increment the frequency by when stepping through frequencies + within a given \a band. + \since 1.0 +*/ + +/*! + \fn QPair<int,int> QRadioTunerControl::frequencyRange(QRadioTuner::Band band) const + + Returns a frequency \a band's minimum and maximum frequency. + \since 1.0 +*/ + +/*! + \fn void QRadioTunerControl::setFrequency(int frequency) + + Sets the \a frequency a radio tuner is tuned to. + \since 1.0 +*/ + +/*! + \fn bool QRadioTunerControl::isStereo() const + + Identifies if a radio tuner is receiving a stereo signal. + + Returns true if the tuner is receiving a stereo signal, and false if it is not. + \since 1.0 +*/ + +/*! + \fn QRadioTuner::StereoMode QRadioTunerControl::stereoMode() const + + Returns a radio tuner's stereo mode. + + \since 1.0 + \sa QRadioTuner::StereoMode +*/ + +/*! + \fn void QRadioTunerControl::setStereoMode(QRadioTuner::StereoMode mode) + + Sets a radio tuner's stereo \a mode. + + \since 1.0 + \sa QRadioTuner::StereoMode +*/ + +/*! + \fn int QRadioTunerControl::signalStrength() const + + Return a radio tuner's current signal strength as a percentage. + \since 1.0 +*/ + +/*! + \fn int QRadioTunerControl::volume() const + + Returns the volume of a radio tuner's audio output as a percentage. + \since 1.0 +*/ + +/*! + \fn void QRadioTunerControl::setVolume(int volume) + + Sets the percentage \a volume of a radio tuner's audio output. + \since 1.0 +*/ + +/*! + \fn bool QRadioTunerControl::isMuted() const + + Identifies if a radio tuner's audio output is muted. + + Returns true if the audio is muted, and false if it is not. + \since 1.0 +*/ + +/*! + \fn void QRadioTunerControl::setMuted(bool muted) + + Sets the \a muted state of a radio tuner's audio output. + \since 1.0 +*/ + +/*! + \fn bool QRadioTunerControl::isSearching() const + + Identifies if a radio tuner is currently scanning for signal. + + Returns true if the tuner is scanning, and false if it is not. + \since 1.0 +*/ + +/*! + \fn void QRadioTunerControl::searchForward() + + Starts a forward scan for a signal, starting from the current \l frequency(). + \since 1.0 +*/ + +/*! + \fn void QRadioTunerControl::searchBackward() + + Starts a backwards scan for a signal, starting from the current \l frequency(). + \since 1.0 +*/ + +/*! + \fn void QRadioTunerControl::cancelSearch() + + Stops scanning for a signal. + \since 1.0 +*/ + +/*! + \fn void QRadioTunerControl::start() + + Activate the radio device. + \since 1.0 +*/ + +/*! + \fn QRadioTunerControl::stop() + + Deactivate the radio device. + \since 1.0 +*/ + +/*! + \fn QRadioTuner::Error QRadioTunerControl::error() const + + Returns the error state of a radio tuner. + \since 1.0 +*/ + +/*! + \fn QString QRadioTunerControl::errorString() const + + Returns a string describing a radio tuner's error state. + \since 1.0 +*/ + +/*! + \fn void QRadioTunerControl::stateChanged(QRadioTuner::State state) + + Signals that the \a state of a radio tuner has changed. + \since 1.0 +*/ + + +/*! + \fn void QRadioTunerControl::frequencyChanged(int frequency) + + Signals that the \a frequency a radio tuner is tuned to has changed. + \since 1.0 +*/ + +/*! + \fn void QRadioTunerControl::stereoStatusChanged(bool stereo) + + Signals that the \a stereo state of a radio tuner has changed. + \since 1.0 +*/ + +/*! + \fn void QRadioTunerControl::searchingChanged(bool searching) + + Signals that the \a searching state of a radio tuner has changed. + \since 1.0 +*/ + +/*! + \fn void QRadioTunerControl::signalStrengthChanged(int strength) + + Signals that the percentage \a strength of the signal received by a radio tuner has changed. + \since 1.0 +*/ + +/*! + \fn void QRadioTunerControl::volumeChanged(int volume) + + Signals that the percentage \a volume of radio tuner's audio output has changed. + \since 1.0 +*/ + +/*! + \fn void QRadioTunerControl::mutedChanged(bool muted) + + Signals that the \a muted state of a radio tuner's audio output has changed. + \since 1.0 +*/ + +/*! + \fn void QRadioTunerControl::error(QRadioTuner::Error error) + + Signals that an \a error has occurred. + \since 1.0 +*/ + +#include "moc_qradiotunercontrol.cpp" +QT_END_NAMESPACE + diff --git a/src/multimedia/qradiotunercontrol.h b/src/multimedia/qradiotunercontrol.h new file mode 100644 index 000000000..04812be48 --- /dev/null +++ b/src/multimedia/qradiotunercontrol.h @@ -0,0 +1,123 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QRADIOTUNERCONTROL_H +#define QRADIOTUNERCONTROL_H + +#include "qmediacontrol.h" +#include "qradiotuner.h" + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + +class Q_MULTIMEDIA_EXPORT QRadioTunerControl : public QMediaControl +{ + Q_OBJECT + +public: + ~QRadioTunerControl(); + + virtual bool isAvailable() const = 0; + virtual QtMultimedia::AvailabilityError availabilityError() const = 0; + + virtual QRadioTuner::State state() const = 0; + + virtual QRadioTuner::Band band() const = 0; + virtual void setBand(QRadioTuner::Band b) = 0; + virtual bool isBandSupported(QRadioTuner::Band b) const = 0; + + virtual int frequency() const = 0; + virtual int frequencyStep(QRadioTuner::Band b) const = 0; + virtual QPair<int,int> frequencyRange(QRadioTuner::Band b) const = 0; + virtual void setFrequency(int frequency) = 0; + + virtual bool isStereo() const = 0; + virtual QRadioTuner::StereoMode stereoMode() const = 0; + virtual void setStereoMode(QRadioTuner::StereoMode mode) = 0; + + virtual int signalStrength() const = 0; + + virtual int volume() const = 0; + virtual void setVolume(int volume) = 0; + + virtual bool isMuted() const = 0; + virtual void setMuted(bool muted) = 0; + + virtual bool isSearching() const = 0; + + virtual void searchForward() = 0; + virtual void searchBackward() = 0; + virtual void cancelSearch() = 0; + + virtual void start() = 0; + virtual void stop() = 0; + + virtual QRadioTuner::Error error() const = 0; + virtual QString errorString() const = 0; + +Q_SIGNALS: + void stateChanged(QRadioTuner::State state); + void bandChanged(QRadioTuner::Band band); + void frequencyChanged(int frequency); + void stereoStatusChanged(bool stereo); + void searchingChanged(bool searching); + void signalStrengthChanged(int signalStrength); + void volumeChanged(int volume); + void mutedChanged(bool muted); + void error(QRadioTuner::Error err); + +protected: + QRadioTunerControl(QObject *parent = 0); +}; + +#define QRadioTunerControl_iid "com.nokia.Qt.QRadioTunerControl/1.0" +Q_MEDIA_DECLARE_CONTROL(QRadioTunerControl, QRadioTunerControl_iid) + +QT_END_NAMESPACE + +QT_END_HEADER + + +#endif // QRADIOTUNERCONTROL_H diff --git a/src/multimedia/qtmedianamespace.h b/src/multimedia/qtmedianamespace.h new file mode 100644 index 000000000..4296b188d --- /dev/null +++ b/src/multimedia/qtmedianamespace.h @@ -0,0 +1,339 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTMEDIANAMESPACE_H +#define QTMEDIANAMESPACE_H + +#include <QtCore/qpair.h> +#include <QtCore/qmetatype.h> + +#include <qtmultimediadefs.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + +// For now, for backwards source compatibility +// we have a copy of these enums +// But if you add a new enum value, you won't need +// to copy it to the QtMMK enums since it can't have +// been used before. +namespace QtMultimedia +{ + enum MetaData + { + // Common + Title, + SubTitle, + Author, + Comment, + Description, + Category, + Genre, + Year, + Date, + UserRating, + Keywords, + Language, + Publisher, + Copyright, + ParentalRating, + RatingOrganisation, + + // Media + Size, + MediaType, + Duration, + + // Audio + AudioBitRate, + AudioCodec, + AverageLevel, + ChannelCount, + PeakValue, + SampleRate, + + // Music + AlbumTitle, + AlbumArtist, + ContributingArtist, + Composer, + Conductor, + Lyrics, + Mood, + TrackNumber, + TrackCount, + + CoverArtUrlSmall, + CoverArtUrlLarge, + + // Image/Video + Resolution, + PixelAspectRatio, + + // Video + VideoFrameRate, + VideoBitRate, + VideoCodec, + + PosterUrl, + + // Movie + ChapterNumber, + Director, + LeadPerformer, + Writer, + + // Photos + CameraManufacturer, + CameraModel, + Event, + Subject, + Orientation, + ExposureTime, + FNumber, + ExposureProgram, + ISOSpeedRatings, + ExposureBiasValue, + DateTimeOriginal, + DateTimeDigitized, + SubjectDistance, + MeteringMode, + LightSource, + Flash, + FocalLength, + ExposureMode, + WhiteBalance, + DigitalZoomRatio, + FocalLengthIn35mmFilm, + SceneCaptureType, + GainControl, + Contrast, + Saturation, + Sharpness, + DeviceSettingDescription, + + PosterImage, + CoverArtImage, + ThumbnailImage + + }; + + enum SupportEstimate + { + NotSupported, + MaybeSupported, + ProbablySupported, + PreferredService + }; + + enum EncodingQuality + { + VeryLowQuality, + LowQuality, + NormalQuality, + HighQuality, + VeryHighQuality + }; + + enum EncodingMode + { + ConstantQualityEncoding, + ConstantBitRateEncoding, + AverageBitRateEncoding, + TwoPassEncoding + }; + + enum AvailabilityError + { + NoError, + ServiceMissingError, + BusyError, + ResourceError + }; + +} + +// For legacy support +namespace QtMultimediaKit +{ + enum MetaData + { + // Common + Title = QtMultimedia::Title, + SubTitle, + Author, + Comment, + Description, + Category, + Genre, + Year, + Date, + UserRating, + Keywords, + Language, + Publisher, + Copyright, + ParentalRating, + RatingOrganisation, + + // Media + Size, + MediaType, + Duration, + + // Audio + AudioBitRate, + AudioCodec, + AverageLevel, + ChannelCount, + PeakValue, + SampleRate, + + // Music + AlbumTitle, + AlbumArtist, + ContributingArtist, + Composer, + Conductor, + Lyrics, + Mood, + TrackNumber, + TrackCount, + + CoverArtUrlSmall, + CoverArtUrlLarge, + + // Image/Video + Resolution, + PixelAspectRatio, + + // Video + VideoFrameRate, + VideoBitRate, + VideoCodec, + + PosterUrl, + + // Movie + ChapterNumber, + Director, + LeadPerformer, + Writer, + + // Photos + CameraManufacturer, + CameraModel, + Event, + Subject, + Orientation, + ExposureTime, + FNumber, + ExposureProgram, + ISOSpeedRatings, + ExposureBiasValue, + DateTimeOriginal, + DateTimeDigitized, + SubjectDistance, + MeteringMode, + LightSource, + Flash, + FocalLength, + ExposureMode, + WhiteBalance, + DigitalZoomRatio, + FocalLengthIn35mmFilm, + SceneCaptureType, + GainControl, + Contrast, + Saturation, + Sharpness, + DeviceSettingDescription, + + PosterImage, + CoverArtImage, + ThumbnailImage + + }; + + enum SupportEstimate + { + NotSupported = QtMultimedia::NotSupported, + MaybeSupported, + ProbablySupported, + PreferredService + }; + + enum EncodingQuality + { + VeryLowQuality = QtMultimedia::VeryLowQuality, + LowQuality, + NormalQuality, + HighQuality, + VeryHighQuality + }; + + enum EncodingMode + { + ConstantQualityEncoding = QtMultimedia::ConstantQualityEncoding, + ConstantBitRateEncoding, + AverageBitRateEncoding, + TwoPassEncoding + }; + + enum AvailabilityError + { + NoError = QtMultimedia::NoError, + ServiceMissingError, + BusyError, + ResourceError + }; + +} + +QT_END_NAMESPACE + +QT_END_HEADER + + +#endif diff --git a/src/multimedia/qtmedianamespace.qdoc b/src/multimedia/qtmedianamespace.qdoc new file mode 100644 index 000000000..bc998e930 --- /dev/null +++ b/src/multimedia/qtmedianamespace.qdoc @@ -0,0 +1,208 @@ +/**************************************************************************** +** +** 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 documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** GNU Free Documentation License +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms +** and conditions contained in a signed written agreement between you +** and Nokia. +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \namespace QtMultimedia + \ingroup multimedia + \inmodule QtMultimedia + + \brief The QtMultimedia namespace contains miscellaneous identifiers used throughout the Qt Media services library. + + QtMultimedia is a module containing the low level, low latency, + Multimedia APIs which were introduced in Qt 4.6 and also includes the + high level QtMultimedia APIs which were introduced in QtMobility 1.0. + +*/ + +/*! + \enum QtMultimedia::MetaData + + This enum provides identifiers for meta-data attributes. + + \note Not all identifiers are supported on all platforms. Please consult vendor documentation for specific support + on different platforms. + + Common attributes + \value Title The title of the media. QString. + \value SubTitle The sub-title of the media. QString. + \value Author The authors of the media. QStringList. + \value Comment A user comment about the media. QString. + \value Description A description of the media. QString + \value Category The category of the media. QStringList. + \value Genre The genre of the media. QStringList. + \value Year The year of release of the media. int. + \value Date The date of the media. QDate. + \value UserRating A user rating of the media. int [0..100]. + \value Keywords A list of keywords describing the media. QStringList. + \value Language The language of media, as an ISO 639-2 code. + + \value Publisher The publisher of the media. QString. + \value Copyright The media's copyright notice. QString. + \value ParentalRating The parental rating of the media. QString. + \value RatingOrganisation The organisation responsible for the parental rating of the media. + QString. + + Media attributes + \value Size The size in bytes of the media. qint64 + \value MediaType The type of the media (audio, video, etc). QString. + \value Duration The duration in millseconds of the media. qint64. + + Audio attributes + \value AudioBitRate The bit rate of the media's audio stream in bits per second. int. + \value AudioCodec The codec of the media's audio stream. QString. + \value AverageLevel The average volume level of the media. int. + \value ChannelCount The number of channels in the media's audio stream. int. + \value PeakValue The peak volume of the media's audio stream. int + \value SampleRate The sample rate of the media's audio stream in hertz. int + + Music attributes + \value AlbumTitle The title of the album the media belongs to. QString. + \value AlbumArtist The principal artist of the album the media belongs to. QString. + \value ContributingArtist The artists contributing to the media. QStringList. + \value Composer The composer of the media. QStringList. + \value Conductor The conductor of the media. QString. + \value Lyrics The lyrics to the media. QString. + \value Mood The mood of the media. QString. + \value TrackNumber The track number of the media. int. + \value TrackCount The number of tracks on the album containing the media. int. + + \value CoverArtUrlSmall The URL of a small cover art image. QUrl. + \value CoverArtUrlLarge The URL of a large cover art image. QUrl. + \value CoverArtImage An embedded cover art image. QImage. + + Image and video attributes + \value Resolution The dimensions of an image or video. QSize. + \value PixelAspectRatio The pixel aspect ratio of an image or video. QSize. + + Video attributes + \value VideoFrameRate The frame rate of the media's video stream. qreal. + \value VideoBitRate The bit rate of the media's video stream in bits per second. int. + \value VideoCodec The codec of the media's video stream. QString. + + \value PosterUrl The URL of a poster image. QUrl. + \value PosterImage An embedded poster image. QImage. + + Movie attributes + \value ChapterNumber The chapter number of the media. int. + \value Director The director of the media. QString. + \value LeadPerformer The lead performer in the media. QStringList. + \value Writer The writer of the media. QStringList. + + Photo attributes. + \value CameraManufacturer The manufacturer of the camera used to capture the media. QString. + \value CameraModel The model of the camera used to capture the media. QString. + \value Event The event during which the media was captured. QString. + \value Subject The subject of the media. QString. + \value Orientation Orientation of image. + \value ExposureTime Exposure time, given in seconds. + \value FNumber The F Number. + \value ExposureProgram + The class of the program used by the camera to set exposure when the picture is taken. + \value ISOSpeedRatings + Indicates the ISO Speed and ISO Latitude of the camera or input device as specified in ISO 12232. + \value ExposureBiasValue + The exposure bias. + The unit is the APEX (Additive System of Photographic Exposure) setting. + \value DateTimeOriginal The date and time when the original image data was generated. + \value DateTimeDigitized The date and time when the image was stored as digital data. + \value SubjectDistance The distance to the subject, given in meters. + \value MeteringMode The metering mode. + \value LightSource + The kind of light source. + \value Flash + Status of flash when the image was shot. + \value FocalLength + The actual focal length of the lens, in mm. + \value ExposureMode + Indicates the exposure mode set when the image was shot. + \value WhiteBalance + Indicates the white balance mode set when the image was shot. + \value DigitalZoomRatio + Indicates the digital zoom ratio when the image was shot. + \value FocalLengthIn35mmFilm + Indicates the equivalent focal length assuming a 35mm film camera, in mm. + \value SceneCaptureType + Indicates the type of scene that was shot. + It can also be used to record the mode in which the image was shot. + \value GainControl + Indicates the degree of overall image gain adjustment. + \value Contrast + Indicates the direction of contrast processing applied by the camera when the image was shot. + \value Saturation + Indicates the direction of saturation processing applied by the camera when the image was shot. + \value Sharpness + Indicates the direction of sharpness processing applied by the camera when the image was shot. + \value DeviceSettingDescription + Exif tag, indicates information on the picture-taking conditions of a particular camera model. QString + + \value ThumbnailImage An embedded thumbnail image. QImage. +*/ + +/*! + \enum QtMultimedia::SupportEstimate + + Enumerates the levels of support a media service provider may have for a feature. + + \value NotSupported The feature is not supported. + \value MaybeSupported The feature may be supported. + \value ProbablySupported The feature is probably supported. + \value PreferredService The service is the preferred provider of a service. +*/ + +/*! + \enum QtMultimedia::EncodingQuality + + Enumerates quality encoding levels. + + \value VeryLowQuality + \value LowQuality + \value NormalQuality + \value HighQuality + \value VeryHighQuality +*/ + +/*! + \enum QtMultimedia::EncodingMode + + Enumerates encoding modes. + + \value ConstantQualityEncoding + \value ConstantBitRateEncoding + \value AverageBitRateEncoding + \value TwoPassEncoding +*/ + +/*! + \enum QtMultimedia::AvailabilityError + + Enumerates Service status errors. + + \value NoError The service is operating correctly. + \value ServiceMissingError There is no service available to provide the requested functionality. + \value ResourceError The service could not allocate resources required to function correctly. + \value BusyError The service must wait for access to necessary resources. +*/ diff --git a/src/multimedia/qtmultimediadefs.h b/src/multimedia/qtmultimediadefs.h new file mode 100644 index 000000000..313503929 --- /dev/null +++ b/src/multimedia/qtmultimediadefs.h @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#ifndef QTMULTIMEDIA_P_H +#define QTMULTIMEDIA_P_H + +#include <QtCore/qglobal.h> + +QT_BEGIN_HEADER + +#if defined(Q_OS_WIN) +# if defined(QT_NODLL) +# undef QT_MAKEDLL +# undef QT_DLL +# elif defined(QT_MAKEDLL) +# if defined(QT_DLL) +# undef QT_DLL +# endif +# if defined(QT_BUILD_MULTIMEDIA_LIB) +# define Q_MULTIMEDIA_EXPORT Q_DECL_EXPORT +# else +# define Q_MULTIMEDIA_EXPORT Q_DECL_IMPORT +# endif +# elif defined(QT_DLL) /* use a Qt DLL library */ +# define Q_MULTIMEDIA_EXPORT Q_DECL_IMPORT +# endif +#endif + +#if !defined(Q_MULTIMEDIA_EXPORT) +# if defined(QT_SHARED) +# define Q_MULTIMEDIA_EXPORT Q_DECL_EXPORT +# else +# define Q_MULTIMEDIA_EXPORT +# endif +#endif + +QT_END_HEADER + + +#endif // QMULTIMEDIA_P_H + diff --git a/src/multimedia/qvideodevicecontrol.cpp b/src/multimedia/qvideodevicecontrol.cpp new file mode 100644 index 000000000..a864fd580 --- /dev/null +++ b/src/multimedia/qvideodevicecontrol.cpp @@ -0,0 +1,159 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qvideodevicecontrol.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QVideoDeviceControl + + \brief The QVideoDeviceControl class provides an video device selector media control. + \inmodule QtMultimedia + \ingroup multimedia-serv + \since 1.0 + + The QVideoDeviceControl class provides descriptions of the video devices + available on a system and allows one to be selected as the endpoint of a + media service. + + The interface name of QVideoDeviceControl is \c com.nokia.Qt.VideoDeviceControl as + defined in QVideoDeviceControl_iid. +*/ + +/*! + \macro QVideoDeviceControl_iid + + \c com.nokia.Qt.VideoDeviceControl + + Defines the interface name of the QVideoDeviceControl class. + + \relates QVideoDeviceControl +*/ + +/*! + Constructs a video device control with the given \a parent. +*/ +QVideoDeviceControl::QVideoDeviceControl(QObject *parent) + :QMediaControl(parent) +{ +} + +/*! + Destroys a video device control. +*/ +QVideoDeviceControl::~QVideoDeviceControl() +{ +} + +/*! + \fn QVideoDeviceControl::deviceCount() const + + Returns the number of available video devices; + \since 1.0 +*/ + +/*! + \fn QVideoDeviceControl::deviceName(int index) const + + Returns the name of the video device at \a index. + \since 1.0 +*/ + +/*! + \fn QVideoDeviceControl::deviceDescription(int index) const + + Returns a description of the video device at \a index. + \since 1.0 +*/ + +/*! + \fn QVideoDeviceControl::deviceIcon(int index) const + + Returns an icon for the video device at \a index. + \since 1.0 +*/ + +/*! + \fn QVideoDeviceControl::defaultDevice() const + + Returns the index of the default video device. + \since 1.0 +*/ + +/*! + \fn QVideoDeviceControl::selectedDevice() const + + Returns the index of the selected video device. + \since 1.0 +*/ + +/*! + \fn QVideoDeviceControl::setSelectedDevice(int index) + + Sets the selected video device \a index. + \since 1.0 +*/ + +/*! + \fn QVideoDeviceControl::devicesChanged() + + Signals that the list of available video devices has changed. + \since 1.0 +*/ + +/*! + \fn QVideoDeviceControl::selectedDeviceChanged(int index) + + Signals that the selected video device \a index has changed. + \since 1.0 +*/ + +/*! + \fn QVideoDeviceControl::selectedDeviceChanged(const QString &name) + + Signals that the selected video device \a name has changed. + \since 1.0 +*/ + +#include "moc_qvideodevicecontrol.cpp" +QT_END_NAMESPACE + diff --git a/src/multimedia/qvideodevicecontrol.h b/src/multimedia/qvideodevicecontrol.h new file mode 100644 index 000000000..6f44c4671 --- /dev/null +++ b/src/multimedia/qvideodevicecontrol.h @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QVIDEODEVICECONTROL_H +#define QVIDEODEVICECONTROL_H + +#include "qmediacontrol.h" + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + +class Q_MULTIMEDIA_EXPORT QVideoDeviceControl : public QMediaControl +{ + Q_OBJECT + +public: + virtual ~QVideoDeviceControl(); + + virtual int deviceCount() const = 0; + + virtual QString deviceName(int index) const = 0; + virtual QString deviceDescription(int index) const = 0; + virtual QIcon deviceIcon(int index) const = 0; + + virtual int defaultDevice() const = 0; + virtual int selectedDevice() const = 0; + +public Q_SLOTS: + virtual void setSelectedDevice(int index) = 0; + +Q_SIGNALS: + void selectedDeviceChanged(int index); + void selectedDeviceChanged(const QString &deviceName); + void devicesChanged(); + +protected: + QVideoDeviceControl(QObject *parent = 0); +}; + +#define QVideoDeviceControl_iid "com.nokia.Qt.QVideoDeviceControl/1.0" +Q_MEDIA_DECLARE_CONTROL(QVideoDeviceControl, QVideoDeviceControl_iid) + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QVIDEODEVICECONTROL_H diff --git a/src/multimedia/qvideoencodercontrol.cpp b/src/multimedia/qvideoencodercontrol.cpp new file mode 100644 index 000000000..1551f2cf7 --- /dev/null +++ b/src/multimedia/qvideoencodercontrol.cpp @@ -0,0 +1,190 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qvideoencodercontrol.h" +#include <QtCore/qstringlist.h> +#include <QtCore/qvariant.h> + +QT_BEGIN_NAMESPACE + +/*! + \class QVideoEncoderControl + + \inmodule QtMultimedia + \ingroup multimedia-serv + \since 1.0 + + \brief The QVideoEncoderControl class provides access to the settings + of a media service that performs video encoding. + + If a QMediaService supports encoding video data it will implement + QVideoEncoderControl. This control provides information about the limits + of restricted video encoder options and allows the selection of a set of + video encoder settings as specified in a QVideoEncoderSettings object. + + The functionality provided by this control is exposed to application code + through the QMediaRecorder class. + + The interface name of QVideoEncoderControl is \c com.nokia.Qt.QVideoEncoderControl/1.0 as + defined in QVideoEncoderControl_iid. + + \sa QMediaRecorder, QVideoEncoderSettings, QMediaService::requestControl() +*/ + +/*! + \macro QVideoEncoderControl_iid + + \c com.nokia.Qt.QVideoEncoderControl/1.0 + + Defines the interface name of the QVideoEncoderControl class. + + \relates QVideoEncoderControl +*/ + +/*! + Create a new video encoder control object with the given \a parent. +*/ +QVideoEncoderControl::QVideoEncoderControl(QObject *parent) + :QMediaControl(parent) +{ +} + +/*! + Destroys a video encoder control. +*/ +QVideoEncoderControl::~QVideoEncoderControl() +{ +} + +/*! + \fn QVideoEncoderControl::supportedVideoCodecs() const + + Returns the list of supported video codecs. + \since 1.0 +*/ + +/*! + \fn QVideoEncoderControl::videoCodecDescription(const QString &codec) const + + Returns a description of a video \a codec. + \since 1.0 +*/ + +/*! + \fn QVideoEncoderControl::supportedEncodingOptions(const QString &codec) const + + Returns a list of supported encoding options for a video \a codec. + + The names and types of the options in the list is system dependent. + \since 1.0 +*/ + +/*! + \fn QVideoEncoderControl::encodingOption(const QString &codec, const QString &option) const + + Returns the value of a video \a codec \a option. + \since 1.0 +*/ + +/*! + \fn QVideoEncoderControl::setEncodingOption(const QString &codec, const QString &option, const QVariant &value) + + Sets the \a value of a \a codec specific \a option. + \since 1.0 +*/ + +/*! + \fn QVideoEncoderControl::supportedResolutions(const QVideoEncoderSettings &settings = QVideoEncoderSettings(), + bool *continuous = 0) const + + Returns a list of supported resolutions. + + If non null video \a settings parameter is passed, + the returned list is reduced to resolution supported with partial settings like + \l {QVideoEncoderSettings::setCodec()}{video codec} or + \l {QVideoEncoderSettings::setFrameRate()}{frame rate} applied. + + If the encoder supports arbitrary resolutions within the supported resolutions range, + *\a continuous is set to true, otherwise *\a continuous is set to false. + + \since 1.0 + \sa QVideoEncoderSettings::resolution() +*/ + +/*! + \fn QVideoEncoderControl::supportedFrameRates(const QVideoEncoderSettings &settings = QVideoEncoderSettings(), + bool *continuous = 0) const + + Returns a list of supported frame rates. + + If non null video \a settings parameter is passed, + the returned list is reduced to frame rates supported with partial settings like + \l {QVideoEncoderSettings::setCodec()}{video codec} or + \l {QVideoEncoderSettings::setResolution()}{video resolution} applied. + + If the encoder supports arbitrary frame rates within the supported range, + *\a continuous is set to true, otherwise *\a continuous is set to false. + + \since 1.0 + \sa QVideoEncoderSettings::frameRate() +*/ + +/*! + \fn QVideoEncoderControl::videoSettings() const + + Returns the video encoder settings. + + The returned value may be different tha passed to QVideoEncoderControl::setVideoSettings() + if the settings contains the default or undefined parameters. + In this case if the undefined parameters are already resolved, they should be returned. + \since 1.0 +*/ + +/*! + \fn QVideoEncoderControl::setVideoSettings(const QVideoEncoderSettings &settings) + + Sets the selected video encoder \a settings. + \since 1.0 +*/ + +#include "moc_qvideoencodercontrol.cpp" +QT_END_NAMESPACE + diff --git a/src/multimedia/qvideoencodercontrol.h b/src/multimedia/qvideoencodercontrol.h new file mode 100644 index 000000000..343af8039 --- /dev/null +++ b/src/multimedia/qvideoencodercontrol.h @@ -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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QVIDEOENCODERCONTROL_H +#define QVIDEOENCODERCONTROL_H + +#include "qmediacontrol.h" +#include "qmediarecorder.h" + +#include <QtCore/qpair.h> +#include <QtCore/qsize.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + +class QByteArray; +class QStringList; +QT_END_NAMESPACE + +QT_BEGIN_NAMESPACE + +class Q_MULTIMEDIA_EXPORT QVideoEncoderControl : public QMediaControl +{ + Q_OBJECT + +public: + virtual ~QVideoEncoderControl(); + + virtual QList<QSize> supportedResolutions(const QVideoEncoderSettings &settings, + bool *continuous = 0) const = 0; + + virtual QList<qreal> supportedFrameRates(const QVideoEncoderSettings &settings, + bool *continuous = 0) const = 0; + + virtual QStringList supportedVideoCodecs() const = 0; + virtual QString videoCodecDescription(const QString &codecName) const = 0; + + virtual QVideoEncoderSettings videoSettings() const = 0; + virtual void setVideoSettings(const QVideoEncoderSettings &settings) = 0; + + virtual QStringList supportedEncodingOptions(const QString &codec) const = 0; + virtual QVariant encodingOption(const QString &codec, const QString &name) const = 0; + virtual void setEncodingOption(const QString &codec, const QString &name, const QVariant &value) = 0; + +protected: + QVideoEncoderControl(QObject *parent = 0); +}; + +#define QVideoEncoderControl_iid "com.nokia.Qt.QVideoEncoderControl/1.0" +Q_MEDIA_DECLARE_CONTROL(QVideoEncoderControl, QVideoEncoderControl_iid) + +QT_END_NAMESPACE + +QT_END_HEADER + + +#endif diff --git a/src/multimedia/qvideorenderercontrol.cpp b/src/multimedia/qvideorenderercontrol.cpp new file mode 100644 index 000000000..99142261a --- /dev/null +++ b/src/multimedia/qvideorenderercontrol.cpp @@ -0,0 +1,114 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qvideorenderercontrol.h" + +#include "qmediacontrol_p.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QVideoRendererControl + + + \brief The QVideoRendererControl class provides a control for rendering + to a video surface. + + \inmodule QtMultimedia + \ingroup multimedia-serv + \since 1.0 + + Using the surface() property of QVideoRendererControl a + QAbstractVideoSurface may be set as the video render target of a + QMediaService. + + \snippet doc/src/snippets/multimedia-snippets/video.cpp Video renderer control + + QVideoRendererControl is one of a number of possible video output controls. + + The interface name of QVideoRendererControl is \c com.nokia.Qt.QVideoRendererControl/1.0 as + defined in QVideoRendererControl_iid. + + \sa QMediaService::requestControl(), QVideoWidget +*/ + +/*! + \macro QVideoRendererControl_iid + + \c com.nokia.Qt.QVideoRendererControl/1.0 + + Defines the interface name of the QVideoRendererControl class. + + \relates QVideoRendererControl +*/ + +/*! + Constructs a new video renderer media end point with the given \a parent. +*/ +QVideoRendererControl::QVideoRendererControl(QObject *parent) + : QMediaControl(parent) +{ +} + +/*! + Destroys a video renderer media end point. +*/ +QVideoRendererControl::~QVideoRendererControl() +{ +} + +/*! + \fn QVideoRendererControl::surface() const + + Returns the surface a video producer renders to. + \since 1.0 +*/ + +/*! + \fn QVideoRendererControl::setSurface(QAbstractVideoSurface *surface) + + Sets the \a surface a video producer renders to. + \since 1.0 +*/ + +#include "moc_qvideorenderercontrol.cpp" +QT_END_NAMESPACE + diff --git a/src/multimedia/qvideorenderercontrol.h b/src/multimedia/qvideorenderercontrol.h new file mode 100644 index 000000000..b3a70837c --- /dev/null +++ b/src/multimedia/qvideorenderercontrol.h @@ -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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QVIDEORENDERERCONTROL_H +#define QVIDEORENDERERCONTROL_H + +#include "qmediacontrol.h" + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + +class QAbstractVideoSurface; +QT_END_NAMESPACE + +QT_BEGIN_NAMESPACE + + +class Q_MULTIMEDIA_EXPORT QVideoRendererControl : public QMediaControl +{ + Q_OBJECT + +public: + ~QVideoRendererControl(); + + virtual QAbstractVideoSurface *surface() const = 0; + virtual void setSurface(QAbstractVideoSurface *surface) = 0; + +protected: + QVideoRendererControl(QObject *parent = 0); +}; + +#define QVideoRendererControl_iid "com.nokia.Qt.QVideoRendererControl/1.0" +Q_MEDIA_DECLARE_CONTROL(QVideoRendererControl, QVideoRendererControl_iid) + +QT_END_NAMESPACE + +QT_END_HEADER + + +#endif // QVIDEORENDERERCONTROL_H diff --git a/src/multimedia/qvideosurfaceoutput.cpp b/src/multimedia/qvideosurfaceoutput.cpp new file mode 100644 index 000000000..cdbec5596 --- /dev/null +++ b/src/multimedia/qvideosurfaceoutput.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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qvideosurfaceoutput_p.h" + +#include <qabstractvideosurface.h> +#include <qmediaservice.h> +#include <qvideorenderercontrol.h> + + +QVideoSurfaceOutput::QVideoSurfaceOutput(QObject*parent) + : QObject(parent) +{ +} + +QVideoSurfaceOutput::~QVideoSurfaceOutput() +{ + if (m_control) { + m_control.data()->setSurface(0); + m_service.data()->releaseControl(m_control.data()); + } +} + +QMediaObject *QVideoSurfaceOutput::mediaObject() const +{ + return m_object.data(); +} + +void QVideoSurfaceOutput::setVideoSurface(QAbstractVideoSurface *surface) +{ + m_surface = surface; + + if (m_control) + m_control.data()->setSurface(surface); +} + +bool QVideoSurfaceOutput::setMediaObject(QMediaObject *object) +{ + if (m_control) { + m_control.data()->setSurface(0); + m_service.data()->releaseControl(m_control.data()); + } + m_control.clear(); + m_service.clear(); + m_object.clear(); + + if (object) { + if (QMediaService *service = object->service()) { + if (QMediaControl *control = service->requestControl(QVideoRendererControl_iid)) { + if ((m_control = qobject_cast<QVideoRendererControl *>(control))) { + m_service = service; + m_object = object; + m_control.data()->setSurface(m_surface.data()); + + return true; + } + service->releaseControl(control); + } + } + } + return false; +} diff --git a/src/multimedia/qvideosurfaceoutput_p.h b/src/multimedia/qvideosurfaceoutput_p.h new file mode 100644 index 000000000..76ec5e84d --- /dev/null +++ b/src/multimedia/qvideosurfaceoutput_p.h @@ -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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QVIDEOSURFACEOUTPUT_P_H +#define QVIDEOSURFACEOUTPUT_P_H + +#include <qmediabindableinterface.h> + +#include <QtCore/qsharedpointer.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + +class QAbstractVideoSurface; +class QVideoRendererControl; + +class QVideoSurfaceOutput : public QObject, public QMediaBindableInterface +{ + Q_OBJECT + Q_INTERFACES(QMediaBindableInterface) +public: + QVideoSurfaceOutput(QObject*parent = 0); + ~QVideoSurfaceOutput(); + + QMediaObject *mediaObject() const; + + void setVideoSurface(QAbstractVideoSurface *surface); + +protected: + bool setMediaObject(QMediaObject *object); + +private: + QWeakPointer<QAbstractVideoSurface> m_surface; + QWeakPointer<QVideoRendererControl> m_control; + QWeakPointer<QMediaService> m_service; + QWeakPointer<QMediaObject> m_object; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + + +#endif diff --git a/src/multimedia/video/qabstractvideobuffer.cpp b/src/multimedia/video/qabstractvideobuffer.cpp new file mode 100644 index 000000000..6480bc850 --- /dev/null +++ b/src/multimedia/video/qabstractvideobuffer.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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qabstractvideobuffer_p.h" + +#include <qvariant.h> + +QT_BEGIN_NAMESPACE + +/*! + \class QAbstractVideoBuffer + \brief The QAbstractVideoBuffer class is an abstraction for video data. + \since 1.0 + \inmodule QtMultimedia + + The QVideoFrame class makes use of a QAbstractVideoBuffer internally to reference a buffer of + video data. Creating a subclass of QAbstractVideoBuffer will allow you to construct video + frames from preallocated or static buffers. + + The contents of a buffer can be accessed by mapping the buffer to memory using the map() + function which returns a pointer to memory containing the contents of the the video buffer. + The memory returned by map() is released by calling the unmap() function. + + The handle() of a buffer may also be used to manipulate its contents using type specific APIs. + The type of a buffer's handle is given by the handleType() function. + + \sa QVideoFrame +*/ + +/*! + \enum QAbstractVideoBuffer::HandleType + + Identifies the type of a video buffers handle. + + \value NoHandle The buffer has no handle, its data can only be accessed by mapping the buffer. + \value GLTextureHandle The handle of the buffer is an OpenGL texture ID. + \value XvShmImageHandle The handle contains pointer to shared memory XVideo image. + \value CoreImageHandle The handle contains pointer to Mac OS X CIImage. + \value QPixmapHandle The handle of the buffer is a QPixmap. + \value UserHandle Start value for user defined handle types. + + \sa handleType() +*/ + +/*! + \enum QAbstractVideoBuffer::MapMode + + Enumerates how a video buffer's data is mapped to memory. + + \value NotMapped The video buffer has is not mapped to memory. + \value ReadOnly The mapped memory is populated with data from the video buffer when mapped, but + the content of the mapped memory may be discarded when unmapped. + \value WriteOnly The mapped memory is uninitialized when mapped, and the content will be used to + populate the video buffer when unmapped. + \value ReadWrite The mapped memory is populated with data from the video buffer, and the + video buffer is repopulated with the content of the mapped memory. + + \sa mapMode(), map() +*/ + +/*! + Constructs an abstract video buffer of the given \a type. +*/ +QAbstractVideoBuffer::QAbstractVideoBuffer(HandleType type) + : d_ptr(new QAbstractVideoBufferPrivate) +{ + Q_D(QAbstractVideoBuffer); + + d->handleType = type; +} + +/*! + \internal +*/ +QAbstractVideoBuffer::QAbstractVideoBuffer(QAbstractVideoBufferPrivate &dd, HandleType type) + : d_ptr(&dd) +{ + Q_D(QAbstractVideoBuffer); + + d->handleType = type; +} + +/*! + Destroys an abstract video buffer. +*/ +QAbstractVideoBuffer::~QAbstractVideoBuffer() +{ + delete d_ptr; +} + +/*! + Returns the type of a video buffer's handle. + + \since 1.0 + \sa handle() +*/ +QAbstractVideoBuffer::HandleType QAbstractVideoBuffer::handleType() const +{ + return d_func()->handleType; +} + +/*! + \fn QAbstractVideoBuffer::mapMode() const + + Returns the mode a video buffer is mapped in. + + \since 1.0 + \sa map() +*/ + +/*! + \fn QAbstractVideoBuffer::map(MapMode mode, int *numBytes, int *bytesPerLine) + + Maps the contents of a video buffer to memory. + + The map \a mode indicates whether the contents of the mapped memory should be read from and/or + written to the buffer. If the map mode includes the QAbstractVideoBuffer::ReadOnly flag the + mapped memory will be populated with the content of the video buffer when mapped. If the map + mode includes the QAbstractVideoBuffer::WriteOnly flag the content of the mapped memory will be + persisted in the buffer when unmapped. + + When access to the data is no longer needed be sure to call the unmap() function to release the + mapped memory. + + Returns a pointer to the mapped memory region, or a null pointer if the mapping failed. The + size in bytes of the mapped memory region is returned in \a numBytes, and the line stride in \a + bytesPerLine. + + When access to the data is no longer needed be sure to unmap() the buffer. + + \note Writing to memory that is mapped as read-only is undefined, and may result in changes + to shared data. + + \since 1.0 + \sa unmap(), mapMode() +*/ + +/*! + \fn QAbstractVideoBuffer::unmap() + + Releases the memory mapped by the map() function + + If the \l {QAbstractVideoBuffer::MapMode}{MapMode} included the QAbstractVideoBuffer::WriteOnly + flag this will persist the current content of the mapped memory to the video frame. + + \since 1.0 + \sa map() +*/ + +/*! + Returns a type specific handle to the data buffer. + + The type of the handle is given by handleType() function. + + \since 1.0 + \sa handleType() +*/ +QVariant QAbstractVideoBuffer::handle() const +{ + return QVariant(); +} + + +QT_END_NAMESPACE diff --git a/src/multimedia/video/qabstractvideobuffer.h b/src/multimedia/video/qabstractvideobuffer.h new file mode 100644 index 000000000..2c66dfd65 --- /dev/null +++ b/src/multimedia/video/qabstractvideobuffer.h @@ -0,0 +1,112 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QABSTRACTVIDEOBUFFER_H +#define QABSTRACTVIDEOBUFFER_H + +#include <qtmultimediadefs.h> +#include <qtmedianamespace.h> + + +#include <QtCore/qmetatype.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + +class QVariant; + +class QAbstractVideoBufferPrivate; + +class Q_MULTIMEDIA_EXPORT QAbstractVideoBuffer +{ +public: + enum HandleType + { + NoHandle, + GLTextureHandle, + XvShmImageHandle, + CoreImageHandle, + QPixmapHandle, + UserHandle = 1000 + }; + + enum MapMode + { + NotMapped = 0x00, + ReadOnly = 0x01, + WriteOnly = 0x02, + ReadWrite = ReadOnly | WriteOnly + }; + + QAbstractVideoBuffer(HandleType type); + virtual ~QAbstractVideoBuffer(); + + HandleType handleType() const; + + virtual MapMode mapMode() const = 0; + + virtual uchar *map(MapMode mode, int *numBytes, int *bytesPerLine) = 0; + virtual void unmap() = 0; + + virtual QVariant handle() const; + +protected: + QAbstractVideoBuffer(QAbstractVideoBufferPrivate &dd, HandleType type); + + QAbstractVideoBufferPrivate *d_ptr; + +private: + Q_DECLARE_PRIVATE(QAbstractVideoBuffer) + Q_DISABLE_COPY(QAbstractVideoBuffer) +}; + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(QAbstractVideoBuffer::HandleType) +Q_DECLARE_METATYPE(QAbstractVideoBuffer::MapMode) + +QT_END_HEADER + +#endif diff --git a/src/multimedia/video/qabstractvideobuffer_p.h b/src/multimedia/video/qabstractvideobuffer_p.h new file mode 100644 index 000000000..b808e5d91 --- /dev/null +++ b/src/multimedia/video/qabstractvideobuffer_p.h @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QABSTRACTVIDEOBUFFER_P_H +#define QABSTRACTVIDEOBUFFER_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtCore/qshareddata.h> +#include "qabstractvideobuffer.h" + +#include <qtmultimediadefs.h> +#include <qtmedianamespace.h> + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + +class QAbstractVideoBufferPrivate +{ +public: + QAbstractVideoBufferPrivate() + : handleType(QAbstractVideoBuffer::NoHandle) + {} + + virtual ~QAbstractVideoBufferPrivate() + {} + + QAbstractVideoBuffer::HandleType handleType; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + + +#endif diff --git a/src/multimedia/video/qabstractvideosurface.cpp b/src/multimedia/video/qabstractvideosurface.cpp new file mode 100644 index 000000000..4d65d7eaa --- /dev/null +++ b/src/multimedia/video/qabstractvideosurface.cpp @@ -0,0 +1,340 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +//TESTED_COMPONENT=src/multimedia + +#include "qabstractvideosurface.h" + +#include "qvideosurfaceformat.h" + +#include <QtCore/qvariant.h> + +QT_BEGIN_NAMESPACE + +Q_DECLARE_METATYPE(QVideoSurfaceFormat) +Q_DECLARE_METATYPE(QAbstractVideoSurface::Error) + +/*! + \class QAbstractVideoSurface + \brief The QAbstractVideoSurface class is a base class for video presentation surfaces. + \since 1.0 + \inmodule QtMultimedia + + A video surface presents a continuous stream of identically formatted frames, where the format + of each frame is compatible with a stream format supplied when starting a presentation. + + The QAbstractVideoSurface class defines the standard interface that video producers use to + inter-operate with video presentation surfaces. It is not supposed to be instantiated directly. + Instead, you should subclass it to create new video surfaces. + + A list of pixel formats a surface can present is given by the supportedPixelFormats() function, + and the isFormatSupported() function will test if a video surface format is supported. If a + format is not supported the nearestFormat() function may be able to suggest a similar format. + For example, if a surface supports fixed set of resolutions it may suggest the smallest + supported resolution that contains the proposed resolution. + + The start() function takes a supported format and enables a video surface. Once started a + surface will begin displaying the frames it receives in the present() function. Surfaces may + hold a reference to the buffer of a presented video frame until a new frame is presented or + streaming is stopped. The stop() function will disable a surface and a release any video + buffers it holds references to. +*/ + +/*! + \enum QAbstractVideoSurface::Error + This enum describes the errors that may be returned by the error() function. + + \value NoError No error occurred. + \value UnsupportedFormatError A video format was not supported. + \value IncorrectFormatError A video frame was not compatible with the format of the surface. + \value StoppedError The surface has not been started. + \value ResourceError The surface could not allocate some resource. +*/ + +/*! + Constructs a video surface with the given \a parent. +*/ +QAbstractVideoSurface::QAbstractVideoSurface(QObject *parent) + : QObject(parent) +{ + setProperty("_q_surfaceFormat", QVariant::fromValue(QVideoSurfaceFormat())); + setProperty("_q_active", false); + setProperty("_q_error", QVariant::fromValue(QAbstractVideoSurface::NoError)); + setProperty("_q_nativeResolution", QSize()); +} + +// XXX Qt5 +/*! + \internal + + This is deprecated. + + Since we need to build without access to Qt's private headers we can't reliably inherit + from QObjectPrivate. Binary compatibility means we can't remove this constructor or + add a d pointer to QAbstractVideoSurface. +*/ +QAbstractVideoSurface::QAbstractVideoSurface(QAbstractVideoSurfacePrivate &, QObject *parent) + : QObject(parent) +{ +} + +/*! + Destroys a video surface. +*/ +QAbstractVideoSurface::~QAbstractVideoSurface() +{ +} + +/*! + \fn QAbstractVideoSurface::supportedPixelFormats(QAbstractVideoBuffer::HandleType type) const + + Returns a list of pixel formats a video surface can present for a given handle \a type. + + The pixel formats returned for the QAbstractVideoBuffer::NoHandle type are valid for any buffer + that can be mapped in read-only mode. + + Types that are first in the list can be assumed to be faster to render. + \since 1.0 +*/ + +/*! + Tests a video surface \a format to determine if a surface can accept it. + + Returns true if the format is supported by the surface, and false otherwise. + \since 1.0 +*/ +bool QAbstractVideoSurface::isFormatSupported(const QVideoSurfaceFormat &format) const +{ + return supportedPixelFormats(format.handleType()).contains(format.pixelFormat()); +} + +/*! + Returns a supported video surface format that is similar to \a format. + + A similar surface format is one that has the same \l {QVideoSurfaceFormat::pixelFormat()}{pixel + format} and \l {QVideoSurfaceFormat::handleType()}{handle type} but may differ in some of the other + properties. For example, if there are restrictions on the \l {QVideoSurfaceFormat::frameSize()} + {frame sizes} a video surface can accept it may suggest a format with a larger frame size and + a \l {QVideoSurfaceFormat::viewport()}{viewport} the size of the original frame size. + + If the format is already supported it will be returned unchanged, or if there is no similar + supported format an invalid format will be returned. + \since 1.0 +*/ +QVideoSurfaceFormat QAbstractVideoSurface::nearestFormat(const QVideoSurfaceFormat &format) const +{ + return isFormatSupported(format) + ? format + : QVideoSurfaceFormat(); +} + +/*! + \fn QAbstractVideoSurface::supportedFormatsChanged() + + Signals that the set of formats supported by a video surface has changed. + + \since 1.0 + \sa supportedPixelFormats(), isFormatSupported() +*/ + +/*! + Returns the format of a video surface. + \since 1.0 +*/ +QVideoSurfaceFormat QAbstractVideoSurface::surfaceFormat() const +{ + return property("_q_format").value<QVideoSurfaceFormat>(); +} + +/*! + \fn QAbstractVideoSurface::surfaceFormatChanged(const QVideoSurfaceFormat &format) + + Signals that the configured \a format of a video surface has changed. + + \since 1.0 + \sa surfaceFormat(), start() +*/ + +/*! + Starts a video surface presenting \a format frames. + + Returns true if the surface was started, and false if an error occurred. + + \since 1.0 + \sa isActive(), stop() +*/ +bool QAbstractVideoSurface::start(const QVideoSurfaceFormat &format) +{ + bool wasActive = property("_q_active").toBool(); + + setProperty("_q_active", true); + setProperty("_q_format", QVariant::fromValue(format)); + setProperty("_q_error", QVariant::fromValue(NoError)); + + emit surfaceFormatChanged(format); + + if (!wasActive) + emit activeChanged(true); + + return true; +} + +/*! + Stops a video surface presenting frames and releases any resources acquired in start(). + + \since 1.0 + \sa isActive(), start() +*/ +void QAbstractVideoSurface::stop() +{ + if (property("_q_active").toBool()) { + setProperty("_q_format", QVariant::fromValue(QVideoSurfaceFormat())); + setProperty("_q_active", false); + + emit activeChanged(false); + emit surfaceFormatChanged(surfaceFormat()); + } +} + +/*! + Indicates whether a video surface has been started. + + Returns true if the surface has been started, and false otherwise. + \since 1.0 +*/ +bool QAbstractVideoSurface::isActive() const +{ + return property("_q_active").toBool(); +} + +/*! + \fn QAbstractVideoSurface::activeChanged(bool active) + + Signals that the \a active state of a video surface has changed. + + \since 1.0 + \sa isActive(), start(), stop() +*/ + +/*! + \fn QAbstractVideoSurface::present(const QVideoFrame &frame) + + Presents a video \a frame. + + Returns true if the frame was presented, and false if an error occurred. + + Not all surfaces will block until the presentation of a frame has completed. Calling present() + on a non-blocking surface may fail if called before the presentation of a previous frame has + completed. In such cases the surface may not return to a ready state until it has had an + opportunity to process events. + + If present() fails for any other reason the surface will immediately enter the stopped state + and an error() value will be set. + + A video surface must be in the started state for present() to succeed, and the format of the + video frame must be compatible with the current video surface format. + + \since 1.0 + \sa error() +*/ + +/*! + Returns the last error that occurred. + + If a surface fails to start(), or stops unexpectedly this function can be called to discover + what error occurred. + \since 1.0 +*/ + +QAbstractVideoSurface::Error QAbstractVideoSurface::error() const +{ + return property("_q_error").value<QAbstractVideoSurface::Error>(); +} + +/*! + Sets the value of error() to \a error. + \since 1.0 +*/ +void QAbstractVideoSurface::setError(Error error) +{ + setProperty("_q_error", QVariant::fromValue(error)); +} + +/*! + \property QAbstractVideoSurface::nativeResolution + + The native resolution of video surface. + This is the resolution of video frames the surface + can render with optimal quality and/or performance. + + The native resolution is not always known and can be changed during playback. + \since 1.1 + */ +QSize QAbstractVideoSurface::nativeResolution() const +{ + return property("_q_nativeResolution").toSize(); +} + +/*! + Set the video surface native \a resolution. + \since 1.1 + */ +void QAbstractVideoSurface::setNativeResolution(const QSize &resolution) +{ + const QSize nativeResolution = property("_q_nativeResolution").toSize(); + + if (nativeResolution != resolution) { + setProperty("_q_nativeResolution", resolution); + + emit nativeResolutionChanged(resolution); + } +} +/*! + \fn QAbstractVideoSurface::nativeResolutionChanged(const QSize &resolution); + + Signals the native \a resolution of video surface has changed. + \since 1.1 +*/ + +QT_END_NAMESPACE + +#include "moc_qabstractvideosurface.cpp" + diff --git a/src/multimedia/video/qabstractvideosurface.h b/src/multimedia/video/qabstractvideosurface.h new file mode 100644 index 000000000..37c4d385f --- /dev/null +++ b/src/multimedia/video/qabstractvideosurface.h @@ -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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QABSTRACTVIDEOSURFACE_H +#define QABSTRACTVIDEOSURFACE_H + +#include <QtCore/qobject.h> +#include <qvideoframe.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + +class QRectF; +class QVideoSurfaceFormat; + +class QAbstractVideoSurfacePrivate; + +class Q_MULTIMEDIA_EXPORT QAbstractVideoSurface : public QObject +{ + Q_OBJECT + Q_PROPERTY(QSize nativeResolution READ nativeResolution NOTIFY nativeResolutionChanged) +public: + enum Error + { + NoError, + UnsupportedFormatError, + IncorrectFormatError, + StoppedError, + ResourceError + }; + + explicit QAbstractVideoSurface(QObject *parent = 0); + ~QAbstractVideoSurface(); + + virtual QList<QVideoFrame::PixelFormat> supportedPixelFormats( + QAbstractVideoBuffer::HandleType handleType = QAbstractVideoBuffer::NoHandle) const = 0; + virtual bool isFormatSupported(const QVideoSurfaceFormat &format) const; + virtual QVideoSurfaceFormat nearestFormat(const QVideoSurfaceFormat &format) const; + + QVideoSurfaceFormat surfaceFormat() const; + + QSize nativeResolution() const; + + virtual bool start(const QVideoSurfaceFormat &format); + virtual void stop(); + + bool isActive() const; + + virtual bool present(const QVideoFrame &frame) = 0; + + Error error() const; + +Q_SIGNALS: + void activeChanged(bool active); + void surfaceFormatChanged(const QVideoSurfaceFormat &format); + void supportedFormatsChanged(); + void nativeResolutionChanged(const QSize &); + +protected: + QAbstractVideoSurface(QAbstractVideoSurfacePrivate &dd, QObject *parent); + + void setError(Error error); + void setNativeResolution(const QSize &resolution); + +private: + Q_DECLARE_PRIVATE(QAbstractVideoSurface) +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/multimedia/video/qimagevideobuffer.cpp b/src/multimedia/video/qimagevideobuffer.cpp new file mode 100644 index 000000000..e16abc30b --- /dev/null +++ b/src/multimedia/video/qimagevideobuffer.cpp @@ -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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qimagevideobuffer_p.h" + +#include "qabstractvideobuffer_p.h" + +#include <qimage.h> +#include <qvariant.h> + +QT_BEGIN_NAMESPACE + +class QImageVideoBufferPrivate : public QAbstractVideoBufferPrivate +{ +public: + QImageVideoBufferPrivate() + : mapMode(QAbstractVideoBuffer::NotMapped) + { + } + + QAbstractVideoBuffer::MapMode mapMode; + QImage image; +}; + +QImageVideoBuffer::QImageVideoBuffer(const QImage &image) + : QAbstractVideoBuffer(*new QImageVideoBufferPrivate, NoHandle) +{ + Q_D(QImageVideoBuffer); + + d->image = image; +} + +QImageVideoBuffer::~QImageVideoBuffer() +{ +} + +QAbstractVideoBuffer::MapMode QImageVideoBuffer::mapMode() const +{ + return d_func()->mapMode; +} + +uchar *QImageVideoBuffer::map(MapMode mode, int *numBytes, int *bytesPerLine) +{ + Q_D(QImageVideoBuffer); + + if (d->mapMode == NotMapped && d->image.bits() && mode != NotMapped) { + d->mapMode = mode; + + if (numBytes) + *numBytes = d->image.byteCount(); + + if (bytesPerLine) + *bytesPerLine = d->image.bytesPerLine(); + + return d->image.bits(); + } else { + return 0; + } +} + +void QImageVideoBuffer::unmap() +{ + Q_D(QImageVideoBuffer); + + d->mapMode = NotMapped; +} + +QT_END_NAMESPACE diff --git a/src/multimedia/video/qimagevideobuffer_p.h b/src/multimedia/video/qimagevideobuffer_p.h new file mode 100644 index 000000000..dae952ed4 --- /dev/null +++ b/src/multimedia/video/qimagevideobuffer_p.h @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QIMAGEVIDEOBUFFER_P_H +#define QIMAGEVIDEOBUFFER_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <qabstractvideobuffer.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + +class QImage; + +class QImageVideoBufferPrivate; + +class Q_MULTIMEDIA_EXPORT QImageVideoBuffer : public QAbstractVideoBuffer +{ + Q_DECLARE_PRIVATE(QImageVideoBuffer) +public: + QImageVideoBuffer(const QImage &image); + ~QImageVideoBuffer(); + + MapMode mapMode() const; + + uchar *map(MapMode mode, int *numBytes, int *bytesPerLine); + void unmap(); +}; + +QT_END_NAMESPACE + +QT_END_HEADER + + +#endif diff --git a/src/multimedia/video/qmemoryvideobuffer.cpp b/src/multimedia/video/qmemoryvideobuffer.cpp new file mode 100644 index 000000000..d3516182a --- /dev/null +++ b/src/multimedia/video/qmemoryvideobuffer.cpp @@ -0,0 +1,132 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmemoryvideobuffer_p.h" + +#include "qabstractvideobuffer_p.h" +#include <qbytearray.h> + +QT_BEGIN_NAMESPACE + +class QMemoryVideoBufferPrivate : public QAbstractVideoBufferPrivate +{ +public: + QMemoryVideoBufferPrivate() + : bytesPerLine(0) + , mapMode(QAbstractVideoBuffer::NotMapped) + { + } + + int bytesPerLine; + QAbstractVideoBuffer::MapMode mapMode; + QByteArray data; +}; + +/*! + \class QMemoryVideoBuffer + \brief The QMemoryVideoBuffer class provides a system memory allocated video data buffer. + \internal + + QMemoryVideoBuffer is the default video buffer for allocating system memory. It may be used to + allocate memory for a QVideoFrame without implementing your own QAbstractVideoBuffer. +*/ + +/*! + Constructs a video buffer with an image stride of \a bytesPerLine from a byte \a array. +*/ +QMemoryVideoBuffer::QMemoryVideoBuffer(const QByteArray &array, int bytesPerLine) + : QAbstractVideoBuffer(*new QMemoryVideoBufferPrivate, NoHandle) +{ + Q_D(QMemoryVideoBuffer); + + d->data = array; + d->bytesPerLine = bytesPerLine; +} + +/*! + Destroys a system memory allocated video buffer. +*/ +QMemoryVideoBuffer::~QMemoryVideoBuffer() +{ +} + +/*! + \reimp + \since 1.1 +*/ +QAbstractVideoBuffer::MapMode QMemoryVideoBuffer::mapMode() const +{ + return d_func()->mapMode; +} + +/*! + \reimp + \since 1.1 +*/ +uchar *QMemoryVideoBuffer::map(MapMode mode, int *numBytes, int *bytesPerLine) +{ + Q_D(QMemoryVideoBuffer); + + if (d->mapMode == NotMapped && d->data.data() && mode != NotMapped) { + d->mapMode = mode; + + if (numBytes) + *numBytes = d->data.size(); + + if (bytesPerLine) + *bytesPerLine = d->bytesPerLine; + + return reinterpret_cast<uchar *>(d->data.data()); + } else { + return 0; + } +} + +/*! + \reimp + \since 1.1 +*/ +void QMemoryVideoBuffer::unmap() +{ + d_func()->mapMode = NotMapped; +} + +QT_END_NAMESPACE diff --git a/src/multimedia/video/qmemoryvideobuffer_p.h b/src/multimedia/video/qmemoryvideobuffer_p.h new file mode 100644 index 000000000..d5bc4e3c8 --- /dev/null +++ b/src/multimedia/video/qmemoryvideobuffer_p.h @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMEMORYVIDEOBUFFER_P_H +#define QMEMORYVIDEOBUFFER_P_H + +#include <qabstractvideobuffer.h> + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +QT_BEGIN_HEADER + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + +class QMemoryVideoBufferPrivate; + +class Q_MULTIMEDIA_EXPORT QMemoryVideoBuffer : public QAbstractVideoBuffer +{ + Q_DECLARE_PRIVATE(QMemoryVideoBuffer) +public: + QMemoryVideoBuffer(const QByteArray &data, int bytesPerLine); + ~QMemoryVideoBuffer(); + + MapMode mapMode() const; + + uchar *map(MapMode mode, int *numBytes, int *bytesPerLine); + void unmap(); +}; + +QT_END_NAMESPACE + +QT_END_HEADER + + +QT_END_HEADER + +#endif diff --git a/src/multimedia/video/qvideoframe.cpp b/src/multimedia/video/qvideoframe.cpp new file mode 100644 index 000000000..eaef644e9 --- /dev/null +++ b/src/multimedia/video/qvideoframe.cpp @@ -0,0 +1,776 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qvideoframe.h" + +#include "qimagevideobuffer_p.h" +#include "qmemoryvideobuffer_p.h" + +#include <qimage.h> +#include <qpair.h> +#include <qsize.h> +#include <qvariant.h> +#include <qvector.h> + +QT_BEGIN_NAMESPACE + +namespace +{ +class QVideoFramePrivateRegisterMetaTypes +{ +public: + QVideoFramePrivateRegisterMetaTypes() + { + qRegisterMetaType<QVideoFrame::PixelFormat>("QVideoFrame::PixelFormat"); + } +} _registerMetaTypes; +} + + +class QVideoFramePrivate : public QSharedData +{ +public: + QVideoFramePrivate() + : startTime(-1) + , endTime(-1) + , data(0) + , mappedBytes(0) + , bytesPerLine(0) + , pixelFormat(QVideoFrame::Format_Invalid) + , fieldType(QVideoFrame::ProgressiveFrame) + , buffer(0) + { + } + + QVideoFramePrivate(const QSize &size, QVideoFrame::PixelFormat format) + : size(size) + , startTime(-1) + , endTime(-1) + , data(0) + , mappedBytes(0) + , bytesPerLine(0) + , pixelFormat(format) + , fieldType(QVideoFrame::ProgressiveFrame) + , buffer(0) + { + } + + ~QVideoFramePrivate() + { + delete buffer; + } + + QSize size; + qint64 startTime; + qint64 endTime; + uchar *data; + int mappedBytes; + int bytesPerLine; + QVideoFrame::PixelFormat pixelFormat; + QVideoFrame::FieldType fieldType; + QAbstractVideoBuffer *buffer; + +private: + Q_DISABLE_COPY(QVideoFramePrivate) +}; + +/*! + \class QVideoFrame + \brief The QVideoFrame class provides a representation of a frame of video data. + \since 1.0 + \inmodule QtMultimedia + + A QVideoFrame encapsulates the data of a video frame, and information about the frame. + + The contents of a video frame can be mapped to memory using the map() function. While + mapped, the video data can accessed using the bits() function, which returns a pointer to a + buffer. The total size of this buffer is given by the mappedBytes() function, and the size of each line is given + by bytesPerLine(). The return value of the handle() function may be used to access frame data + using the internal buffer's native APIs. + + The video data in a QVideoFrame is encapsulated in a QAbstractVideoBuffer. A QVideoFrame + may be constructed from any buffer type by subclassing the QAbstractVideoBuffer class. + + \note QVideoFrame is explicitly shared, any change made to video frame will also apply to any + copies. +*/ + +/*! + \enum QVideoFrame::PixelFormat + + Enumerates video data types. + + \value Format_Invalid + The frame is invalid. + + \value Format_ARGB32 + The frame is stored using a 32-bit ARGB format (0xAARRGGBB). This is equivalent to + QImage::Format_ARGB32. + + \value Format_ARGB32_Premultiplied + The frame stored using a premultiplied 32-bit ARGB format (0xAARRGGBB). This is equivalent + to QImage::Format_ARGB32_Premultiplied. + + \value Format_RGB32 + The frame stored using a 32-bit RGB format (0xffRRGGBB). This is equivalent to + QImage::Format_RGB32 + + \value Format_RGB24 + The frame is stored using a 24-bit RGB format (8-8-8). This is equivalent to + QImage::Format_RGB888 + + \value Format_RGB565 + The frame is stored using a 16-bit RGB format (5-6-5). This is equivalent to + QImage::Format_RGB16. + + \value Format_RGB555 + The frame is stored using a 16-bit RGB format (5-5-5). This is equivalent to + QImage::Format_RGB555. + + \value Format_ARGB8565_Premultiplied + The frame is stored using a 24-bit premultiplied ARGB format (8-6-6-5). + + \value Format_BGRA32 + The frame is stored using a 32-bit ARGB format (0xBBGGRRAA). + + \value Format_BGRA32_Premultiplied + The frame is stored using a premultiplied 32bit BGRA format. + + \value Format_BGR32 + The frame is stored using a 32-bit BGR format (0xBBGGRRff). + + \value Format_BGR24 + The frame is stored using a 24-bit BGR format (0xBBGGRR). + + \value Format_BGR565 + The frame is stored using a 16-bit BGR format (5-6-5). + + \value Format_BGR555 + The frame is stored using a 16-bit BGR format (5-5-5). + + \value Format_BGRA5658_Premultiplied + The frame is stored using a 24-bit premultiplied BGRA format (5-6-5-8). + + \value Format_AYUV444 + The frame is stored using a packed 32-bit AYUV format (0xAAYYUUVV). + + \value Format_AYUV444_Premultiplied + The frame is stored using a packed premultiplied 32-bit AYUV format (0xAAYYUUVV). + + \value Format_YUV444 + The frame is stored using a 24-bit packed YUV format (8-8-8). + + \value Format_YUV420P + The frame is stored using an 8-bit per component planar YUV format with the U and V planes + horizontally and vertically sub-sampled, i.e. the height and width of the U and V planes are + half that of the Y plane. + + \value Format_YV12 + The frame is stored using an 8-bit per component planar YVU format with the V and U planes + horizontally and vertically sub-sampled, i.e. the height and width of the V and U planes are + half that of the Y plane. + + \value Format_UYVY + The frame is stored using an 8-bit per component packed YUV format with the U and V planes + horizontally sub-sampled (U-Y-V-Y), i.e. two horizontally adjacent pixels are stored as a 32-bit + macropixel which has a Y value for each pixel and common U and V values. + + \value Format_YUYV + The frame is stored using an 8-bit per component packed YUV format with the U and V planes + horizontally sub-sampled (Y-U-Y-V), i.e. two horizontally adjacent pixels are stored as a 32-bit + macropixel which has a Y value for each pixel and common U and V values. + + \value Format_NV12 + The frame is stored using an 8-bit per component semi-planar YUV format with a Y plane (Y) + followed by a horizontally and vertically sub-sampled, packed UV plane (U-V). + + \value Format_NV21 + The frame is stored using an 8-bit per component semi-planar YUV format with a Y plane (Y) + followed by a horizontally and vertically sub-sampled, packed VU plane (V-U). + + \value Format_IMC1 + The frame is stored using an 8-bit per component planar YUV format with the U and V planes + horizontally and vertically sub-sampled. This is similar to the Format_YUV420P type, except + that the bytes per line of the U and V planes are padded out to the same stride as the Y plane. + + \value Format_IMC2 + The frame is stored using an 8-bit per component planar YUV format with the U and V planes + horizontally and vertically sub-sampled. This is similar to the Format_YUV420P type, except + that the lines of the U and V planes are interleaved, i.e. each line of U data is followed by a + line of V data creating a single line of the same stride as the Y data. + + \value Format_IMC3 + The frame is stored using an 8-bit per component planar YVU format with the V and U planes + horizontally and vertically sub-sampled. This is similar to the Format_YV12 type, except that + the bytes per line of the V and U planes are padded out to the same stride as the Y plane. + + \value Format_IMC4 + The frame is stored using an 8-bit per component planar YVU format with the V and U planes + horizontally and vertically sub-sampled. This is similar to the Format_YV12 type, except that + the lines of the V and U planes are interleaved, i.e. each line of V data is followed by a line + of U data creating a single line of the same stride as the Y data. + + \value Format_Y8 + The frame is stored using an 8-bit greyscale format. + + \value Format_Y16 + The frame is stored using a 16-bit linear greyscale format. Little endian. + + \value Format_Jpeg + The frame is stored in compressed Jpeg format. + + \value Format_CameraRaw + The frame is stored using a device specific camera raw format. + + \value Format_AdobeDng + The frame is stored using raw Adobe Digital Negative (DNG) format. + + \value Format_User + Start value for user defined pixel formats. +*/ + +/*! + \enum QVideoFrame::FieldType + + Specifies the field an interlaced video frame belongs to. + + \value ProgressiveFrame The frame is not interlaced. + \value TopField The frame contains a top field. + \value BottomField The frame contains a bottom field. + \value InterlacedFrame The frame contains a merged top and bottom field. +*/ + +/*! + Constructs a null video frame. +*/ +QVideoFrame::QVideoFrame() + : d(new QVideoFramePrivate) +{ +} + +/*! + Constructs a video frame from a \a buffer with the given pixel \a format and \a size in pixels. + + \note This doesn't increment the reference count of the video buffer. + \since 1.0 +*/ +QVideoFrame::QVideoFrame( + QAbstractVideoBuffer *buffer, const QSize &size, PixelFormat format) + : d(new QVideoFramePrivate(size, format)) +{ + d->buffer = buffer; +} + +/*! + Constructs a video frame of the given pixel \a format and \a size in pixels. + + The \a bytesPerLine (stride) is the length of each scan line in bytes, and \a bytes is the total + number of bytes that must be allocated for the frame. + \since 1.0 +*/ +QVideoFrame::QVideoFrame(int bytes, const QSize &size, int bytesPerLine, PixelFormat format) + : d(new QVideoFramePrivate(size, format)) +{ + if (bytes > 0) { + QByteArray data; + data.resize(bytes); + + // Check the memory was successfully allocated. + if (!data.isEmpty()) + d->buffer = new QMemoryVideoBuffer(data, bytesPerLine); + } +} + +/*! + Constructs a video frame from an \a image. + + \note This will construct an invalid video frame if there is no frame type equivalent to the + image format. + + \since 1.0 + \sa pixelFormatFromImageFormat() +*/ +QVideoFrame::QVideoFrame(const QImage &image) + : d(new QVideoFramePrivate( + image.size(), pixelFormatFromImageFormat(image.format()))) +{ + if (d->pixelFormat != Format_Invalid) + d->buffer = new QImageVideoBuffer(image); +} + +/*! + Constructs a copy of \a other. + + \since 1.0 +*/ +QVideoFrame::QVideoFrame(const QVideoFrame &other) + : d(other.d) +{ +} + +/*! + Assigns the contents of \a other to a video frame. + \since 1.0 +*/ +QVideoFrame &QVideoFrame::operator =(const QVideoFrame &other) +{ + d = other.d; + + return *this; +} + +/*! + Destroys a video frame. +*/ +QVideoFrame::~QVideoFrame() +{ +} + +/*! + Identifies whether a video frame is valid. + + An invalid frame has no video buffer associated with it. + + Returns true if the frame is valid, and false if it is not. + \since 1.0 +*/ +bool QVideoFrame::isValid() const +{ + return d->buffer != 0; +} + +/*! + Returns the color format of a video frame. + \since 1.0 +*/ +QVideoFrame::PixelFormat QVideoFrame::pixelFormat() const +{ + return d->pixelFormat; +} + +/*! + Returns the type of a video frame's handle. + + \since 1.0 +*/ +QAbstractVideoBuffer::HandleType QVideoFrame::handleType() const +{ + return d->buffer ? d->buffer->handleType() : QAbstractVideoBuffer::NoHandle; +} + +/*! + Returns the dimensions of a video frame. + \since 1.0 +*/ +QSize QVideoFrame::size() const +{ + return d->size; +} + +/*! + Returns the width of a video frame. + \since 1.0 +*/ +int QVideoFrame::width() const +{ + return d->size.width(); +} + +/*! + Returns the height of a video frame. + \since 1.0 +*/ +int QVideoFrame::height() const +{ + return d->size.height(); +} + +/*! + Returns the field an interlaced video frame belongs to. + + If the video is not interlaced this will return WholeFrame. + \since 1.0 +*/ +QVideoFrame::FieldType QVideoFrame::fieldType() const +{ + return d->fieldType; +} + +/*! + Sets the \a field an interlaced video frame belongs to. + \since 1.0 +*/ +void QVideoFrame::setFieldType(QVideoFrame::FieldType field) +{ + d->fieldType = field; +} + +/*! + Identifies if a video frame's contents are currently mapped to system memory. + + This is a convenience function which checks that the \l {QAbstractVideoBuffer::MapMode}{MapMode} + of the frame is not equal to QAbstractVideoBuffer::NotMapped. + + Returns true if the contents of the video frame are mapped to system memory, and false + otherwise. + + \since 1.0 + \sa mapMode(), QAbstractVideoBuffer::MapMode +*/ + +bool QVideoFrame::isMapped() const +{ + return d->buffer != 0 && d->buffer->mapMode() != QAbstractVideoBuffer::NotMapped; +} + +/*! + Identifies if the mapped contents of a video frame will be persisted when the frame is unmapped. + + This is a convenience function which checks if the \l {QAbstractVideoBuffer::MapMode}{MapMode} + contains the QAbstractVideoBuffer::WriteOnly flag. + + Returns true if the video frame will be updated when unmapped, and false otherwise. + + \note The result of altering the data of a frame that is mapped in read-only mode is undefined. + Depending on the buffer implementation the changes may be persisted, or worse alter a shared + buffer. + + \since 1.0 + \sa mapMode(), QAbstractVideoBuffer::MapMode +*/ +bool QVideoFrame::isWritable() const +{ + return d->buffer != 0 && (d->buffer->mapMode() & QAbstractVideoBuffer::WriteOnly); +} + +/*! + Identifies if the mapped contents of a video frame were read from the frame when it was mapped. + + This is a convenience function which checks if the \l {QAbstractVideoBuffer::MapMode}{MapMode} + contains the QAbstractVideoBuffer::WriteOnly flag. + + Returns true if the contents of the mapped memory were read from the video frame, and false + otherwise. + + \since 1.0 + \sa mapMode(), QAbstractVideoBuffer::MapMode +*/ +bool QVideoFrame::isReadable() const +{ + return d->buffer != 0 && (d->buffer->mapMode() & QAbstractVideoBuffer::ReadOnly); +} + +/*! + Returns the mode a video frame was mapped to system memory in. + + \since 1.0 + \sa map(), QAbstractVideoBuffer::MapMode +*/ +QAbstractVideoBuffer::MapMode QVideoFrame::mapMode() const +{ + return d->buffer != 0 ? d->buffer->mapMode() : QAbstractVideoBuffer::NotMapped; +} + +/*! + Maps the contents of a video frame to memory. + + The map \a mode indicates whether the contents of the mapped memory should be read from and/or + written to the frame. If the map mode includes the QAbstractVideoBuffer::ReadOnly flag the + mapped memory will be populated with the content of the video frame when mapped. If the map + mode inclues the QAbstractVideoBuffer::WriteOnly flag the content of the mapped memory will be + persisted in the frame when unmapped. + + While mapped the contents of a video frame can be accessed directly through the pointer returned + by the bits() function. + + When access to the data is no longer needed be sure to call the unmap() function to release the + mapped memory and possibly update the video frame contents. + + Returns true if the buffer was mapped to memory in the given \a mode and false otherwise. + + \since 1.0 + \sa unmap(), mapMode(), bits() +*/ +bool QVideoFrame::map(QAbstractVideoBuffer::MapMode mode) +{ + if (d->buffer != 0 && d->data == 0) { + Q_ASSERT(d->bytesPerLine == 0); + Q_ASSERT(d->mappedBytes == 0); + + d->data = d->buffer->map(mode, &d->mappedBytes, &d->bytesPerLine); + + return d->data != 0; + } + + return false; +} + +/*! + Releases the memory mapped by the map() function. + + If the \l {QAbstractVideoBuffer::MapMode}{MapMode} included the QAbstractVideoBuffer::WriteOnly + flag this will persist the current content of the mapped memory to the video frame. + + \since 1.0 + \sa map() +*/ +void QVideoFrame::unmap() +{ + if (d->data != 0) { + d->mappedBytes = 0; + d->bytesPerLine = 0; + d->data = 0; + + d->buffer->unmap(); + } +} + +/*! + Returns the number of bytes in a scan line. + + \note This is the bytes per line of the first plane only. The bytes per line of subsequent + planes should be calculated as per the frame type. + + This value is only valid while the frame data is \l {map()}{mapped}. + + \since 1.0 + \sa bits(), map(), mappedBytes() +*/ +int QVideoFrame::bytesPerLine() const +{ + return d->bytesPerLine; +} + +/*! + Returns a pointer to the start of the frame data buffer. + + This value is only valid while the frame data is \l {map()}{mapped}. + + Changes made to data accessed via this pointer (when mapped with write access) + are only guaranteed to have been persisted when unmap() is called. + + \since 1.0 + \sa map(), mappedBytes(), bytesPerLine() +*/ +uchar *QVideoFrame::bits() +{ + return d->data; +} + +/*! + Returns a pointer to the start of the frame data buffer. + + This value is only valid while the frame data is \l {map()}{mapped}. + + If the buffer was not mapped with read access, the contents of this + buffer will initially be uninitialized. + + \since 1.0 + \sa map(), mappedBytes(), bytesPerLine() +*/ +const uchar *QVideoFrame::bits() const +{ + return d->data; +} + +/*! + Returns the number of bytes occupied by the mapped frame data. + + This value is only valid while the frame data is \l {map()}{mapped}. + + \since 1.0 + \sa map() +*/ +int QVideoFrame::mappedBytes() const +{ + return d->mappedBytes; +} + +/*! + Returns a type specific handle to a video frame's buffer. + + For an OpenGL texture this would be the texture ID. + + \since 1.0 + \sa QAbstractVideoBuffer::handle() +*/ +QVariant QVideoFrame::handle() const +{ + return d->buffer != 0 ? d->buffer->handle() : QVariant(); +} + +/*! + Returns the presentation time when the frame should be displayed. + \since 1.0 +*/ +qint64 QVideoFrame::startTime() const +{ + return d->startTime; +} + +/*! + Sets the presentation \a time when the frame should be displayed. + \since 1.0 +*/ +void QVideoFrame::setStartTime(qint64 time) +{ + d->startTime = time; +} + +/*! + Returns the presentation time when a frame should stop being displayed. + + \since 1.0 +*/ +qint64 QVideoFrame::endTime() const +{ + return d->endTime; +} + +/*! + Sets the presentation \a time when a frame should stop being displayed. + \since 1.0 +*/ +void QVideoFrame::setEndTime(qint64 time) +{ + d->endTime = time; +} + +/*! + Returns a video pixel format equivalent to an image \a format. If there is no equivalent + format QVideoFrame::InvalidType is returned instead. + \since 1.0 +*/ +QVideoFrame::PixelFormat QVideoFrame::pixelFormatFromImageFormat(QImage::Format format) +{ + switch (format) { + case QImage::Format_Invalid: + case QImage::Format_Mono: + case QImage::Format_MonoLSB: + case QImage::Format_Indexed8: + return Format_Invalid; + case QImage::Format_RGB32: + return Format_RGB32; + case QImage::Format_ARGB32: + return Format_ARGB32; + case QImage::Format_ARGB32_Premultiplied: + return Format_ARGB32_Premultiplied; + case QImage::Format_RGB16: + return Format_RGB565; + case QImage::Format_ARGB8565_Premultiplied: + return Format_ARGB8565_Premultiplied; + case QImage::Format_RGB666: + case QImage::Format_ARGB6666_Premultiplied: + return Format_Invalid; + case QImage::Format_RGB555: + return Format_RGB555; + case QImage::Format_ARGB8555_Premultiplied: + return Format_Invalid; + case QImage::Format_RGB888: + return Format_RGB24; + case QImage::Format_RGB444: + case QImage::Format_ARGB4444_Premultiplied: + return Format_Invalid; + case QImage::NImageFormats: + return Format_Invalid; + } + return Format_Invalid; +} + +/*! + Returns an image format equivalent to a video frame pixel \a format. If there is no equivalent + format QImage::Format_Invalid is returned instead. + \since 1.0 +*/ +QImage::Format QVideoFrame::imageFormatFromPixelFormat(PixelFormat format) +{ + switch (format) { + case Format_Invalid: + return QImage::Format_Invalid; + case Format_ARGB32: + return QImage::Format_ARGB32; + case Format_ARGB32_Premultiplied: + return QImage::Format_ARGB32_Premultiplied; + case Format_RGB32: + return QImage::Format_RGB32; + case Format_RGB24: + return QImage::Format_RGB888; + case Format_RGB565: + return QImage::Format_RGB16; + case Format_RGB555: + return QImage::Format_RGB555; + case Format_ARGB8565_Premultiplied: + return QImage::Format_ARGB8565_Premultiplied; + case Format_BGRA32: + case Format_BGRA32_Premultiplied: + case Format_BGR32: + case Format_BGR24: + return QImage::Format_Invalid; + case Format_BGR565: + case Format_BGR555: + case Format_BGRA5658_Premultiplied: + case Format_AYUV444: + case Format_AYUV444_Premultiplied: + case Format_YUV444: + case Format_YUV420P: + case Format_YV12: + case Format_UYVY: + case Format_YUYV: + case Format_NV12: + case Format_NV21: + case Format_IMC1: + case Format_IMC2: + case Format_IMC3: + case Format_IMC4: + case Format_Y8: + case Format_Y16: + case Format_Jpeg: + case Format_CameraRaw: + case Format_AdobeDng: + return QImage::Format_Invalid; + case Format_User: + return QImage::Format_Invalid; + } + return QImage::Format_Invalid; +} + +QT_END_NAMESPACE + diff --git a/src/multimedia/video/qvideoframe.h b/src/multimedia/video/qvideoframe.h new file mode 100644 index 000000000..6dffaf59d --- /dev/null +++ b/src/multimedia/video/qvideoframe.h @@ -0,0 +1,174 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QVIDEOFRAME_H +#define QVIDEOFRAME_H + +#include <QtCore/qmetatype.h> +#include <QtCore/qshareddata.h> +#include <QtGui/qimage.h> +#include <qabstractvideobuffer.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + +class QSize; +class QVariant; + +class QVideoFramePrivate; + +class Q_MULTIMEDIA_EXPORT QVideoFrame +{ +public: + enum FieldType + { + ProgressiveFrame, + TopField, + BottomField, + InterlacedFrame + }; + + enum PixelFormat + { + Format_Invalid, + Format_ARGB32, + Format_ARGB32_Premultiplied, + Format_RGB32, + Format_RGB24, + Format_RGB565, + Format_RGB555, + Format_ARGB8565_Premultiplied, + Format_BGRA32, + Format_BGRA32_Premultiplied, + Format_BGR32, + Format_BGR24, + Format_BGR565, + Format_BGR555, + Format_BGRA5658_Premultiplied, + + Format_AYUV444, + Format_AYUV444_Premultiplied, + Format_YUV444, + Format_YUV420P, + Format_YV12, + Format_UYVY, + Format_YUYV, + Format_NV12, + Format_NV21, + Format_IMC1, + Format_IMC2, + Format_IMC3, + Format_IMC4, + Format_Y8, + Format_Y16, + + Format_Jpeg, + + Format_CameraRaw, + Format_AdobeDng, + + Format_User = 1000 + }; + + QVideoFrame(); + QVideoFrame(QAbstractVideoBuffer *buffer, const QSize &size, PixelFormat format); + QVideoFrame(int bytes, const QSize &size, int bytesPerLine, PixelFormat format); + QVideoFrame(const QImage &image); + QVideoFrame(const QVideoFrame &other); + ~QVideoFrame(); + + QVideoFrame &operator =(const QVideoFrame &other); + + bool isValid() const; + + PixelFormat pixelFormat() const; + + QAbstractVideoBuffer::HandleType handleType() const; + + QSize size() const; + int width() const; + int height() const; + + FieldType fieldType() const; + void setFieldType(FieldType); + + bool isMapped() const; + bool isReadable() const; + bool isWritable() const; + + QAbstractVideoBuffer::MapMode mapMode() const; + + bool map(QAbstractVideoBuffer::MapMode mode); + void unmap(); + + int bytesPerLine() const; + + uchar *bits(); + const uchar *bits() const; + int mappedBytes() const; + + QVariant handle() const; + + qint64 startTime() const; + void setStartTime(qint64 time); + + qint64 endTime() const; + void setEndTime(qint64 time); + + static PixelFormat pixelFormatFromImageFormat(QImage::Format format); + static QImage::Format imageFormatFromPixelFormat(PixelFormat format); + +private: + QExplicitlySharedDataPointer<QVideoFramePrivate> d; +}; + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(QVideoFrame::FieldType) +Q_DECLARE_METATYPE(QVideoFrame::PixelFormat) + +QT_END_HEADER + +#endif + diff --git a/src/multimedia/video/qvideosurfaceformat.cpp b/src/multimedia/video/qvideosurfaceformat.cpp new file mode 100644 index 000000000..8286d18e1 --- /dev/null +++ b/src/multimedia/video/qvideosurfaceformat.cpp @@ -0,0 +1,707 @@ +/**************************************************************************** +** +** 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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qvideosurfaceformat.h" + +#include <qdebug.h> +#include <qmetatype.h> +#include <qpair.h> +#include <qvariant.h> +#include <qvector.h> + +QT_BEGIN_NAMESPACE + +class QVideoSurfaceFormatPrivate : public QSharedData +{ +public: + QVideoSurfaceFormatPrivate() + : pixelFormat(QVideoFrame::Format_Invalid) + , handleType(QAbstractVideoBuffer::NoHandle) + , scanLineDirection(QVideoSurfaceFormat::TopToBottom) + , pixelAspectRatio(1, 1) + , ycbcrColorSpace(QVideoSurfaceFormat::YCbCr_Undefined) + , frameRate(0.0) + { + } + + QVideoSurfaceFormatPrivate( + const QSize &size, + QVideoFrame::PixelFormat format, + QAbstractVideoBuffer::HandleType type) + : pixelFormat(format) + , handleType(type) + , scanLineDirection(QVideoSurfaceFormat::TopToBottom) + , frameSize(size) + , pixelAspectRatio(1, 1) + , ycbcrColorSpace(QVideoSurfaceFormat::YCbCr_Undefined) + , viewport(QPoint(0, 0), size) + , frameRate(0.0) + { + } + + QVideoSurfaceFormatPrivate(const QVideoSurfaceFormatPrivate &other) + : QSharedData(other) + , pixelFormat(other.pixelFormat) + , handleType(other.handleType) + , scanLineDirection(other.scanLineDirection) + , frameSize(other.frameSize) + , pixelAspectRatio(other.pixelAspectRatio) + , ycbcrColorSpace(other.ycbcrColorSpace) + , viewport(other.viewport) + , frameRate(other.frameRate) + , propertyNames(other.propertyNames) + , propertyValues(other.propertyValues) + { + } + + bool operator ==(const QVideoSurfaceFormatPrivate &other) const + { + if (pixelFormat == other.pixelFormat + && handleType == other.handleType + && scanLineDirection == other.scanLineDirection + && frameSize == other.frameSize + && pixelAspectRatio == other.pixelAspectRatio + && viewport == other.viewport + && frameRatesEqual(frameRate, other.frameRate) + && ycbcrColorSpace == other.ycbcrColorSpace + && propertyNames.count() == other.propertyNames.count()) { + for (int i = 0; i < propertyNames.count(); ++i) { + int j = other.propertyNames.indexOf(propertyNames.at(i)); + + if (j == -1 || propertyValues.at(i) != other.propertyValues.at(j)) + return false; + } + return true; + } else { + return false; + } + } + + inline static bool frameRatesEqual(qreal r1, qreal r2) + { + return qAbs(r1 - r2) <= 0.00001 * qMin(qAbs(r1), qAbs(r2)); + } + + QVideoFrame::PixelFormat pixelFormat; + QAbstractVideoBuffer::HandleType handleType; + QVideoSurfaceFormat::Direction scanLineDirection; + QSize frameSize; + QSize pixelAspectRatio; + QVideoSurfaceFormat::YCbCrColorSpace ycbcrColorSpace; + QRect viewport; + qreal frameRate; + QList<QByteArray> propertyNames; + QList<QVariant> propertyValues; +}; + +/*! + \class QVideoSurfaceFormat + \brief The QVideoSurfaceFormat class specifies the stream format of a video presentation + surface. + \since 1.0 + \inmodule QtMultimedia + + A video surface presents a stream of video frames. The surface's format describes the type of + the frames and determines how they should be presented. + + The core properties of a video stream required to setup a video surface are the pixel format + given by pixelFormat(), and the frame dimensions given by frameSize(). + + If the surface is to present frames using a frame's handle a surface format will also include + a handle type which is given by the handleType() function. + + The region of a frame that is actually displayed on a video surface is given by the viewport(). + A stream may have a viewport less than the entire region of a frame to allow for videos smaller + than the nearest optimal size of a video frame. For example the width of a frame may be + extended so that the start of each scan line is eight byte aligned. + + Other common properties are the pixelAspectRatio(), scanLineDirection(), and frameRate(). + Additionally a stream may have some additional type specific properties which are listed by the + dynamicPropertyNames() function and can be accessed using the property(), and setProperty() + functions. +*/ + +/*! + \enum QVideoSurfaceFormat::Direction + + Enumerates the layout direction of video scan lines. + + \value TopToBottom Scan lines are arranged from the top of the frame to the bottom. + \value BottomToTop Scan lines are arranged from the bottom of the frame to the top. +*/ + +/*! + \enum QVideoSurfaceFormat::YCbCrColorSpace + + Enumerates the Y'CbCr color space of video frames. + + \value YCbCr_Undefined + No color space is specified. + + \value YCbCr_BT601 + A Y'CbCr color space defined by ITU-R recommendation BT.601 + with Y value range from 16 to 235, and Cb/Cr range from 16 to 240. + Used in standard definition video. + + \value YCbCr_BT709 + A Y'CbCr color space defined by ITU-R BT.709 with the same values range as YCbCr_BT601. Used + for HDTV. + + \value YCbCr_xvYCC601 + The BT.601 color space with the value range extended to 0 to 255. + It is backward compatibile with BT.601 and uses values outside BT.601 range to represent a + wider range of colors. + + \value YCbCr_xvYCC709 + The BT.709 color space with the value range extended to 0 to 255. + + \value YCbCr_JPEG + The full range Y'CbCr color space used in JPEG files. +*/ + +/*! + Constructs a null video stream format. +*/ +QVideoSurfaceFormat::QVideoSurfaceFormat() + : d(new QVideoSurfaceFormatPrivate) +{ +} + +/*! + Contructs a description of stream which receives stream of \a type buffers with given frame + \a size and pixel \a format. + \since 1.0 +*/ +QVideoSurfaceFormat::QVideoSurfaceFormat( + const QSize& size, QVideoFrame::PixelFormat format, QAbstractVideoBuffer::HandleType type) + : d(new QVideoSurfaceFormatPrivate(size, format, type)) +{ +} + +/*! + Constructs a copy of \a other. + \since 1.0 +*/ +QVideoSurfaceFormat::QVideoSurfaceFormat(const QVideoSurfaceFormat &other) + : d(other.d) +{ +} + +/*! + Assigns the values of \a other to this object. + \since 1.0 +*/ +QVideoSurfaceFormat &QVideoSurfaceFormat::operator =(const QVideoSurfaceFormat &other) +{ + d = other.d; + + return *this; +} + +/*! + Destroys a video stream description. +*/ +QVideoSurfaceFormat::~QVideoSurfaceFormat() +{ +} + +/*! + Identifies if a video surface format has a valid pixel format and frame size. + + Returns true if the format is valid, and false otherwise. + \since 1.0 +*/ +bool QVideoSurfaceFormat::isValid() const +{ + return d->pixelFormat != QVideoFrame::Format_Invalid && d->frameSize.isValid(); +} + +/*! + Returns true if \a other is the same as this video format, and false if they are different. + \since 1.0 +*/ +bool QVideoSurfaceFormat::operator ==(const QVideoSurfaceFormat &other) const +{ + return d == other.d || *d == *other.d; +} + +/*! + Returns true if \a other is different to a video format, and false if they are the same. + \since 1.0 +*/ +bool QVideoSurfaceFormat::operator !=(const QVideoSurfaceFormat &other) const +{ + return d != other.d && !(*d == *other.d); +} + +/*! + Returns the pixel format of frames in a video stream. + \since 1.0 +*/ +QVideoFrame::PixelFormat QVideoSurfaceFormat::pixelFormat() const +{ + return d->pixelFormat; +} + +/*! + Returns the type of handle the surface uses to present the frame data. + + If the handle type is QAbstractVideoBuffer::NoHandle buffers with any handle type are valid + provided they can be \l {QAbstractVideoBuffer::map()}{mapped} with the + QAbstractVideoBuffer::ReadOnly flag. If the handleType() is not QAbstractVideoBuffer::NoHandle + then the handle type of the buffer must be the same as that of the surface format. + \since 1.0 +*/ +QAbstractVideoBuffer::HandleType QVideoSurfaceFormat::handleType() const +{ + return d->handleType; +} + +/*! + Returns the dimensions of frames in a video stream. + + \sa frameWidth(), frameHeight() + \since 1.0 +*/ +QSize QVideoSurfaceFormat::frameSize() const +{ + return d->frameSize; +} + +/*! + Returns the width of frames in a video stream. + + \sa frameSize(), frameHeight() + \since 1.0 +*/ +int QVideoSurfaceFormat::frameWidth() const +{ + return d->frameSize.width(); +} + +/*! + Returns the height of frame in a video stream. + \since 1.0 +*/ +int QVideoSurfaceFormat::frameHeight() const +{ + return d->frameSize.height(); +} + +/*! + Sets the size of frames in a video stream to \a size. + + This will reset the viewport() to fill the entire frame. + \since 1.0 +*/ +void QVideoSurfaceFormat::setFrameSize(const QSize &size) +{ + d->frameSize = size; + d->viewport = QRect(QPoint(0, 0), size); +} + +/*! + \overload + + Sets the \a width and \a height of frames in a video stream. + + This will reset the viewport() to fill the entire frame. + \since 1.0 +*/ +void QVideoSurfaceFormat::setFrameSize(int width, int height) +{ + d->frameSize = QSize(width, height); + d->viewport = QRect(0, 0, width, height); +} + +/*! + Returns the viewport of a video stream. + + The viewport is the region of a video frame that is actually displayed. + + By default the viewport covers an entire frame. + \since 1.0 +*/ +QRect QVideoSurfaceFormat::viewport() const +{ + return d->viewport; +} + +/*! + Sets the viewport of a video stream to \a viewport. + \since 1.0 +*/ +void QVideoSurfaceFormat::setViewport(const QRect &viewport) +{ + d->viewport = viewport; +} + +/*! + Returns the direction of scan lines. + \since 1.0 +*/ +QVideoSurfaceFormat::Direction QVideoSurfaceFormat::scanLineDirection() const +{ + return d->scanLineDirection; +} + +/*! + Sets the \a direction of scan lines. + \since 1.0 +*/ +void QVideoSurfaceFormat::setScanLineDirection(Direction direction) +{ + d->scanLineDirection = direction; +} + +/*! + Returns the frame rate of a video stream in frames per second. + \since 1.0 +*/ +qreal QVideoSurfaceFormat::frameRate() const +{ + return d->frameRate; +} + +/*! + Sets the frame \a rate of a video stream in frames per second. + \since 1.0 +*/ +void QVideoSurfaceFormat::setFrameRate(qreal rate) +{ + d->frameRate = rate; +} + +/*! + Returns a video stream's pixel aspect ratio. + \since 1.0 +*/ +QSize QVideoSurfaceFormat::pixelAspectRatio() const +{ + return d->pixelAspectRatio; +} + +/*! + Sets a video stream's pixel aspect \a ratio. + \since 1.0 +*/ +void QVideoSurfaceFormat::setPixelAspectRatio(const QSize &ratio) +{ + d->pixelAspectRatio = ratio; +} + +/*! + \overload + + Sets the \a horizontal and \a vertical elements of a video stream's pixel aspect ratio. + \since 1.0 +*/ +void QVideoSurfaceFormat::setPixelAspectRatio(int horizontal, int vertical) +{ + d->pixelAspectRatio = QSize(horizontal, vertical); +} + +/*! + Returns the Y'CbCr color space of a video stream. + \since 1.0 +*/ +QVideoSurfaceFormat::YCbCrColorSpace QVideoSurfaceFormat::yCbCrColorSpace() const +{ + return d->ycbcrColorSpace; +} + +/*! + Sets the Y'CbCr color \a space of a video stream. + It is only used with raw YUV frame types. + \since 1.0 +*/ +void QVideoSurfaceFormat::setYCbCrColorSpace(QVideoSurfaceFormat::YCbCrColorSpace space) +{ + d->ycbcrColorSpace = space; +} + +/*! + Returns a suggested size in pixels for the video stream. + + This is the size of the viewport scaled according to the pixel aspect ratio. + \since 1.0 +*/ +QSize QVideoSurfaceFormat::sizeHint() const +{ + QSize size = d->viewport.size(); + + if (d->pixelAspectRatio.height() != 0) + size.setWidth(size.width() * d->pixelAspectRatio.width() / d->pixelAspectRatio.height()); + + return size; +} + +/*! + Returns a list of video format dynamic property names. + \since 1.0 +*/ +QList<QByteArray> QVideoSurfaceFormat::propertyNames() const +{ + return (QList<QByteArray>() + << "handleType" + << "pixelFormat" + << "frameSize" + << "frameWidth" + << "viewport" + << "scanLineDirection" + << "frameRate" + << "pixelAspectRatio" + << "sizeHint" + << "yCbCrColorSpace") + + d->propertyNames; +} + +/*! + Returns the value of the video format's \a name property. + \since 1.0 +*/ +QVariant QVideoSurfaceFormat::property(const char *name) const +{ + if (qstrcmp(name, "handleType") == 0) { + return qVariantFromValue(d->handleType); + } else if (qstrcmp(name, "pixelFormat") == 0) { + return qVariantFromValue(d->pixelFormat); + } else if (qstrcmp(name, "handleType") == 0) { + return qVariantFromValue(d->handleType); + } else if (qstrcmp(name, "frameSize") == 0) { + return d->frameSize; + } else if (qstrcmp(name, "frameWidth") == 0) { + return d->frameSize.width(); + } else if (qstrcmp(name, "frameHeight") == 0) { + return d->frameSize.height(); + } else if (qstrcmp(name, "viewport") == 0) { + return d->viewport; + } else if (qstrcmp(name, "scanLineDirection") == 0) { + return qVariantFromValue(d->scanLineDirection); + } else if (qstrcmp(name, "frameRate") == 0) { + return qVariantFromValue(d->frameRate); + } else if (qstrcmp(name, "pixelAspectRatio") == 0) { + return qVariantFromValue(d->pixelAspectRatio); + } else if (qstrcmp(name, "sizeHint") == 0) { + return sizeHint(); + } else if (qstrcmp(name, "yCbCrColorSpace") == 0) { + return qVariantFromValue(d->ycbcrColorSpace); + } else { + int id = 0; + for (; id < d->propertyNames.count() && d->propertyNames.at(id) != name; ++id) {} + + return id < d->propertyValues.count() + ? d->propertyValues.at(id) + : QVariant(); + } +} + +/*! + Sets the video format's \a name property to \a value. + + Trying to set a read only property will be ignored. + + \since 1.0 +*/ +void QVideoSurfaceFormat::setProperty(const char *name, const QVariant &value) +{ + if (qstrcmp(name, "handleType") == 0) { + // read only. + } else if (qstrcmp(name, "pixelFormat") == 0) { + // read only. + } else if (qstrcmp(name, "frameSize") == 0) { + if (qVariantCanConvert<QSize>(value)) { + d->frameSize = qvariant_cast<QSize>(value); + d->viewport = QRect(QPoint(0, 0), d->frameSize); + } + } else if (qstrcmp(name, "frameWidth") == 0) { + // read only. + } else if (qstrcmp(name, "frameHeight") == 0) { + // read only. + } else if (qstrcmp(name, "viewport") == 0) { + if (qVariantCanConvert<QRect>(value)) + d->viewport = qvariant_cast<QRect>(value); + } else if (qstrcmp(name, "scanLineDirection") == 0) { + if (qVariantCanConvert<Direction>(value)) + d->scanLineDirection = qvariant_cast<Direction>(value); + } else if (qstrcmp(name, "frameRate") == 0) { + if (qVariantCanConvert<qreal>(value)) + d->frameRate = qvariant_cast<qreal>(value); + } else if (qstrcmp(name, "pixelAspectRatio") == 0) { + if (qVariantCanConvert<QSize>(value)) + d->pixelAspectRatio = qvariant_cast<QSize>(value); + } else if (qstrcmp(name, "sizeHint") == 0) { + // read only. + } else if (qstrcmp(name, "yCbCrColorSpace") == 0) { + if (qVariantCanConvert<YCbCrColorSpace>(value)) + d->ycbcrColorSpace = qvariant_cast<YCbCrColorSpace>(value); + } else { + int id = 0; + for (; id < d->propertyNames.count() && d->propertyNames.at(id) != name; ++id) {} + + if (id < d->propertyValues.count()) { + if (value.isNull()) { + d->propertyNames.removeAt(id); + d->propertyValues.removeAt(id); + } else { + d->propertyValues[id] = value; + } + } else if (!value.isNull()) { + d->propertyNames.append(QByteArray(name)); + d->propertyValues.append(value); + } + } +} + + +#ifndef QT_NO_DEBUG_STREAM +QDebug operator<<(QDebug dbg, const QVideoSurfaceFormat &f) +{ + QString typeName; + switch (f.pixelFormat()) { + case QVideoFrame::Format_Invalid: + typeName = QLatin1String("Format_Invalid"); + break; + case QVideoFrame::Format_ARGB32: + typeName = QLatin1String("Format_ARGB32"); + break; + case QVideoFrame::Format_ARGB32_Premultiplied: + typeName = QLatin1String("Format_ARGB32_Premultiplied"); + break; + case QVideoFrame::Format_RGB32: + typeName = QLatin1String("Format_RGB32"); + break; + case QVideoFrame::Format_RGB24: + typeName = QLatin1String("Format_RGB24"); + break; + case QVideoFrame::Format_RGB565: + typeName = QLatin1String("Format_RGB565"); + break; + case QVideoFrame::Format_RGB555: + typeName = QLatin1String("Format_RGB555"); + break; + case QVideoFrame::Format_ARGB8565_Premultiplied: + typeName = QLatin1String("Format_ARGB8565_Premultiplied"); + break; + case QVideoFrame::Format_BGRA32: + typeName = QLatin1String("Format_BGRA32"); + break; + case QVideoFrame::Format_BGRA32_Premultiplied: + typeName = QLatin1String("Format_BGRA32_Premultiplied"); + break; + case QVideoFrame::Format_BGR32: + typeName = QLatin1String("Format_BGR32"); + break; + case QVideoFrame::Format_BGR24: + typeName = QLatin1String("Format_BGR24"); + break; + case QVideoFrame::Format_BGR565: + typeName = QLatin1String("Format_BGR565"); + break; + case QVideoFrame::Format_BGR555: + typeName = QLatin1String("Format_BGR555"); + break; + case QVideoFrame::Format_BGRA5658_Premultiplied: + typeName = QLatin1String("Format_BGRA5658_Premultiplied"); + break; + case QVideoFrame::Format_AYUV444: + typeName = QLatin1String("Format_AYUV444"); + break; + case QVideoFrame::Format_AYUV444_Premultiplied: + typeName = QLatin1String("Format_AYUV444_Premultiplied"); + break; + case QVideoFrame::Format_YUV444: + typeName = QLatin1String("Format_YUV444"); + break; + case QVideoFrame::Format_YUV420P: + typeName = QLatin1String("Format_YUV420P"); + break; + case QVideoFrame::Format_YV12: + typeName = QLatin1String("Format_YV12"); + break; + case QVideoFrame::Format_UYVY: + typeName = QLatin1String("Format_UYVY"); + break; + case QVideoFrame::Format_YUYV: + typeName = QLatin1String("Format_YUYV"); + break; + case QVideoFrame::Format_NV12: + typeName = QLatin1String("Format_NV12"); + break; + case QVideoFrame::Format_NV21: + typeName = QLatin1String("Format_NV21"); + break; + case QVideoFrame::Format_IMC1: + typeName = QLatin1String("Format_IMC1"); + break; + case QVideoFrame::Format_IMC2: + typeName = QLatin1String("Format_IMC2"); + break; + case QVideoFrame::Format_IMC3: + typeName = QLatin1String("Format_IMC3"); + break; + case QVideoFrame::Format_IMC4: + typeName = QLatin1String("Format_IMC4"); + break; + case QVideoFrame::Format_Y8: + typeName = QLatin1String("Format_Y8"); + break; + case QVideoFrame::Format_Y16: + typeName = QLatin1String("Format_Y16"); + break; + default: + typeName = QString(QLatin1String("UserType(%1)" )).arg(int(f.pixelFormat())); + } + + dbg.nospace() << "QVideoSurfaceFormat(" << typeName; + dbg.nospace() << ", " << f.frameSize(); + dbg.nospace() << ", viewport=" << f.viewport(); + dbg.nospace() << ", pixelAspectRatio=" << f.pixelAspectRatio(); + dbg.nospace() << ")"; + + foreach(const QByteArray& propertyName, f.propertyNames()) + dbg << "\n " << propertyName.data() << " = " << f.property(propertyName.data()); + + return dbg.space(); +} +#endif + +QT_END_NAMESPACE diff --git a/src/multimedia/video/qvideosurfaceformat.h b/src/multimedia/video/qvideosurfaceformat.h new file mode 100644 index 000000000..f830b80a6 --- /dev/null +++ b/src/multimedia/video/qvideosurfaceformat.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 Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QVIDEOSURFACEFORMAT_H +#define QVIDEOSURFACEFORMAT_H + +#include <QtCore/qlist.h> +#include <QtCore/qpair.h> +#include <QtCore/qshareddata.h> +#include <QtCore/qsize.h> +#include <QtGui/qimage.h> +#include <qvideoframe.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + +class QDebug; + +class QVideoSurfaceFormatPrivate; + +class Q_MULTIMEDIA_EXPORT QVideoSurfaceFormat +{ +public: + enum Direction + { + TopToBottom, + BottomToTop + }; + + enum YCbCrColorSpace + { + YCbCr_Undefined, + YCbCr_BT601, + YCbCr_BT709, + YCbCr_xvYCC601, + YCbCr_xvYCC709, + YCbCr_JPEG, +#ifndef qdoc + YCbCr_CustomMatrix +#endif + }; + + QVideoSurfaceFormat(); + QVideoSurfaceFormat( + const QSize &size, + QVideoFrame::PixelFormat pixelFormat, + QAbstractVideoBuffer::HandleType handleType = QAbstractVideoBuffer::NoHandle); + QVideoSurfaceFormat(const QVideoSurfaceFormat &format); + ~QVideoSurfaceFormat(); + + QVideoSurfaceFormat &operator =(const QVideoSurfaceFormat &format); + + bool operator ==(const QVideoSurfaceFormat &format) const; + bool operator !=(const QVideoSurfaceFormat &format) const; + + bool isValid() const; + + QVideoFrame::PixelFormat pixelFormat() const; + QAbstractVideoBuffer::HandleType handleType() const; + + QSize frameSize() const; + void setFrameSize(const QSize &size); + void setFrameSize(int width, int height); + + int frameWidth() const; + int frameHeight() const; + + QRect viewport() const; + void setViewport(const QRect &viewport); + + Direction scanLineDirection() const; + void setScanLineDirection(Direction direction); + + qreal frameRate() const; + void setFrameRate(qreal rate); + + QSize pixelAspectRatio() const; + void setPixelAspectRatio(const QSize &ratio); + void setPixelAspectRatio(int width, int height); + + YCbCrColorSpace yCbCrColorSpace() const; + void setYCbCrColorSpace(YCbCrColorSpace colorSpace); + + QSize sizeHint() const; + + QList<QByteArray> propertyNames() const; + QVariant property(const char *name) const; + void setProperty(const char *name, const QVariant &value); + +private: + QSharedDataPointer<QVideoSurfaceFormatPrivate> d; +}; + +#ifndef QT_NO_DEBUG_STREAM +Q_MULTIMEDIA_EXPORT QDebug operator<<(QDebug, const QVideoSurfaceFormat &); +#endif + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(QVideoSurfaceFormat::Direction) +Q_DECLARE_METATYPE(QVideoSurfaceFormat::YCbCrColorSpace) + +QT_END_HEADER + +#endif + diff --git a/src/multimedia/video/video.pri b/src/multimedia/video/video.pri new file mode 100644 index 000000000..accaa3371 --- /dev/null +++ b/src/multimedia/video/video.pri @@ -0,0 +1,22 @@ + +INCLUDEPATH += video + +PUBLIC_HEADERS += \ + video/qabstractvideobuffer.h \ + video/qabstractvideosurface.h \ + video/qvideoframe.h \ + video/qvideosurfaceformat.h + +PRIVATE_HEADERS += \ + video/qabstractvideobuffer_p.h \ + video/qimagevideobuffer_p.h \ + video/qmemoryvideobuffer_p.h + +SOURCES += \ + video/qabstractvideobuffer.cpp \ + video/qabstractvideosurface.cpp \ + video/qimagevideobuffer.cpp \ + video/qmemoryvideobuffer.cpp \ + video/qvideoframe.cpp \ + video/qvideosurfaceformat.cpp + |