Remove some obsolete bits.

They can be updated again later when things are more stable, if needed.

Change-Id: I73bdacdd3d1fd43a60cd3a0c14b925fa9c32ee27
Reviewed-on: http://codereview.qt.nokia.com/1724
Reviewed-by: Qt Sanity Bot <qt_sanity_bot@ovi.com>
Reviewed-by: Jonas Rabbe <jonas.rabbe@nokia.com>
This commit is contained in:
Michael Goddard
2011-07-18 10:32:16 +10:00
committed by Qt by Nokia
parent 7085775a11
commit 1403a1c7be
264 changed files with 47 additions and 51130 deletions

View File

@@ -40,29 +40,10 @@ win32 {
SOURCES += audio/qaudiodeviceinfo_win32_p.cpp \
audio/qaudiooutput_win32_p.cpp \
audio/qaudioinput_win32_p.cpp
!wince*:LIBS += -lwinmm
wince*:LIBS += -lcoredll
LIBS += -lstrmiids -lole32 -loleaut32
LIBS += -lwinmm -lstrmiids -lole32 -loleaut32
}
symbian {
INCLUDEPATH += $${EPOCROOT}epoc32/include/mmf/common
INCLUDEPATH += $${EPOCROOT}epoc32/include/mmf/server
PRIVATE_HEADERS += audio/qaudio_symbian_p.h \
audio/qaudiodeviceinfo_symbian_p.h \
audio/qaudioinput_symbian_p.h \
audio/qaudiooutput_symbian_p.h
SOURCES += audio/qaudio_symbian_p.cpp \
audio/qaudiodeviceinfo_symbian_p.cpp \
audio/qaudioinput_symbian_p.cpp \
audio/qaudiooutput_symbian_p.cpp
LIBS += -lmmfdevsound
}
unix:!mac:!symbian {
unix:!mac {
contains(pulseaudio_enabled, yes) {
DEFINES += QT_NO_AUDIO_BACKEND
}

View File

@@ -1,663 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Mobility Components.
**
** $QT_BEGIN_LICENSE:LGPL$
** 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_symbian_p.h"
#include <mmffourcc.h>
QT_BEGIN_NAMESPACE
namespace SymbianAudio {
namespace Utils {
//-----------------------------------------------------------------------------
// Static data
//-----------------------------------------------------------------------------
// Sample rate / frequency
typedef TMMFSampleRate SampleRateNative;
typedef int SampleRateQt;
const int SampleRateCount = 12;
const SampleRateNative SampleRateListNative[SampleRateCount] = {
EMMFSampleRate8000Hz
, EMMFSampleRate11025Hz
, EMMFSampleRate12000Hz
, EMMFSampleRate16000Hz
, EMMFSampleRate22050Hz
, EMMFSampleRate24000Hz
, EMMFSampleRate32000Hz
, EMMFSampleRate44100Hz
, EMMFSampleRate48000Hz
, EMMFSampleRate64000Hz
, EMMFSampleRate88200Hz
, EMMFSampleRate96000Hz
};
const SampleRateQt SampleRateListQt[SampleRateCount] = {
8000
, 11025
, 12000
, 16000
, 22050
, 24000
, 32000
, 44100
, 48000
, 64000
, 88200
, 96000
};
// Channels
typedef TMMFMonoStereo ChannelsNative;
typedef int ChannelsQt;
const int ChannelsCount = 2;
const ChannelsNative ChannelsListNative[ChannelsCount] = {
EMMFMono
, EMMFStereo
};
const ChannelsQt ChannelsListQt[ChannelsCount] = {
1
, 2
};
// Encoding
const int EncodingCount = 6;
const TUint32 EncodingFourCC[EncodingCount] = {
KMMFFourCCCodePCM8 // 0
, KMMFFourCCCodePCMU8 // 1
, KMMFFourCCCodePCM16 // 2
, KMMFFourCCCodePCMU16 // 3
, KMMFFourCCCodePCM16B // 4
, KMMFFourCCCodePCMU16B // 5
};
// The characterised DevSound API specification states that the iEncoding
// field in TMMFCapabilities is ignored, and that the FourCC should be used
// to specify the PCM encoding.
// See "SGL.GT0287.102 Multimedia DevSound Baseline Compatibility.doc" in the
// mm_info/mm_docs repository.
const TMMFSoundEncoding EncodingNative[EncodingCount] = {
EMMFSoundEncoding16BitPCM // 0
, EMMFSoundEncoding16BitPCM // 1
, EMMFSoundEncoding16BitPCM // 2
, EMMFSoundEncoding16BitPCM // 3
, EMMFSoundEncoding16BitPCM // 4
, EMMFSoundEncoding16BitPCM // 5
};
const int EncodingSampleSize[EncodingCount] = {
8 // 0
, 8 // 1
, 16 // 2
, 16 // 3
, 16 // 4
, 16 // 5
};
const QAudioFormat::Endian EncodingByteOrder[EncodingCount] = {
QAudioFormat::LittleEndian // 0
, QAudioFormat::LittleEndian // 1
, QAudioFormat::LittleEndian // 2
, QAudioFormat::LittleEndian // 3
, QAudioFormat::BigEndian // 4
, QAudioFormat::BigEndian // 5
};
const QAudioFormat::SampleType EncodingSampleType[EncodingCount] = {
QAudioFormat::SignedInt // 0
, QAudioFormat::UnSignedInt // 1
, QAudioFormat::SignedInt // 2
, QAudioFormat::UnSignedInt // 3
, QAudioFormat::SignedInt // 4
, QAudioFormat::UnSignedInt // 5
};
//-----------------------------------------------------------------------------
// Private functions
//-----------------------------------------------------------------------------
// Helper functions for implementing parameter conversions
template<typename Input>
bool findValue(const Input *inputArray, int length, Input input, int &index) {
bool result = false;
for (int i=0; !result && i<length; ++i)
if (inputArray[i] == input) {
index = i;
result = true;
}
return result;
}
template<typename Input, typename Output>
bool convertValue(const Input *inputArray, const Output *outputArray,
int length, Input input, Output &output) {
int index;
const bool result = findValue<Input>(inputArray, length, input, index);
if (result)
output = outputArray[index];
return result;
}
/**
* Macro which is used to generate the implementation of the conversion
* functions. The implementation is just a wrapper around the templated
* convertValue function, e.g.
*
* CONVERSION_FUNCTION_IMPL(SampleRate, Qt, Native)
*
* expands to
*
* bool SampleRateQtToNative(int input, TMMFSampleRate &output) {
* return convertValue<SampleRateQt, SampleRateNative>
* (SampleRateListQt, SampleRateListNative, SampleRateCount,
* input, output);
* }
*/
#define CONVERSION_FUNCTION_IMPL(FieldLc, Field, Input, Output) \
bool FieldLc##Input##To##Output(Field##Input input, Field##Output &output) { \
return convertValue<Field##Input, Field##Output>(Field##List##Input, \
Field##List##Output, Field##Count, input, output); \
}
//-----------------------------------------------------------------------------
// Local helper functions
//-----------------------------------------------------------------------------
CONVERSION_FUNCTION_IMPL(sampleRate, SampleRate, Qt, Native)
CONVERSION_FUNCTION_IMPL(sampleRate, SampleRate, Native, Qt)
CONVERSION_FUNCTION_IMPL(channels, Channels, Qt, Native)
CONVERSION_FUNCTION_IMPL(channels, Channels, Native, Qt)
bool sampleInfoQtToNative(int inputSampleSize,
QAudioFormat::Endian inputByteOrder,
QAudioFormat::SampleType inputSampleType,
TUint32 &outputFourCC,
TMMFSoundEncoding &outputEncoding) {
bool found = false;
for (int i=0; i<EncodingCount && !found; ++i) {
if ( EncodingSampleSize[i] == inputSampleSize
&& EncodingByteOrder[i] == inputByteOrder
&& EncodingSampleType[i] == inputSampleType) {
outputFourCC = EncodingFourCC[i];
outputEncoding = EncodingNative[i]; // EMMFSoundEncoding16BitPCM
found = true;
}
}
return found;
}
void capabilitiesNativeToQt(const TMMFCapabilities &caps,
const TFourCC &fourcc,
QList<int> &frequencies,
QList<int> &channels,
QList<int> &sampleSizes,
QList<QAudioFormat::Endian> &byteOrders,
QList<QAudioFormat::SampleType> &sampleTypes) {
frequencies.clear();
sampleSizes.clear();
byteOrders.clear();
sampleTypes.clear();
channels.clear();
for (int i=0; i<SampleRateCount; ++i)
if (caps.iRate & SampleRateListNative[i])
frequencies += SampleRateListQt[i];
for (int i=0; i<ChannelsCount; ++i)
if (caps.iChannels & ChannelsListNative[i])
channels += ChannelsListQt[i];
for (int i=0; i<EncodingCount; ++i) {
if (fourcc == EncodingFourCC[i]) {
sampleSizes += EncodingSampleSize[i];
byteOrders += EncodingByteOrder[i];
sampleTypes += EncodingSampleType[i];
}
}
}
bool formatQtToNative(const QAudioFormat &inputFormat,
TUint32 &outputFourCC,
TMMFCapabilities &outputFormat) {
bool result = false;
// Need to use temporary variables because TMMFCapabilities fields are all
// TInt, rather than MMF enumerated types.
TMMFSampleRate outputSampleRate;
TMMFMonoStereo outputChannels;
TMMFSoundEncoding outputEncoding;
if (inputFormat.codec() == QLatin1String("audio/pcm")) {
result =
sampleRateQtToNative(inputFormat.frequency(), outputSampleRate)
&& channelsQtToNative(inputFormat.channels(), outputChannels)
&& sampleInfoQtToNative(inputFormat.sampleSize(),
inputFormat.byteOrder(),
inputFormat.sampleType(),
outputFourCC,
outputEncoding);
}
if (result) {
outputFormat.iRate = outputSampleRate;
outputFormat.iChannels = outputChannels;
outputFormat.iEncoding = outputEncoding;
}
return result;
}
QAudio::State stateNativeToQt(State nativeState)
{
switch (nativeState) {
case ClosedState:
return QAudio::StoppedState;
case InitializingState:
return QAudio::StoppedState;
case ActiveState:
return QAudio::ActiveState;
case IdleState:
return QAudio::IdleState;
case SuspendedPausedState:
case SuspendedStoppedState:
return QAudio::SuspendedState;
default:
Q_ASSERT_X(false, Q_FUNC_INFO, "Invalid state");
return QAudio::StoppedState; // suppress compiler warning
}
}
qint64 bytesToSamples(const QAudioFormat &format, qint64 length)
{
return length / ((format.sampleSize() / 8) * format.channels());
}
qint64 samplesToBytes(const QAudioFormat &format, qint64 samples)
{
return samples * (format.sampleSize() / 8) * format.channels();
}
} // namespace Utils
//-----------------------------------------------------------------------------
// DevSoundWrapper
//-----------------------------------------------------------------------------
DevSoundWrapper::DevSoundWrapper(QAudio::Mode mode, QObject *parent)
: QObject(parent)
, m_mode(mode)
, m_state(StateIdle)
, m_devsound(0)
, m_fourcc(0)
{
QT_TRAP_THROWING(m_devsound = CMMFDevSound::NewL());
switch (mode) {
case QAudio::AudioOutput:
m_nativeMode = EMMFStatePlaying;
break;
case QAudio::AudioInput:
m_nativeMode = EMMFStateRecording;
break;
default:
Q_ASSERT_X(false, Q_FUNC_INFO, "Invalid mode");
}
getSupportedCodecs();
}
DevSoundWrapper::~DevSoundWrapper()
{
delete m_devsound;
}
const QList<QString>& DevSoundWrapper::supportedCodecs() const
{
return m_supportedCodecs;
}
void DevSoundWrapper::initialize(const QString& codec)
{
Q_ASSERT(StateInitializing != m_state);
m_state = StateInitializing;
if (QLatin1String("audio/pcm") == codec) {
m_fourcc = KMMFFourCCCodePCM16;
TRAPD(err, m_devsound->InitializeL(*this, m_fourcc, m_nativeMode));
if (KErrNone != err) {
m_state = StateIdle;
emit initializeComplete(err);
}
} else {
emit initializeComplete(KErrNotSupported);
}
}
const QList<int>& DevSoundWrapper::supportedFrequencies() const
{
Q_ASSERT(StateInitialized == m_state);
return m_supportedFrequencies;
}
const QList<int>& DevSoundWrapper::supportedChannels() const
{
Q_ASSERT(StateInitialized == m_state);
return m_supportedChannels;
}
const QList<int>& DevSoundWrapper::supportedSampleSizes() const
{
Q_ASSERT(StateInitialized == m_state);
return m_supportedSampleSizes;
}
const QList<QAudioFormat::Endian>& DevSoundWrapper::supportedByteOrders() const
{
Q_ASSERT(StateInitialized == m_state);
return m_supportedByteOrders;
}
const QList<QAudioFormat::SampleType>& DevSoundWrapper::supportedSampleTypes() const
{
Q_ASSERT(StateInitialized == m_state);
return m_supportedSampleTypes;
}
bool DevSoundWrapper::isFormatSupported(const QAudioFormat &format) const
{
Q_ASSERT(StateInitialized == m_state);
return m_supportedCodecs.contains(format.codec())
&& m_supportedFrequencies.contains(format.frequency())
&& m_supportedChannels.contains(format.channels())
&& m_supportedSampleSizes.contains(format.sampleSize())
&& m_supportedSampleTypes.contains(format.sampleType())
&& m_supportedByteOrders.contains(format.byteOrder());
}
int DevSoundWrapper::samplesProcessed() const
{
int result = 0;
if (StateInitialized == m_state) {
switch (m_mode) {
case QAudio::AudioInput:
result = m_devsound->SamplesRecorded();
break;
case QAudio::AudioOutput:
result = m_devsound->SamplesPlayed();
break;
}
}
return result;
}
bool DevSoundWrapper::setFormat(const QAudioFormat &format)
{
Q_ASSERT(StateInitialized == m_state);
bool result = false;
TUint32 fourcc;
TMMFCapabilities nativeFormat;
if (Utils::formatQtToNative(format, fourcc, nativeFormat)) {
TMMFCapabilities currentNativeFormat = m_devsound->Config();
nativeFormat.iBufferSize = currentNativeFormat.iBufferSize;
TRAPD(err, m_devsound->SetConfigL(nativeFormat));
result = (KErrNone == err);
}
return result;
}
bool DevSoundWrapper::start()
{
Q_ASSERT(StateInitialized == m_state);
int err = KErrArgument;
switch (m_mode) {
case QAudio::AudioInput:
TRAP(err, m_devsound->RecordInitL());
break;
case QAudio::AudioOutput:
TRAP(err, m_devsound->PlayInitL());
break;
}
return (KErrNone == err);
}
bool DevSoundWrapper::pause()
{
Q_ASSERT(StateInitialized == m_state);
#ifndef PRE_S60_52_PLATFORM
if (m_mode == QAudio::AudioOutput ) {
m_devsound->Pause();
return true;
} else {
const bool canPause = isResumeSupported();
if (canPause)
m_devsound->Pause();
else
stop();
return canPause;
}
#else
const bool canPause = isResumeSupported();
if (canPause)
m_devsound->Pause();
else
stop();
return canPause;
#endif
}
void DevSoundWrapper::resume()
{
Q_ASSERT(StateInitialized == m_state);
Q_ASSERT(isResumeSupported());
// TODO: QTBUG-13625
}
void DevSoundWrapper::stop()
{
m_devsound->Stop();
}
void DevSoundWrapper::bufferProcessed()
{
Q_ASSERT(StateInitialized == m_state);
switch (m_mode) {
case QAudio::AudioInput:
m_devsound->RecordData();
break;
case QAudio::AudioOutput:
m_devsound->PlayData();
break;
}
}
void DevSoundWrapper::getSupportedCodecs()
{
/*
* TODO: once we support formats other than PCM, this function should
* convert the array of FourCC codes into MIME types for each codec.
*
RArray<TFourCC> fourcc;
QT_TRAP_THROWING(CleanupClosePushL(&fourcc));
TMMFPrioritySettings settings;
switch (mode) {
case QAudio::AudioOutput:
settings.iState = EMMFStatePlaying;
m_devsound->GetSupportedInputDataTypesL(fourcc, settings);
break;
case QAudio::AudioInput:
settings.iState = EMMFStateRecording;
m_devsound->GetSupportedInputDataTypesL(fourcc, settings);
break;
default:
Q_ASSERT_X(false, Q_FUNC_INFO, "Invalid mode");
}
CleanupStack::PopAndDestroy(); // fourcc
*/
m_supportedCodecs.append(QLatin1String("audio/pcm"));
}
void DevSoundWrapper::populateCapabilities()
{
m_supportedFrequencies.clear();
m_supportedChannels.clear();
m_supportedSampleSizes.clear();
m_supportedByteOrders.clear();
m_supportedSampleTypes.clear();
const TMMFCapabilities caps = m_devsound->Capabilities();
for (int i=0; i<Utils::SampleRateCount; ++i)
if (caps.iRate & Utils::SampleRateListNative[i])
m_supportedFrequencies += Utils::SampleRateListQt[i];
for (int i=0; i<Utils::ChannelsCount; ++i)
if (caps.iChannels & Utils::ChannelsListNative[i])
m_supportedChannels += Utils::ChannelsListQt[i];
for (int i=0; i<Utils::EncodingCount; ++i) {
if (m_fourcc == Utils::EncodingFourCC[i]) {
m_supportedSampleSizes += Utils::EncodingSampleSize[i];
m_supportedByteOrders += Utils::EncodingByteOrder[i];
m_supportedSampleTypes += Utils::EncodingSampleType[i];
}
}
}
bool DevSoundWrapper::isResumeSupported() const
{
// TODO: QTBUG-13625
return false;
}
void DevSoundWrapper::InitializeComplete(TInt aError)
{
Q_ASSERT(StateInitializing == m_state);
if (KErrNone == aError) {
m_state = StateInitialized;
populateCapabilities();
} else {
m_state = StateIdle;
}
emit initializeComplete(aError);
}
void DevSoundWrapper::ToneFinished(TInt aError)
{
Q_UNUSED(aError)
// This class doesn't use DevSound's tone playback functions, so should
// never receive this callback.
Q_ASSERT_X(false, Q_FUNC_INFO, "Unexpected callback");
}
void DevSoundWrapper::BufferToBeFilled(CMMFBuffer *aBuffer)
{
Q_ASSERT(QAudio::AudioOutput == m_mode);
emit bufferToBeProcessed(aBuffer);
}
void DevSoundWrapper::PlayError(TInt aError)
{
Q_ASSERT(QAudio::AudioOutput == m_mode);
emit processingError(aError);
}
void DevSoundWrapper::BufferToBeEmptied(CMMFBuffer *aBuffer)
{
Q_ASSERT(QAudio::AudioInput == m_mode);
emit bufferToBeProcessed(aBuffer);
}
void DevSoundWrapper::RecordError(TInt aError)
{
Q_ASSERT(QAudio::AudioInput == m_mode);
emit processingError(aError);
}
void DevSoundWrapper::ConvertError(TInt aError)
{
Q_UNUSED(aError)
// This class doesn't use DevSound's format conversion functions, so
// should never receive this callback.
Q_ASSERT_X(false, Q_FUNC_INFO, "Unexpected callback");
}
void DevSoundWrapper::DeviceMessage(TUid aMessageType, const TDesC8 &aMsg)
{
Q_UNUSED(aMessageType)
Q_UNUSED(aMsg)
// Ignore this callback.
}
#ifndef PRE_S60_52_PLATFORM
int DevSoundWrapper::flush()
{
return m_devsound->EmptyBuffers();
}
#endif
} // namespace SymbianAudio
QT_END_NAMESPACE

View File

@@ -1,204 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Mobility Components.
**
** $QT_BEGIN_LICENSE:LGPL$
** 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_SYMBIAN_P_H
#define QAUDIO_SYMBIAN_P_H
#include <QtCore/qnamespace.h>
#include <QtCore/QList>
#include <QtCore/QString>
#include <qaudioformat.h>
#include <qaudio.h>
#include <sounddevice.h>
QT_BEGIN_NAMESPACE
namespace SymbianAudio {
/**
* Default values used by audio input and output classes, when underlying
* DevSound instance has not yet been created.
*/
const int DefaultBufferSize = 4096; // bytes
const int DefaultNotifyInterval = 1000; // ms
/**
* Enumeration used to track state of internal DevSound instances.
* Values are translated to the corresponding QAudio::State values by
* SymbianAudio::Utils::stateNativeToQt.
*/
enum State {
ClosedState
, InitializingState
, ActiveState
, IdleState
// QAudio is suspended; DevSound is paused
, SuspendedPausedState
// QAudio is suspended; DevSound is stopped
, SuspendedStoppedState
};
/**
* Wrapper around DevSound instance
*/
class DevSoundWrapper
: public QObject
, public MDevSoundObserver
{
Q_OBJECT
public:
DevSoundWrapper(QAudio::Mode mode, QObject *parent = 0);
~DevSoundWrapper();
public:
// List of supported codecs; can be called once object is constructed
const QList<QString>& supportedCodecs() const;
// Asynchronous initialization function; emits devsoundInitializeComplete
void initialize(const QString& codec);
// Capabilities, for selected codec. Can be called once initialize has returned
// successfully.
const QList<int>& supportedFrequencies() const;
const QList<int>& supportedChannels() const;
const QList<int>& supportedSampleSizes() const;
const QList<QAudioFormat::Endian>& supportedByteOrders() const;
const QList<QAudioFormat::SampleType>& supportedSampleTypes() const;
bool isFormatSupported(const QAudioFormat &format) const;
int samplesProcessed() const;
bool setFormat(const QAudioFormat &format);
bool start();
// If DevSound implementation supports pause, calls pause and returns true.
// Otherwise calls stop and returns false. In this case, all DevSound buffers
// currently held by the backend must be discarded.
bool pause();
void resume();
void stop();
void bufferProcessed();
#ifndef PRE_S60_52_PLATFORM
int flush();
#endif
public:
// MDevSoundObserver
void InitializeComplete(TInt aError);
void ToneFinished(TInt aError);
void BufferToBeFilled(CMMFBuffer *aBuffer);
void PlayError(TInt aError);
void BufferToBeEmptied(CMMFBuffer *aBuffer);
void RecordError(TInt aError);
void ConvertError(TInt aError);
void DeviceMessage(TUid aMessageType, const TDesC8 &aMsg);
signals:
void initializeComplete(int error);
void bufferToBeProcessed(CMMFBuffer *buffer);
void processingError(int error);
private:
void getSupportedCodecs();
void populateCapabilities();
bool isResumeSupported() const;
private:
const QAudio::Mode m_mode;
TMMFState m_nativeMode;
enum State {
StateIdle,
StateInitializing,
StateInitialized
} m_state;
CMMFDevSound* m_devsound;
TFourCC m_fourcc;
QList<QString> m_supportedCodecs;
QList<int> m_supportedFrequencies;
QList<int> m_supportedChannels;
QList<int> m_supportedSampleSizes;
QList<QAudioFormat::Endian> m_supportedByteOrders;
QList<QAudioFormat::SampleType> m_supportedSampleTypes;
};
namespace Utils {
/**
* Convert internal states to QAudio states.
*/
QAudio::State stateNativeToQt(State nativeState);
/**
* Convert data length to number of samples.
*/
qint64 bytesToSamples(const QAudioFormat &format, qint64 length);
/**
* Convert number of samples to data length.
*/
qint64 samplesToBytes(const QAudioFormat &format, qint64 samples);
} // namespace Utils
} // namespace SymbianAudio
QT_END_NAMESPACE
#endif

View File

@@ -60,10 +60,6 @@
#include "qaudiodeviceinfo_alsa_p.h"
#include "qaudiooutput_alsa_p.h"
#include "qaudioinput_alsa_p.h"
#elif defined(Q_OS_SYMBIAN)
#include "qaudiodeviceinfo_symbian_p.h"
#include "qaudiooutput_symbian_p.h"
#include "qaudioinput_symbian_p.h"
#endif
#endif
@@ -139,7 +135,7 @@ 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) || defined(Q_OS_SYMBIAN))
#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
@@ -174,7 +170,7 @@ QAudioDeviceInfo QAudioDeviceFactory::defaultInputDevice()
#endif
#ifndef QT_NO_AUDIO_BACKEND
#if (defined(Q_OS_WIN) || defined(Q_OS_MAC) || defined(HAS_ALSA) || defined(Q_OS_SYMBIAN))
#if (defined(Q_OS_WIN) || defined(Q_OS_MAC) || defined(HAS_ALSA))
return QAudioDeviceInfo(QLatin1String("builtin"), QAudioDeviceInfoInternal::defaultInputDevice(), QAudio::AudioInput);
#endif
#endif
@@ -194,7 +190,7 @@ QAudioDeviceInfo QAudioDeviceFactory::defaultOutputDevice()
#endif
#ifndef QT_NO_AUDIO_BACKEND
#if (defined(Q_OS_WIN) || defined(Q_OS_MAC) || defined(HAS_ALSA) || defined(Q_OS_SYMBIAN))
#if (defined(Q_OS_WIN) || defined(Q_OS_MAC) || defined(HAS_ALSA))
return QAudioDeviceInfo(QLatin1String("builtin"), QAudioDeviceInfoInternal::defaultOutputDevice(), QAudio::AudioOutput);
#endif
#endif
@@ -206,7 +202,7 @@ QAbstractAudioDeviceInfo* QAudioDeviceFactory::audioDeviceInfo(const QString &re
QAbstractAudioDeviceInfo *rc = 0;
#ifndef QT_NO_AUDIO_BACKEND
#if (defined(Q_OS_WIN) || defined(Q_OS_MAC) || defined(HAS_ALSA) || defined(Q_OS_SYMBIAN))
#if (defined(Q_OS_WIN) || defined(Q_OS_MAC) || defined(HAS_ALSA))
if (realm == QLatin1String("builtin"))
return new QAudioDeviceInfoInternal(handle, mode);
#endif
@@ -238,7 +234,7 @@ QAbstractAudioInput* QAudioDeviceFactory::createInputDevice(QAudioDeviceInfo con
if (deviceInfo.isNull())
return new QNullInputDevice();
#ifndef QT_NO_AUDIO_BACKEND
#if (defined(Q_OS_WIN) || defined(Q_OS_MAC) || defined(HAS_ALSA) || defined(Q_OS_SYMBIAN))
#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);
@@ -265,7 +261,7 @@ QAbstractAudioOutput* QAudioDeviceFactory::createOutputDevice(QAudioDeviceInfo c
if (deviceInfo.isNull())
return new QNullOutputDevice();
#ifndef QT_NO_AUDIO_BACKEND
#if (defined(Q_OS_WIN) || defined(Q_OS_MAC) || defined(HAS_ALSA) || defined(Q_OS_SYMBIAN))
#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);

View File

@@ -1,235 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Mobility Components.
**
** $QT_BEGIN_LICENSE:LGPL$
** 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/QCoreApplication>
#include "qaudiodeviceinfo_symbian_p.h"
#include "qaudio_symbian_p.h"
QT_BEGIN_NAMESPACE
QAudioDeviceInfoInternal::QAudioDeviceInfoInternal(QByteArray device,
QAudio::Mode mode)
: m_deviceName(QLatin1String(device))
, m_mode(mode)
, m_updated(false)
{
}
QAudioDeviceInfoInternal::~QAudioDeviceInfoInternal()
{
}
QAudioFormat QAudioDeviceInfoInternal::preferredFormat() const
{
QAudioFormat format;
switch (m_mode) {
case QAudio::AudioOutput:
format.setFrequency(44100);
format.setChannels(2);
format.setSampleSize(16);
format.setByteOrder(QAudioFormat::LittleEndian);
format.setSampleType(QAudioFormat::SignedInt);
format.setCodec(QLatin1String("audio/pcm"));
break;
case QAudio::AudioInput:
format.setFrequency(8000);
format.setChannels(1);
format.setSampleSize(16);
format.setByteOrder(QAudioFormat::LittleEndian);
format.setSampleType(QAudioFormat::SignedInt);
format.setCodec(QLatin1String("audio/pcm"));
break;
default:
Q_ASSERT_X(false, Q_FUNC_INFO, "Invalid mode");
}
if (!isFormatSupported(format)) {
format = QAudioFormat();
format.setCodec(QLatin1String("audio/pcm"));
if (m_capabilities.contains(format.codec())) {
const Capabilities &codecCaps = m_capabilities[format.codec()];
if (codecCaps.m_frequencies.size())
format.setFrequency(codecCaps.m_frequencies[0]);
if (codecCaps.m_channels.size())
format.setChannels(codecCaps.m_channels[0]);
if (codecCaps.m_sampleSizes.size())
format.setSampleSize(codecCaps.m_sampleSizes[0]);
if (codecCaps.m_byteOrders.size())
format.setByteOrder(codecCaps.m_byteOrders[0]);
if (codecCaps.m_sampleTypes.size())
format.setSampleType(codecCaps.m_sampleTypes[0]);
}
}
return format;
}
bool QAudioDeviceInfoInternal::isFormatSupported(
const QAudioFormat &format) const
{
getSupportedFormats();
bool supported = false;
if (m_capabilities.contains(format.codec())) {
const Capabilities &codecCaps = m_capabilities[format.codec()];
supported = codecCaps.m_frequencies.contains(format.frequency())
&& codecCaps.m_channels.contains(format.channels())
&& codecCaps.m_sampleSizes.contains(format.sampleSize())
&& codecCaps.m_byteOrders.contains(format.byteOrder())
&& codecCaps.m_sampleTypes.contains(format.sampleType());
}
return supported;
}
QString QAudioDeviceInfoInternal::deviceName() const
{
return m_deviceName;
}
QStringList QAudioDeviceInfoInternal::supportedCodecs()
{
getSupportedFormats();
return m_capabilities.keys();
}
QList<int> QAudioDeviceInfoInternal::supportedSampleRates()
{
getSupportedFormats();
return m_unionCapabilities.m_frequencies;
}
QList<int> QAudioDeviceInfoInternal::supportedChannelCounts()
{
getSupportedFormats();
return m_unionCapabilities.m_channels;
}
QList<int> QAudioDeviceInfoInternal::supportedSampleSizes()
{
getSupportedFormats();
return m_unionCapabilities.m_sampleSizes;
}
QList<QAudioFormat::Endian> QAudioDeviceInfoInternal::supportedByteOrders()
{
getSupportedFormats();
return m_unionCapabilities.m_byteOrders;
}
QList<QAudioFormat::SampleType> QAudioDeviceInfoInternal::supportedSampleTypes()
{
getSupportedFormats();
return m_unionCapabilities. m_sampleTypes;
}
QByteArray QAudioDeviceInfoInternal::defaultInputDevice()
{
return QByteArray("default");
}
QByteArray QAudioDeviceInfoInternal::defaultOutputDevice()
{
return QByteArray("default");
}
QList<QByteArray> QAudioDeviceInfoInternal::availableDevices(QAudio::Mode)
{
QList<QByteArray> result;
result += QByteArray("default");
return result;
}
void QAudioDeviceInfoInternal::devsoundInitializeComplete(int err)
{
m_intializationResult = err;
m_initializing = false;
}
// Helper function
template<typename T>
void appendUnique(QList<T> &left, const QList<T> &right)
{
foreach (const T &value, right)
if (!left.contains(value))
left += value;
}
void QAudioDeviceInfoInternal::getSupportedFormats() const
{
if (!m_updated) {
QScopedPointer<SymbianAudio::DevSoundWrapper> devsound(new SymbianAudio::DevSoundWrapper(m_mode));
connect(devsound.data(), SIGNAL(initializeComplete(int)),
this, SLOT(devsoundInitializeComplete(int)));
foreach (const QString& codec, devsound->supportedCodecs()) {
m_initializing = true;
devsound->initialize(codec);
while (m_initializing)
QCoreApplication::instance()->processEvents(QEventLoop::WaitForMoreEvents);
if (KErrNone == m_intializationResult) {
m_capabilities[codec].m_frequencies = devsound->supportedFrequencies();
appendUnique(m_unionCapabilities.m_frequencies, devsound->supportedFrequencies());
m_capabilities[codec].m_channels = devsound->supportedChannels();
appendUnique(m_unionCapabilities.m_channels, devsound->supportedChannels());
m_capabilities[codec].m_sampleSizes = devsound->supportedSampleSizes();
appendUnique(m_unionCapabilities.m_sampleSizes, devsound->supportedSampleSizes());
m_capabilities[codec].m_byteOrders = devsound->supportedByteOrders();
appendUnique(m_unionCapabilities.m_byteOrders, devsound->supportedByteOrders());
m_capabilities[codec].m_sampleTypes = devsound->supportedSampleTypes();
appendUnique(m_unionCapabilities.m_sampleTypes, devsound->supportedSampleTypes());
}
}
m_updated = true;
}
}
QT_END_NAMESPACE
#include "moc_qaudiodeviceinfo_symbian_p.cpp"

View File

@@ -1,116 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Mobility Components.
**
** $QT_BEGIN_LICENSE:LGPL$
** 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 QAUDIODEVICEINFO_SYMBIAN_P_H
#define QAUDIODEVICEINFO_SYMBIAN_P_H
#include <QtCore/QMap>
#include <qaudiosystem.h>
#include <sounddevice.h>
QT_BEGIN_NAMESPACE
class QAudioDeviceInfoInternal
: public QAbstractAudioDeviceInfo
{
Q_OBJECT
public:
QAudioDeviceInfoInternal(QByteArray device, QAudio::Mode mode);
~QAudioDeviceInfoInternal();
// QAbstractAudioDeviceInfo
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 slots:
void devsoundInitializeComplete(int err);
private:
void getSupportedFormats() const;
private:
mutable bool m_initializing;
int m_intializationResult;
QString m_deviceName;
QAudio::Mode m_mode;
struct Capabilities
{
QList<int> m_frequencies;
QList<int> m_channels;
QList<int> m_sampleSizes;
QList<QAudioFormat::Endian> m_byteOrders;
QList<QAudioFormat::SampleType> m_sampleTypes;
};
// Mutable to allow lazy initialization when called from const-qualified
// public functions (isFormatSupported, nearestFormat)
mutable bool m_updated;
mutable QMap<QString, Capabilities> m_capabilities;
mutable Capabilities m_unionCapabilities;
};
QT_END_NAMESPACE
#endif

View File

@@ -315,12 +315,10 @@ void QAudioDeviceInfoInternal::updateLists()
|| (fmt && WAVE_FORMAT_2S08)
|| (fmt && WAVE_FORMAT_4M08)
|| (fmt && WAVE_FORMAT_4S08)
#ifndef Q_OS_WINCE
|| (fmt && WAVE_FORMAT_48M08)
|| (fmt && WAVE_FORMAT_48S08)
|| (fmt && WAVE_FORMAT_96M08)
|| (fmt && WAVE_FORMAT_96S08)
#endif
) {
sizez.append(8);
}
@@ -330,12 +328,10 @@ void QAudioDeviceInfoInternal::updateLists()
|| (fmt && WAVE_FORMAT_2S16)
|| (fmt && WAVE_FORMAT_4M16)
|| (fmt && WAVE_FORMAT_4S16)
#ifndef Q_OS_WINCE
|| (fmt && WAVE_FORMAT_48M16)
|| (fmt && WAVE_FORMAT_48S16)
|| (fmt && WAVE_FORMAT_96M16)
|| (fmt && WAVE_FORMAT_96S16)
#endif
) {
sizez.append(16);
}
@@ -357,7 +353,6 @@ void QAudioDeviceInfoInternal::updateLists()
|| (fmt && WAVE_FORMAT_4S16)) {
freqz.append(44100);
}
#ifndef Q_OS_WINCE
if((fmt && WAVE_FORMAT_48M08)
|| (fmt && WAVE_FORMAT_48S08)
|| (fmt && WAVE_FORMAT_48M16)
@@ -370,7 +365,6 @@ void QAudioDeviceInfoInternal::updateLists()
|| (fmt && WAVE_FORMAT_96S16)) {
freqz.append(96000);
}
#endif
channelz.append(1);
channelz.append(2);
if (mode == QAudio::AudioOutput) {

View File

@@ -117,20 +117,6 @@ QT_BEGIN_NAMESPACE
\snippet doc/src/snippets/multimedia-snippets/audio.cpp Audio input state changed
\sa QAudioOutput, QAudioDeviceInfo
\section1 Symbian Platform Security Requirements
On Symbian, processes which use this class must have the
\c UserEnvironment platform security capability. If the client
process lacks this capability, calls to either overload of start()
will fail.
This failure is indicated by the QAudioInput object setting
its error() value to \l{QAudio::OpenError} and then emitting a
\l{stateChanged()}{stateChanged}(\l{QAudio::StoppedState}) signal.
Platform security capabilities are added via the
\l{qmake-variable-reference.html#target-capability}{TARGET.CAPABILITY}
qmake variable.
*/
/*!
@@ -184,8 +170,6 @@ QAudioInput::~QAudioInput()
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.
\l{QAudioInput#Symbian Platform Security Requirements}
\since 1.0
\sa QIODevice
*/
@@ -207,8 +191,6 @@ void QAudioInput::start(QIODevice* device)
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.
\l{QAudioInput#Symbian Platform Security Requirements}
\since 1.0
\sa QIODevice
*/

View File

@@ -1,594 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Mobility Components.
**
** $QT_BEGIN_LICENSE:LGPL$
** 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 "qaudioinput_symbian_p.h"
QT_BEGIN_NAMESPACE
//-----------------------------------------------------------------------------
// Constants
//-----------------------------------------------------------------------------
const int PushInterval = 50; // ms
//-----------------------------------------------------------------------------
// Private class
//-----------------------------------------------------------------------------
SymbianAudioInputPrivate::SymbianAudioInputPrivate(
QAudioInputPrivate *audioDevice)
: m_audioDevice(audioDevice)
{
}
SymbianAudioInputPrivate::~SymbianAudioInputPrivate()
{
}
qint64 SymbianAudioInputPrivate::readData(char *data, qint64 len)
{
qint64 totalRead = 0;
if (m_audioDevice->state() == QAudio::ActiveState ||
m_audioDevice->state() == QAudio::IdleState) {
while (totalRead < len) {
const qint64 read = m_audioDevice->read(data + totalRead,
len - totalRead);
if (read > 0)
totalRead += read;
else
break;
}
}
return totalRead;
}
qint64 SymbianAudioInputPrivate::writeData(const char *data, qint64 len)
{
Q_UNUSED(data)
Q_UNUSED(len)
return 0;
}
void SymbianAudioInputPrivate::dataReady()
{
emit readyRead();
}
//-----------------------------------------------------------------------------
// Public functions
//-----------------------------------------------------------------------------
QAudioInputPrivate::QAudioInputPrivate(const QByteArray &device)
: m_device(device)
, m_clientBufferSize(SymbianAudio::DefaultBufferSize)
, m_notifyInterval(SymbianAudio::DefaultNotifyInterval)
, m_notifyTimer(new QTimer(this))
, m_lastNotifyPosition(0)
, m_error(QAudio::NoError)
, m_internalState(SymbianAudio::ClosedState)
, m_externalState(QAudio::StoppedState)
, m_pullMode(false)
, m_sink(0)
, m_pullTimer(new QTimer(this))
, m_devSound(0)
, m_devSoundBuffer(0)
, m_devSoundBufferSize(0)
, m_totalBytesReady(0)
, m_devSoundBufferPos(0)
, m_totalSamplesRecorded(0)
{
qRegisterMetaType<CMMFBuffer *>("CMMFBuffer *");
connect(m_notifyTimer.data(), SIGNAL(timeout()),
this, SIGNAL(notifyTimerExpired()));
m_pullTimer->setInterval(PushInterval);
connect(m_pullTimer.data(), SIGNAL(timeout()), this, SLOT(pullData()));
}
void QAudioInputPrivate::setFormat(const QAudioFormat& fmt)
{
m_format = fmt;
}
QAudioInputPrivate::~QAudioInputPrivate()
{
close();
}
void QAudioInputPrivate::start(QIODevice *device)
{
stop();
open();
if (SymbianAudio::ClosedState != m_internalState) {
m_pullMode = true;
m_sink = device;
m_elapsed.restart();
}
}
QIODevice* QAudioInputPrivate::start()
{
stop();
open();
if (SymbianAudio::ClosedState != m_internalState) {
m_sink = new SymbianAudioInputPrivate(this);
m_sink->open(QIODevice::ReadOnly | QIODevice::Unbuffered);
m_elapsed.restart();
}
return m_sink;
}
void QAudioInputPrivate::stop()
{
close();
}
void QAudioInputPrivate::reset()
{
m_totalSamplesRecorded += getSamplesRecorded();
m_devSound->stop();
startRecording();
}
void QAudioInputPrivate::suspend()
{
if (SymbianAudio::ActiveState == m_internalState
|| SymbianAudio::IdleState == m_internalState) {
m_pullTimer->stop();
const qint64 samplesRecorded = getSamplesRecorded();
m_totalSamplesRecorded += samplesRecorded;
const bool paused = m_devSound->pause();
if (paused) {
if (m_devSoundBuffer)
m_devSoundBufferQ.append(m_devSoundBuffer);
m_devSoundBuffer = 0;
setState(SymbianAudio::SuspendedPausedState);
} else {
m_devSoundBuffer = 0;
m_devSoundBufferQ.clear();
m_devSoundBufferPos = 0;
setState(SymbianAudio::SuspendedStoppedState);
}
}
}
void QAudioInputPrivate::resume()
{
if (QAudio::SuspendedState == m_externalState) {
if (SymbianAudio::SuspendedPausedState == m_internalState)
m_devSound->resume();
else
m_devSound->start();
startDataTransfer();
}
}
int QAudioInputPrivate::bytesReady() const
{
Q_ASSERT(m_devSoundBufferPos <= m_totalBytesReady);
return m_totalBytesReady - m_devSoundBufferPos;
}
int QAudioInputPrivate::periodSize() const
{
return bufferSize();
}
void QAudioInputPrivate::setBufferSize(int value)
{
// Note that DevSound does not allow its client to specify the buffer size.
// This functionality is available via custom interfaces, but since these
// cannot be guaranteed to work across all DevSound implementations, we
// do not use them here.
// In order to comply with the expected bevahiour of QAudioInput, we store
// the value and return it from bufferSize(), but the underlying DevSound
// buffer size remains unchanged.
if (value > 0)
m_clientBufferSize = value;
}
int QAudioInputPrivate::bufferSize() const
{
return m_devSoundBufferSize ? m_devSoundBufferSize : m_clientBufferSize;
}
void QAudioInputPrivate::setNotifyInterval(int ms)
{
if (ms >= 0) {
//const int oldNotifyInterval = m_notifyInterval;
m_notifyInterval = ms;
if (m_notifyInterval && (SymbianAudio::ActiveState == m_internalState ||
SymbianAudio::IdleState == m_internalState))
m_notifyTimer->start(m_notifyInterval);
else
m_notifyTimer->stop();
}
}
int QAudioInputPrivate::notifyInterval() const
{
return m_notifyInterval;
}
qint64 QAudioInputPrivate::processedUSecs() const
{
int samplesPlayed = 0;
if (m_devSound && QAudio::SuspendedState != m_externalState)
samplesPlayed = getSamplesRecorded();
// Protect against division by zero
Q_ASSERT_X(m_format.frequency() > 0, Q_FUNC_INFO, "Invalid frequency");
const qint64 result = qint64(1000000) *
(samplesPlayed + m_totalSamplesRecorded)
/ m_format.frequency();
return result;
}
qint64 QAudioInputPrivate::elapsedUSecs() const
{
const qint64 result = (QAudio::StoppedState == state()) ?
0 : m_elapsed.elapsed() * 1000;
return result;
}
QAudio::Error QAudioInputPrivate::error() const
{
return m_error;
}
QAudio::State QAudioInputPrivate::state() const
{
return m_externalState;
}
QAudioFormat QAudioInputPrivate::format() const
{
return m_format;
}
//-----------------------------------------------------------------------------
// Private functions
//-----------------------------------------------------------------------------
void QAudioInputPrivate::open()
{
Q_ASSERT_X(SymbianAudio::ClosedState == m_internalState,
Q_FUNC_INFO, "DevSound already opened");
Q_ASSERT(!m_devSound);
m_devSound = new SymbianAudio::DevSoundWrapper(QAudio::AudioInput, this);
connect(m_devSound, SIGNAL(initializeComplete(int)),
this, SLOT(devsoundInitializeComplete(int)));
connect(m_devSound, SIGNAL(bufferToBeProcessed(CMMFBuffer *)),
this, SLOT(devsoundBufferToBeEmptied(CMMFBuffer *)));
connect(m_devSound, SIGNAL(processingError(int)),
this, SLOT(devsoundRecordError(int)));
setState(SymbianAudio::InitializingState);
m_devSound->initialize(m_format.codec());
}
void QAudioInputPrivate::startRecording()
{
const int samplesRecorded = m_devSound->samplesProcessed();
Q_ASSERT(samplesRecorded == 0);
bool ok = m_devSound->setFormat(m_format);
if (ok)
ok = m_devSound->start();
if (ok) {
startDataTransfer();
} else {
setError(QAudio::OpenError);
close();
}
}
void QAudioInputPrivate::startDataTransfer()
{
if (m_notifyInterval)
m_notifyTimer->start(m_notifyInterval);
if (m_pullMode)
m_pullTimer->start();
if (bytesReady()) {
setState(SymbianAudio::ActiveState);
if (!m_pullMode)
pushData();
} else {
if (QAudio::SuspendedState == m_externalState)
setState(SymbianAudio::ActiveState);
else
setState(SymbianAudio::IdleState);
}
}
CMMFDataBuffer* QAudioInputPrivate::currentBuffer() const
{
CMMFDataBuffer *result = m_devSoundBuffer;
if (!result && !m_devSoundBufferQ.empty())
result = m_devSoundBufferQ.front();
return result;
}
void QAudioInputPrivate::pushData()
{
Q_ASSERT_X(bytesReady(), Q_FUNC_INFO, "No data available");
Q_ASSERT_X(!m_pullMode, Q_FUNC_INFO, "pushData called when in pull mode");
qobject_cast<SymbianAudioInputPrivate *>(m_sink)->dataReady();
}
qint64 QAudioInputPrivate::read(char *data, qint64 len)
{
// SymbianAudioInputPrivate is ready to read data
Q_ASSERT_X(!m_pullMode, Q_FUNC_INFO,
"read called when in pull mode");
qint64 bytesRead = 0;
CMMFDataBuffer *buffer = 0;
buffer = currentBuffer();
while (buffer && (bytesRead < len)) {
if (SymbianAudio::IdleState == m_internalState)
setState(SymbianAudio::ActiveState);
TDesC8 &inputBuffer = buffer->Data();
Q_ASSERT(inputBuffer.Length() >= m_devSoundBufferPos);
const qint64 inputBytes = inputBuffer.Length() - m_devSoundBufferPos;
const qint64 outputBytes = len - bytesRead;
const qint64 copyBytes = outputBytes < inputBytes ?
outputBytes : inputBytes;
memcpy(data, inputBuffer.Ptr() + m_devSoundBufferPos, copyBytes);
m_devSoundBufferPos += copyBytes;
data += copyBytes;
bytesRead += copyBytes;
if (inputBytes == copyBytes)
bufferEmptied();
buffer = currentBuffer();
}
return bytesRead;
}
void QAudioInputPrivate::notifyTimerExpired()
{
const qint64 pos = processedUSecs();
if (pos > m_lastNotifyPosition) {
int count = (pos - m_lastNotifyPosition) / (m_notifyInterval * 1000);
while (count--) {
emit notify();
m_lastNotifyPosition += m_notifyInterval * 1000;
}
}
}
void QAudioInputPrivate::pullData()
{
Q_ASSERT_X(m_pullMode, Q_FUNC_INFO,
"pullData called when in push mode");
CMMFDataBuffer *buffer = 0;
buffer = currentBuffer();
while (buffer) {
if (SymbianAudio::IdleState == m_internalState)
setState(SymbianAudio::ActiveState);
TDesC8 &inputBuffer = buffer->Data();
Q_ASSERT(inputBuffer.Length() >= m_devSoundBufferPos);
const qint64 inputBytes = inputBuffer.Length() - m_devSoundBufferPos;
const qint64 bytesPushed = m_sink->write(
(char*)inputBuffer.Ptr() + m_devSoundBufferPos, inputBytes);
m_devSoundBufferPos += bytesPushed;
if (inputBytes == bytesPushed)
bufferEmptied();
if (!bytesPushed)
break;
buffer = currentBuffer();
}
}
void QAudioInputPrivate::devsoundInitializeComplete(int err)
{
Q_ASSERT_X(SymbianAudio::InitializingState == m_internalState,
Q_FUNC_INFO, "Invalid state");
if (!err && m_devSound->isFormatSupported(m_format))
startRecording();
else
setError(QAudio::OpenError);
}
void QAudioInputPrivate::devsoundBufferToBeEmptied(CMMFBuffer *baseBuffer)
{
// Following receipt of this signal, DevSound should not provide another
// buffer until we have returned the current one.
Q_ASSERT_X(!m_devSoundBuffer, Q_FUNC_INFO, "Buffer already held");
CMMFDataBuffer *const buffer = static_cast<CMMFDataBuffer*>(baseBuffer);
if (!m_devSoundBufferSize)
m_devSoundBufferSize = buffer->Data().MaxLength();
m_totalBytesReady += buffer->Data().Length();
if (SymbianAudio::SuspendedPausedState == m_internalState) {
m_devSoundBufferQ.append(buffer);
} else {
// Will be returned to DevSoundWrapper by bufferProcessed().
m_devSoundBuffer = buffer;
m_devSoundBufferPos = 0;
if (bytesReady() && !m_pullMode)
pushData();
}
}
void QAudioInputPrivate::devsoundRecordError(int err)
{
Q_UNUSED(err)
setError(QAudio::IOError);
}
void QAudioInputPrivate::bufferEmptied()
{
m_devSoundBufferPos = 0;
if (m_devSoundBuffer) {
m_totalBytesReady -= m_devSoundBuffer->Data().Length();
m_devSoundBuffer = 0;
m_devSound->bufferProcessed();
} else {
Q_ASSERT(!m_devSoundBufferQ.empty());
m_totalBytesReady -= m_devSoundBufferQ.front()->Data().Length();
m_devSoundBufferQ.erase(m_devSoundBufferQ.begin());
// If the queue has been emptied, resume transfer from the hardware
if (m_devSoundBufferQ.empty())
if (!m_devSound->start())
setError(QAudio::IOError);
}
Q_ASSERT(m_totalBytesReady >= 0);
}
void QAudioInputPrivate::close()
{
m_lastNotifyPosition = 0;
m_pullTimer->stop();
m_error = QAudio::NoError;
if (m_devSound)
m_devSound->stop();
delete m_devSound;
m_devSound = 0;
m_devSoundBuffer = 0;
m_devSoundBufferSize = 0;
m_totalBytesReady = 0;
if (!m_pullMode) // m_sink is owned
delete m_sink;
m_pullMode = false;
m_sink = 0;
m_devSoundBufferQ.clear();
m_devSoundBufferPos = 0;
m_totalSamplesRecorded = 0;
setState(SymbianAudio::ClosedState);
}
qint64 QAudioInputPrivate::getSamplesRecorded() const
{
qint64 result = 0;
if (m_devSound)
result = qint64(m_devSound->samplesProcessed());
return result;
}
void QAudioInputPrivate::setError(QAudio::Error error)
{
m_error = error;
// Although no state transition actually occurs here, a stateChanged event
// must be emitted to inform the client that the call to start() was
// unsuccessful.
if (QAudio::OpenError == error) {
emit stateChanged(QAudio::StoppedState);
} else {
if (QAudio::UnderrunError == error)
setState(SymbianAudio::IdleState);
else
// Close the DevSound instance. This causes a transition to
// StoppedState. This must be done asynchronously in case the
// current function was called from a DevSound event handler, in which
// case deleting the DevSound instance may cause an exception.
QMetaObject::invokeMethod(this, "close", Qt::QueuedConnection);
}
}
void QAudioInputPrivate::setState(SymbianAudio::State newInternalState)
{
const QAudio::State oldExternalState = m_externalState;
m_internalState = newInternalState;
m_externalState = SymbianAudio::Utils::stateNativeToQt(m_internalState);
if (m_externalState != QAudio::ActiveState &&
m_externalState != QAudio::IdleState)
m_notifyTimer->stop();
if (m_externalState != oldExternalState)
emit stateChanged(m_externalState);
}
QT_END_NAMESPACE
#include "moc_qaudioinput_symbian_p.cpp"

View File

@@ -1,178 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Mobility Components.
**
** $QT_BEGIN_LICENSE:LGPL$
** 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_SYMBIAN_P_H
#define QAUDIOINPUT_SYMBIAN_P_H
#include <qaudiosystem.h>
#include <QTime>
#include <QTimer>
#include "qaudio_symbian_p.h"
QT_BEGIN_NAMESPACE
class QAudioInputPrivate;
class SymbianAudioInputPrivate : public QIODevice
{
friend class QAudioInputPrivate;
Q_OBJECT
public:
SymbianAudioInputPrivate(QAudioInputPrivate *audio);
~SymbianAudioInputPrivate();
qint64 readData(char *data, qint64 len);
qint64 writeData(const char *data, qint64 len);
void dataReady();
private:
QAudioInputPrivate *const m_audioDevice;
};
class QAudioInputPrivate
: public QAbstractAudioInput
{
friend class SymbianAudioInputPrivate;
Q_OBJECT
public:
QAudioInputPrivate(const QByteArray &device);
~QAudioInputPrivate();
// QAbstractAudioInput
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;
QAudioFormat format() const;
void setFormat(const QAudioFormat& fmt);
private slots:
void notifyTimerExpired();
void pullData();
void devsoundInitializeComplete(int err);
void devsoundBufferToBeEmptied(CMMFBuffer *);
void devsoundRecordError(int err);
private:
void open();
void startRecording();
void startDataTransfer();
CMMFDataBuffer* currentBuffer() const;
void pushData();
qint64 read(char *data, qint64 len);
void bufferEmptied();
Q_INVOKABLE void close();
qint64 getSamplesRecorded() const;
void setError(QAudio::Error error);
void setState(SymbianAudio::State state);
private:
const QByteArray m_device;
QAudioFormat m_format;
int m_clientBufferSize;
int m_notifyInterval;
QScopedPointer<QTimer> m_notifyTimer;
qint64 m_lastNotifyPosition;
QTime m_elapsed;
QAudio::Error m_error;
SymbianAudio::State m_internalState;
QAudio::State m_externalState;
bool m_pullMode;
QIODevice *m_sink;
QScopedPointer<QTimer> m_pullTimer;
SymbianAudio::DevSoundWrapper* m_devSound;
// Latest buffer provided by DevSound, to be empied of data.
CMMFDataBuffer *m_devSoundBuffer;
int m_devSoundBufferSize;
// Total amount of data in buffers provided by DevSound
int m_totalBytesReady;
// Queue of buffers returned after call to CMMFDevSound::Pause().
QList<CMMFDataBuffer *> m_devSoundBufferQ;
// Current read position within m_devSoundBuffer
qint64 m_devSoundBufferPos;
// Samples recorded up to the last call to suspend(). It is necessary
// to cache this because suspend() is implemented using
// CMMFDevSound::Stop(), which resets DevSound's SamplesRecorded() counter.
quint32 m_totalSamplesRecorded;
};
QT_END_NAMESPACE
#endif

View File

@@ -250,17 +250,10 @@ bool QAudioInputPrivate::open()
= (settings.frequency()
* settings.channelCount()
* settings.sampleSize()
#ifndef Q_OS_WINCE // Default buffer size, 200ms, default period size is 40ms
+ 39) / 40;
period_size = buffer_size / 5;
} else {
period_size = buffer_size / 5;
#else // For wince reduce size to 40ms for buffer size and 20ms period
+ 199) / 200;
period_size = buffer_size / 2;
} else {
period_size = buffer_size / 2;
#endif
}
if (period_size == 0) {

View File

@@ -1,713 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Mobility Components.
**
** $QT_BEGIN_LICENSE:LGPL$
** 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 "qaudiooutput_symbian_p.h"
QT_BEGIN_NAMESPACE
//-----------------------------------------------------------------------------
// Constants
//-----------------------------------------------------------------------------
const int UnderflowTimerInterval = 50; // ms
//-----------------------------------------------------------------------------
// Private class
//-----------------------------------------------------------------------------
SymbianAudioOutputPrivate::SymbianAudioOutputPrivate(
QAudioOutputPrivate *audioDevice)
: m_audioDevice(audioDevice)
{
}
SymbianAudioOutputPrivate::~SymbianAudioOutputPrivate()
{
}
qint64 SymbianAudioOutputPrivate::readData(char *data, qint64 len)
{
Q_UNUSED(data)
Q_UNUSED(len)
return 0;
}
qint64 SymbianAudioOutputPrivate::writeData(const char *data, qint64 len)
{
qint64 totalWritten = 0;
if (m_audioDevice->state() == QAudio::ActiveState ||
m_audioDevice->state() == QAudio::IdleState) {
while (totalWritten < len) {
const qint64 written = m_audioDevice->pushData(data + totalWritten,
len - totalWritten);
if (written > 0)
totalWritten += written;
else
break;
}
}
return totalWritten;
}
//-----------------------------------------------------------------------------
// Public functions
//-----------------------------------------------------------------------------
QAudioOutputPrivate::QAudioOutputPrivate(const QByteArray &device)
: m_device(device)
, m_clientBufferSize(SymbianAudio::DefaultBufferSize)
, m_notifyInterval(SymbianAudio::DefaultNotifyInterval)
, m_notifyTimer(new QTimer(this))
, m_lastNotifyPosition(0)
, m_error(QAudio::NoError)
, m_internalState(SymbianAudio::ClosedState)
, m_externalState(QAudio::StoppedState)
, m_pullMode(false)
, m_source(0)
, m_devSound(0)
, m_devSoundBuffer(0)
, m_devSoundBufferSize(0)
, m_bytesWritten(0)
, m_pushDataReady(false)
, m_bytesPadding(0)
, m_underflow(false)
, m_lastBuffer(false)
, m_underflowTimer(new QTimer(this))
, m_samplesPlayed(0)
, m_totalSamplesPlayed(0)
{
connect(m_notifyTimer.data(), SIGNAL(timeout()),
this, SLOT(notifyTimerExpired()));
m_underflowTimer->setInterval(UnderflowTimerInterval);
connect(m_underflowTimer.data(), SIGNAL(timeout()), this,
SLOT(underflowTimerExpired()));
}
QAudioOutputPrivate::~QAudioOutputPrivate()
{
close();
}
void QAudioOutputPrivate::setFormat(const QAudioFormat& fmt)
{
m_format = fmt;
}
void QAudioOutputPrivate::start(QIODevice *device)
{
stop();
// We have to set these before the call to open() because of the
// logic in initializingState()
m_pullMode = true;
m_source = device;
open();
if (SymbianAudio::ClosedState != m_internalState) {
connect(m_source, SIGNAL(readyRead()), this, SLOT(dataReady()));
m_elapsed.restart();
}
}
QIODevice* QAudioOutputPrivate::start()
{
stop();
open();
if (SymbianAudio::ClosedState != m_internalState) {
m_source = new SymbianAudioOutputPrivate(this);
m_source->open(QIODevice::WriteOnly | QIODevice::Unbuffered);
m_elapsed.restart();
}
return m_source;
}
void QAudioOutputPrivate::stop()
{
close();
}
void QAudioOutputPrivate::reset()
{
#ifndef PRE_S60_52_PLATFORM
int err = m_devSound->flush();
if (err != 0)
setError(QAudio::FatalError);
#else
m_totalSamplesPlayed += getSamplesPlayed();
m_devSound->stop();
m_bytesPadding = 0;
startPlayback();
#endif
}
void QAudioOutputPrivate::suspend()
{
if (SymbianAudio::ActiveState == m_internalState
|| SymbianAudio::IdleState == m_internalState) {
m_underflowTimer->stop();
const qint64 samplesWritten = SymbianAudio::Utils::bytesToSamples(
m_format, m_bytesWritten);
const qint64 samplesPlayed = getSamplesPlayed();
#ifdef PRE_S60_52_PLATFORM
m_totalSamplesPlayed += samplesPlayed;
m_bytesWritten = 0;
#endif
const bool paused = m_devSound->pause();
if (paused) {
setState(SymbianAudio::SuspendedPausedState);
} else {
m_devSoundBuffer = 0;
// Calculate the amount of data dropped
const qint64 paddingSamples = samplesWritten - samplesPlayed;
Q_ASSERT(paddingSamples >= 0);
m_bytesPadding = SymbianAudio::Utils::samplesToBytes(m_format,
paddingSamples);
setState(SymbianAudio::SuspendedStoppedState);
}
}
}
void QAudioOutputPrivate::resume()
{
if (QAudio::SuspendedState == m_externalState) {
if (SymbianAudio::SuspendedPausedState == m_internalState) {
#ifndef PRE_S60_52_PLATFORM
setState(SymbianAudio::ActiveState);
if (m_devSoundBuffer != 0)
devsoundBufferToBeFilled(m_devSoundBuffer);
m_devSound->start();
#else
//defined in else part of macro to enable compatibility of previous code
m_devSound->resume();
#endif
} else {
startPlayback();
}
}
}
int QAudioOutputPrivate::bytesFree() const
{
int result = 0;
if (m_devSoundBuffer) {
const TDes8 &outputBuffer = m_devSoundBuffer->Data();
result = outputBuffer.MaxLength() - outputBuffer.Length();
}
return result;
}
int QAudioOutputPrivate::periodSize() const
{
return bufferSize();
}
void QAudioOutputPrivate::setBufferSize(int value)
{
// Note that DevSound does not allow its client to specify the buffer size.
// This functionality is available via custom interfaces, but since these
// cannot be guaranteed to work across all DevSound implementations, we
// do not use them here.
// In order to comply with the expected bevahiour of QAudioOutput, we store
// the value and return it from bufferSize(), but the underlying DevSound
// buffer size remains unchanged.
if (value > 0)
m_clientBufferSize = value;
}
int QAudioOutputPrivate::bufferSize() const
{
return m_devSoundBufferSize ? m_devSoundBufferSize : m_clientBufferSize;
}
void QAudioOutputPrivate::setNotifyInterval(int ms)
{
if (ms >= 0) {
//const int oldNotifyInterval = m_notifyInterval;
m_notifyInterval = ms;
if (m_notifyInterval && (SymbianAudio::ActiveState == m_internalState ||
SymbianAudio::IdleState == m_internalState))
m_notifyTimer->start(m_notifyInterval);
else
m_notifyTimer->stop();
}
}
int QAudioOutputPrivate::notifyInterval() const
{
return m_notifyInterval;
}
qint64 QAudioOutputPrivate::processedUSecs() const
{
int samplesPlayed = 0;
if (!m_devSound)
return samplesPlayed;
if (QAudio::SuspendedState != m_externalState)
samplesPlayed = getSamplesPlayed();
// Protect against division by zero
Q_ASSERT_X(m_format.frequency() > 0, Q_FUNC_INFO, "Invalid frequency");
#ifndef PRE_S60_52_PLATFORM
const qint64 devSoundSamplesPlayed(m_devSound->samplesProcessed());
const qint64 result = qint64(1000000) *
(devSoundSamplesPlayed)
/ m_format.frequency();
#else
const qint64 result = qint64(1000000) *
(samplesPlayed + m_totalSamplesPlayed)
/ m_format.frequency();
#endif
return result;
}
qint64 QAudioOutputPrivate::elapsedUSecs() const
{
const qint64 result = (QAudio::StoppedState == state()) ?
0 : m_elapsed.elapsed() * 1000;
return result;
}
QAudio::Error QAudioOutputPrivate::error() const
{
return m_error;
}
QAudio::State QAudioOutputPrivate::state() const
{
return m_externalState;
}
QAudioFormat QAudioOutputPrivate::format() const
{
return m_format;
}
//-----------------------------------------------------------------------------
// Private functions
//-----------------------------------------------------------------------------
void QAudioOutputPrivate::notifyTimerExpired()
{
const qint64 pos = processedUSecs();
if (pos > m_lastNotifyPosition) {
int count = (pos - m_lastNotifyPosition) / (m_notifyInterval * 1000);
while (count--) {
emit notify();
m_lastNotifyPosition += m_notifyInterval * 1000;
}
}
}
void QAudioOutputPrivate::dataReady()
{
// Client-provided QIODevice has data ready to read.
Q_ASSERT_X(m_source->bytesAvailable(), Q_FUNC_INFO,
"readyRead signal received, but no data available");
if (!m_bytesPadding)
pullData();
}
void QAudioOutputPrivate::underflowTimerExpired()
{
const TInt samplesPlayed = getSamplesPlayed();
if (m_samplesPlayed && (samplesPlayed == m_samplesPlayed)) {
setError(QAudio::UnderrunError);
#ifndef PRE_S60_52_PLATFORM
m_underflowTimer->stop();
#endif
} else {
m_samplesPlayed = samplesPlayed;
m_underflowTimer->start();
}
}
void QAudioOutputPrivate::devsoundInitializeComplete(int err)
{
Q_ASSERT_X(SymbianAudio::InitializingState == m_internalState,
Q_FUNC_INFO, "Invalid state");
if (!err && m_devSound->isFormatSupported(m_format))
startPlayback();
else
setError(QAudio::OpenError);
}
void QAudioOutputPrivate::devsoundBufferToBeFilled(CMMFBuffer *bufferBase)
{
// Following receipt of this signal, DevSound should not provide another
// buffer until we have returned the current one.
Q_ASSERT_X(!m_devSoundBuffer, Q_FUNC_INFO, "Buffer already held");
// Will be returned to DevSoundWrapper by bufferProcessed().
m_devSoundBuffer = static_cast<CMMFDataBuffer*>(bufferBase);
#ifndef PRE_S60_52_PLATFORM
if (m_externalState == QAudio::SuspendedState) {
// This condition occurs when buffertobefilled callback is received after
// pause command is processed.
return;
}
#endif
if (!m_devSoundBufferSize)
m_devSoundBufferSize = m_devSoundBuffer->Data().MaxLength();
writePaddingData();
if (m_pullMode && isDataReady() && !m_bytesPadding)
pullData();
}
void QAudioOutputPrivate::devsoundPlayError(int err)
{
switch (err) {
case KErrUnderflow:
m_underflow = true;
if (m_pullMode && !m_lastBuffer)
setError(QAudio::UnderrunError);
else
setState(SymbianAudio::IdleState);
break;
case KErrOverflow:
// Silently consume this error when in playback mode
break;
default:
setError(QAudio::IOError);
break;
}
}
void QAudioOutputPrivate::open()
{
Q_ASSERT_X(SymbianAudio::ClosedState == m_internalState,
Q_FUNC_INFO, "DevSound already opened");
Q_ASSERT(!m_devSound);
m_devSound = new SymbianAudio::DevSoundWrapper(QAudio::AudioOutput, this);
connect(m_devSound, SIGNAL(initializeComplete(int)),
this, SLOT(devsoundInitializeComplete(int)));
connect(m_devSound, SIGNAL(bufferToBeProcessed(CMMFBuffer *)),
this, SLOT(devsoundBufferToBeFilled(CMMFBuffer *)));
connect(m_devSound, SIGNAL(processingError(int)),
this, SLOT(devsoundPlayError(int)));
setState(SymbianAudio::InitializingState);
m_devSound->initialize(m_format.codec());
}
void QAudioOutputPrivate::startPlayback()
{
bool ok = m_devSound->setFormat(m_format);
if (ok)
ok = m_devSound->start();
if (ok) {
if (isDataReady())
setState(SymbianAudio::ActiveState);
else
setState(SymbianAudio::IdleState);
if (m_notifyInterval)
m_notifyTimer->start(m_notifyInterval);
m_underflow = false;
Q_ASSERT(m_devSound->samplesProcessed() == 0);
writePaddingData();
if (m_pullMode && m_source->bytesAvailable() && !m_bytesPadding)
dataReady();
} else {
setError(QAudio::OpenError);
close();
}
}
void QAudioOutputPrivate::writePaddingData()
{
// See comments in suspend()
while (m_devSoundBuffer && m_bytesPadding) {
if (SymbianAudio::IdleState == m_internalState)
setState(SymbianAudio::ActiveState);
TDes8 &outputBuffer = m_devSoundBuffer->Data();
const qint64 outputBytes = bytesFree();
const qint64 paddingBytes = outputBytes < m_bytesPadding ?
outputBytes : m_bytesPadding;
unsigned char *ptr = const_cast<unsigned char*>(outputBuffer.Ptr());
Mem::FillZ(ptr, paddingBytes);
outputBuffer.SetLength(outputBuffer.Length() + paddingBytes);
m_bytesPadding -= paddingBytes;
Q_ASSERT(m_bytesPadding >= 0);
if (m_pullMode && m_source->atEnd())
lastBufferFilled();
if ((paddingBytes == outputBytes) || !m_bytesPadding)
bufferFilled();
}
}
qint64 QAudioOutputPrivate::pushData(const char *data, qint64 len)
{
// Data has been written to SymbianAudioOutputPrivate
Q_ASSERT_X(!m_pullMode, Q_FUNC_INFO,
"pushData called when in pull mode");
const unsigned char *const inputPtr =
reinterpret_cast<const unsigned char*>(data);
qint64 bytesWritten = 0;
if (SymbianAudio::IdleState == m_internalState)
setState(SymbianAudio::ActiveState);
while (m_devSoundBuffer && (bytesWritten < len)) {
// writePaddingData() is called from BufferToBeFilled(), so we should
// never have any padding data left at this point.
Q_ASSERT_X(0 == m_bytesPadding, Q_FUNC_INFO,
"Padding bytes remaining in pushData");
TDes8 &outputBuffer = m_devSoundBuffer->Data();
const qint64 outputBytes = bytesFree();
const qint64 inputBytes = len - bytesWritten;
const qint64 copyBytes = outputBytes < inputBytes ?
outputBytes : inputBytes;
outputBuffer.Append(inputPtr + bytesWritten, copyBytes);
bytesWritten += copyBytes;
bufferFilled();
}
m_pushDataReady = (bytesWritten < len);
// If DevSound is still initializing (m_internalState == InitializingState),
// we cannot transition m_internalState to ActiveState, but we must emit
// an (external) state change from IdleState to ActiveState. The following
// call triggers this signal.
setState(m_internalState);
return bytesWritten;
}
void QAudioOutputPrivate::pullData()
{
Q_ASSERT_X(m_pullMode, Q_FUNC_INFO,
"pullData called when in push mode");
// writePaddingData() is called by BufferToBeFilled() before pullData(),
// so we should never have any padding data left at this point.
Q_ASSERT_X(0 == m_bytesPadding, Q_FUNC_INFO,
"Padding bytes remaining in pullData");
qint64 inputBytes = m_source->bytesAvailable();
while (m_devSoundBuffer && inputBytes) {
if (SymbianAudio::IdleState == m_internalState)
setState(SymbianAudio::ActiveState);
TDes8 &outputBuffer = m_devSoundBuffer->Data();
const qint64 outputBytes = bytesFree();
const qint64 copyBytes = outputBytes < inputBytes ?
outputBytes : inputBytes;
char *outputPtr = (char*)(outputBuffer.Ptr() + outputBuffer.Length());
const qint64 bytesCopied = m_source->read(outputPtr, copyBytes);
//Partial buffers can be sent to DevSound. This assert not required.
//Q_ASSERT(bytesCopied == copyBytes);
outputBuffer.SetLength(outputBuffer.Length() + bytesCopied);
inputBytes -= bytesCopied;
if(bytesCopied == 0)
return;
if (m_source->atEnd())
lastBufferFilled();
else
bufferFilled();
}
}
void QAudioOutputPrivate::bufferFilled()
{
Q_ASSERT_X(m_devSoundBuffer, Q_FUNC_INFO, "No buffer to return");
const TDes8 &outputBuffer = m_devSoundBuffer->Data();
m_bytesWritten += outputBuffer.Length();
m_devSoundBuffer = 0;
m_samplesPlayed = getSamplesPlayed();
m_underflowTimer->start();
if (QAudio::UnderrunError == m_error)
m_error = QAudio::NoError;
m_devSound->bufferProcessed();
}
void QAudioOutputPrivate::lastBufferFilled()
{
Q_ASSERT_X(m_devSoundBuffer, Q_FUNC_INFO, "No buffer to fill");
Q_ASSERT_X(!m_lastBuffer, Q_FUNC_INFO, "Last buffer already sent");
m_lastBuffer = true;
m_devSoundBuffer->SetLastBuffer(ETrue);
bufferFilled();
}
void QAudioOutputPrivate::close()
{
m_lastNotifyPosition = 0;
m_underflowTimer->stop();
m_error = QAudio::NoError;
if (m_devSound)
m_devSound->stop();
delete m_devSound;
m_devSound = 0;
m_devSoundBuffer = 0;
m_devSoundBufferSize = 0;
if (!m_pullMode) // m_source is owned
delete m_source;
m_pullMode = false;
m_source = 0;
m_bytesWritten = 0;
m_pushDataReady = false;
m_bytesPadding = 0;
m_underflow = false;
m_lastBuffer = false;
m_samplesPlayed = 0;
m_totalSamplesPlayed = 0;
setState(SymbianAudio::ClosedState);
}
qint64 QAudioOutputPrivate::getSamplesPlayed() const
{
qint64 result = 0;
if (m_devSound) {
const qint64 samplesWritten = SymbianAudio::Utils::bytesToSamples(
m_format, m_bytesWritten);
if (m_underflow) {
result = samplesWritten;
} else {
// This is necessary because some DevSound implementations report
// that they have played more data than has actually been provided to them
// by the client.
const qint64 devSoundSamplesPlayed(m_devSound->samplesProcessed());
result = qMin(devSoundSamplesPlayed, samplesWritten);
}
}
return result;
}
void QAudioOutputPrivate::setError(QAudio::Error error)
{
m_error = error;
// Although no state transition actually occurs here, a stateChanged event
// must be emitted to inform the client that the call to start() was
// unsuccessful.
if (QAudio::OpenError == error) {
emit stateChanged(QAudio::StoppedState);
} else {
if (QAudio::UnderrunError == error)
setState(SymbianAudio::IdleState);
else
// Close the DevSound instance. This causes a transition to
// StoppedState. This must be done asynchronously in case the
// current function was called from a DevSound event handler, in which
// case deleting the DevSound instance may cause an exception.
QMetaObject::invokeMethod(this, "close", Qt::QueuedConnection);
}
}
void QAudioOutputPrivate::setState(SymbianAudio::State newInternalState)
{
const QAudio::State oldExternalState = m_externalState;
m_internalState = newInternalState;
m_externalState = SymbianAudio::Utils::stateNativeToQt(m_internalState);
if (m_externalState != QAudio::ActiveState &&
m_externalState != QAudio::IdleState)
m_notifyTimer->stop();
if (m_externalState != oldExternalState)
emit stateChanged(m_externalState);
}
bool QAudioOutputPrivate::isDataReady() const
{
return (m_source && m_source->bytesAvailable())
|| m_bytesPadding
|| m_pushDataReady;
}
QT_END_NAMESPACE
#include "moc_qaudiooutput_symbian_p.cpp"

View File

@@ -1,201 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Mobility Components.
**
** $QT_BEGIN_LICENSE:LGPL$
** 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_SYMBIAN_P_H
#define QAUDIOOUTPUT_SYMBIAN_P_H
#include <qaudiosystem.h>
#include <QTime>
#include <QTimer>
#include <sounddevice.h>
#include "qaudio_symbian_p.h"
QT_BEGIN_NAMESPACE
class QAudioOutputPrivate;
class SymbianAudioOutputPrivate : public QIODevice
{
friend class QAudioOutputPrivate;
Q_OBJECT
public:
SymbianAudioOutputPrivate(QAudioOutputPrivate *audio);
~SymbianAudioOutputPrivate();
qint64 readData(char *data, qint64 len);
qint64 writeData(const char *data, qint64 len);
private:
QAudioOutputPrivate *const m_audioDevice;
};
class QAudioOutputPrivate
: public QAbstractAudioOutput
{
friend class SymbianAudioOutputPrivate;
Q_OBJECT
public:
QAudioOutputPrivate(const QByteArray &device);
~QAudioOutputPrivate();
// QAbstractAudioOutput
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;
QAudioFormat format() const;
void setFormat(const QAudioFormat& fmt);
private slots:
void dataReady();
void notifyTimerExpired();
void underflowTimerExpired();
void devsoundInitializeComplete(int err);
void devsoundBufferToBeFilled(CMMFBuffer *);
void devsoundPlayError(int err);
private:
void open();
void startPlayback();
void writePaddingData();
qint64 pushData(const char *data, qint64 len);
void pullData();
void bufferFilled();
void lastBufferFilled();
Q_INVOKABLE void close();
qint64 getSamplesPlayed() const;
void setError(QAudio::Error error);
void setState(SymbianAudio::State state);
bool isDataReady() const;
private:
const QByteArray m_device;
QAudioFormat m_format;
int m_clientBufferSize;
int m_notifyInterval;
QScopedPointer<QTimer> m_notifyTimer;
qint64 m_lastNotifyPosition;
QTime m_elapsed;
QAudio::Error m_error;
SymbianAudio::State m_internalState;
QAudio::State m_externalState;
bool m_pullMode;
QIODevice *m_source;
SymbianAudio::DevSoundWrapper* m_devSound;
// Buffer provided by DevSound, to be filled with data.
CMMFDataBuffer *m_devSoundBuffer;
int m_devSoundBufferSize;
// Number of bytes transferred from QIODevice to QAudioOutput. It is
// necessary to count this because data is dropped when suspend() is
// called. The difference between the position reported by DevSound and
// this value allows us to calculate m_bytesPadding;
quint32 m_bytesWritten;
// True if client has provided data while the audio subsystem was not
// ready to consume it.
bool m_pushDataReady;
// Number of zero bytes which will be written when client calls resume().
quint32 m_bytesPadding;
// True if PlayError(KErrUnderflow) has been called.
bool m_underflow;
// True if a buffer marked with the "last buffer" flag has been provided
// to DevSound.
bool m_lastBuffer;
// Some DevSound implementations ignore all underflow errors raised by the
// audio driver, unless the last buffer flag has been set by the client.
// In push-mode playback, this flag will never be set, so the underflow
// error will never be reported. In order to work around this, a timer
// is used, which gets reset every time the client provides more data. If
// the timer expires, an underflow error is raised by this object.
QScopedPointer<QTimer> m_underflowTimer;
// Result of previous call to CMMFDevSound::SamplesPlayed(). This value is
// used to determine whether, when m_underflowTimer expires, an
// underflow error has actually occurred.
quint32 m_samplesPlayed;
// Samples played up to the last call to suspend(). It is necessary
// to cache this because suspend() is implemented using
// CMMFDevSound::Stop(), which resets DevSound's SamplesPlayed() counter.
quint32 m_totalSamplesPlayed;
};
QT_END_NAMESPACE
#endif

View File

@@ -1,6 +1,6 @@
INCLUDEPATH += effects
unix:!mac:!symbian {
unix:!mac {
contains(pulseaudio_enabled, yes) {
CONFIG += link_pkgconfig
PKGCONFIG += libpulse

View File

@@ -86,7 +86,7 @@ QT_BEGIN_NAMESPACE
\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 and Symbian.
Note: Currently this has no effect on Mac OS X.
*/
/*!

View File

@@ -8,7 +8,7 @@ QT = core network gui
CONFIG += module
MODULE_PRI += ../../modules/qt_multimediakit.pri
contains(QT_CONFIG, opengl) | contains(QT_CONFIG, opengles2): !symbian {
contains(QT_CONFIG, opengl) | contains(QT_CONFIG, opengles2) {
QT += opengl
} else {
DEFINES += QT_NO_OPENGL
@@ -167,14 +167,6 @@ mac {
LIBS += -framework AppKit -framework QuartzCore -framework QTKit
}
maemo5 {
isEqual(QT_ARCH,armv6):QMAKE_CXXFLAGS += -march=armv7a -mcpu=cortex-a8 -mfloat-abi=softfp -mfpu=neon
HEADERS += qxvideosurface_maemo5_p.h
SOURCES += qxvideosurface_maemo5.cpp
SOURCES += qgraphicsvideoitem_maemo5.cpp
LIBS += -lXv -lX11 -lXext
}
maemo6 {
isEqual(QT_ARCH,armv6) {
HEADERS += qeglimagetexturesurface_p.h
@@ -188,30 +180,9 @@ maemo6 {
}
}
symbian {
contains(surfaces_s60_enabled, yes) {
SOURCES += qgraphicsvideoitem_symbian.cpp
} else {
SOURCES += qgraphicsvideoitem_overlay.cpp
}
}
!maemo*:!symbian {
!maemo* {
SOURCES += qgraphicsvideoitem.cpp
}
HEADERS += $$PUBLIC_HEADERS $$PRIVATE_HEADERS
symbian {
contains(S60_VERSION, 5.1) |contains (S60_VERSION, 3.2) | contains(S60_VERSION, 3.1): DEFINES += PRE_S60_52_PLATFORM
load(data_caging_paths)
QtMediaDeployment.sources = QtMultimediaKit.dll
QtMediaDeployment.path = /sys/bin
DEPLOYMENT += QtMediaDeployment
TARGET.UID3=0x2002AC77
TARGET.CAPABILITY = ALL -TCB
LIBS += -lefsrv
}
# CONFIG += middleware
# include(../../features/deploy.pri)

View File

@@ -1,647 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Mobility Components.
**
** $QT_BEGIN_LICENSE:LGPL$
** 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/qpointer.h>
#include <QtCore/qdatetime.h>
#include <QtCore/qbasictimer.h>
#include <QtCore/qcoreevent.h>
#include <QtGui/qgraphicsscene.h>
#include <QtGui/qgraphicsview.h>
#include <QtGui/qscrollbar.h>
#include <QtGui/qx11info_x11.h>
#include "qgraphicsvideoitem.h"
#include <qmediaobject.h>
#include <qmediaservice.h>
#include <qpaintervideosurface_p.h>
#include <qvideorenderercontrol.h>
#include <qvideosurfaceformat.h>
#include "qxvideosurface_maemo5_p.h"
QT_BEGIN_NAMESPACE
//#define DEBUG_GFX_VIDEO_ITEM
//update overlay geometry slightly later,
//to ensure color key is alredy replaced with static frame
#define GEOMETRY_UPDATE_DELAY 20
//this is necessary to prevent flickering, see maemo bug 8798
//on geometry changes, the color key is replaced with static image frame
//until the overlay is re-initialized
#define SOFTWARE_RENDERING_DURATION 150
#ifdef __ARM_NEON__
/*
* ARM NEON optimized implementation of UYVY -> RGB16 convertor
*/
static void uyvy422_to_rgb16_line_neon (uint8_t * dst, const uint8_t * src, int n)
{
/* and this is the NEON code itself */
static __attribute__ ((aligned (16))) uint16_t acc_r[8] = {
22840, 22840, 22840, 22840, 22840, 22840, 22840, 22840,
};
static __attribute__ ((aligned (16))) uint16_t acc_g[8] = {
17312, 17312, 17312, 17312, 17312, 17312, 17312, 17312,
};
static __attribute__ ((aligned (16))) uint16_t acc_b[8] = {
28832, 28832, 28832, 28832, 28832, 28832, 28832, 28832,
};
/*
* Registers:
* q0, q1 : d0, d1, d2, d3 - are used for initial loading of YUV data
* q2 : d4, d5 - are used for storing converted RGB data
* q3 : d6, d7 - are used for temporary storage
*
* q6 : d12, d13 - are used for converting to RGB16
* q7 : d14, d15 - are used for storing RGB16 data
* q4-q5 - reserved
*
* q8, q9 : d16, d17, d18, d19 - are used for expanded Y data
* q10 : d20, d21
* q11 : d22, d23
* q12 : d24, d25
* q13 : d26, d27
* q13, q14, q15 - various constants (#16, #149, #204, #50, #104, #154)
*/
asm volatile (".macro convert_macroblock size\n"
/* load up to 16 source pixels in UYVY format */
".if \\size == 16\n"
"pld [%[src], #128]\n"
"vld1.32 {d0, d1, d2, d3}, [%[src]]!\n"
".elseif \\size == 8\n"
"vld1.32 {d0, d1}, [%[src]]!\n"
".elseif \\size == 4\n"
"vld1.32 {d0}, [%[src]]!\n"
".elseif \\size == 2\n"
"vld1.32 {d0[0]}, [%[src]]!\n"
".else\n" ".error \"unsupported macroblock size\"\n" ".endif\n"
/* convert from 'packed' to 'planar' representation */
"vuzp.8 d0, d1\n" /* d1 - separated Y data (first 8 bytes) */
"vuzp.8 d2, d3\n" /* d3 - separated Y data (next 8 bytes) */
"vuzp.8 d0, d2\n" /* d0 - separated U data, d2 - separated V data */
/* split even and odd Y color components */
"vuzp.8 d1, d3\n" /* d1 - evenY, d3 - oddY */
/* clip upper and lower boundaries */
"vqadd.u8 q0, q0, q4\n"
"vqadd.u8 q1, q1, q4\n"
"vqsub.u8 q0, q0, q5\n"
"vqsub.u8 q1, q1, q5\n"
"vshr.u8 d4, d2, #1\n" /* d4 = V >> 1 */
"vmull.u8 q8, d1, d27\n" /* q8 = evenY * 149 */
"vmull.u8 q9, d3, d27\n" /* q9 = oddY * 149 */
"vld1.16 {d20, d21}, [%[acc_r], :128]\n" /* q10 - initialize accumulator for red */
"vsubw.u8 q10, q10, d4\n" /* red acc -= (V >> 1) */
"vmlsl.u8 q10, d2, d28\n" /* red acc -= V * 204 */
"vld1.16 {d22, d23}, [%[acc_g], :128]\n" /* q11 - initialize accumulator for green */
"vmlsl.u8 q11, d2, d30\n" /* green acc -= V * 104 */
"vmlsl.u8 q11, d0, d29\n" /* green acc -= U * 50 */
"vld1.16 {d24, d25}, [%[acc_b], :128]\n" /* q12 - initialize accumulator for blue */
"vmlsl.u8 q12, d0, d30\n" /* blue acc -= U * 104 */
"vmlsl.u8 q12, d0, d31\n" /* blue acc -= U * 154 */
"vhsub.s16 q3, q8, q10\n" /* calculate even red components */
"vhsub.s16 q10, q9, q10\n" /* calculate odd red components */
"vqshrun.s16 d0, q3, #6\n" /* right shift, narrow and saturate even red components */
"vqshrun.s16 d3, q10, #6\n" /* right shift, narrow and saturate odd red components */
"vhadd.s16 q3, q8, q11\n" /* calculate even green components */
"vhadd.s16 q11, q9, q11\n" /* calculate odd green components */
"vqshrun.s16 d1, q3, #6\n" /* right shift, narrow and saturate even green components */
"vqshrun.s16 d4, q11, #6\n" /* right shift, narrow and saturate odd green components */
"vhsub.s16 q3, q8, q12\n" /* calculate even blue components */
"vhsub.s16 q12, q9, q12\n" /* calculate odd blue components */
"vqshrun.s16 d2, q3, #6\n" /* right shift, narrow and saturate even blue components */
"vqshrun.s16 d5, q12, #6\n" /* right shift, narrow and saturate odd blue components */
"vzip.8 d0, d3\n" /* join even and odd red components */
"vzip.8 d1, d4\n" /* join even and odd green components */
"vzip.8 d2, d5\n" /* join even and odd blue components */
"vshll.u8 q7, d0, #8\n" //red
"vshll.u8 q6, d1, #8\n" //greed
"vsri.u16 q7, q6, #5\n"
"vshll.u8 q6, d2, #8\n" //blue
"vsri.u16 q7, q6, #11\n" //now there is rgb16 in q7
".if \\size == 16\n"
"vst1.16 {d14, d15}, [%[dst]]!\n"
//"vst3.8 {d0, d1, d2}, [%[dst]]!\n"
"vshll.u8 q7, d3, #8\n" //red
"vshll.u8 q6, d4, #8\n" //greed
"vsri.u16 q7, q6, #5\n"
"vshll.u8 q6, d5, #8\n" //blue
"vsri.u16 q7, q6, #11\n" //now there is rgb16 in q7
//"vst3.8 {d3, d4, d5}, [%[dst]]!\n"
"vst1.16 {d14, d15}, [%[dst]]!\n"
".elseif \\size == 8\n"
"vst1.16 {d14, d15}, [%[dst]]!\n"
//"vst3.8 {d0, d1, d2}, [%[dst]]!\n"
".elseif \\size == 4\n"
"vst1.8 {d14}, [%[dst]]!\n"
".elseif \\size == 2\n"
"vst1.8 {d14[0]}, [%[dst]]!\n"
"vst1.8 {d14[1]}, [%[dst]]!\n"
".else\n"
".error \"unsupported macroblock size\"\n"
".endif\n"
".endm\n"
"vmov.u8 d8, #15\n" /* add this to U/V to saturate upper boundary */
"vmov.u8 d9, #20\n" /* add this to Y to saturate upper boundary */
"vmov.u8 d10, #31\n" /* sub this from U/V to saturate lower boundary */
"vmov.u8 d11, #36\n" /* sub this from Y to saturate lower boundary */
"vmov.u8 d26, #16\n"
"vmov.u8 d27, #149\n"
"vmov.u8 d28, #204\n"
"vmov.u8 d29, #50\n"
"vmov.u8 d30, #104\n"
"vmov.u8 d31, #154\n"
"subs %[n], %[n], #16\n"
"blt 2f\n"
"1:\n"
"convert_macroblock 16\n"
"subs %[n], %[n], #16\n"
"bge 1b\n"
"2:\n"
"tst %[n], #8\n"
"beq 3f\n"
"convert_macroblock 8\n"
"3:\n"
"tst %[n], #4\n"
"beq 4f\n"
"convert_macroblock 4\n"
"4:\n"
"tst %[n], #2\n"
"beq 5f\n"
"convert_macroblock 2\n"
"5:\n"
".purgem convert_macroblock\n":[src] "+&r" (src),[dst] "+&r" (dst),
[n] "+&r" (n)
:[acc_r] "r" (&acc_r[0]),[acc_g] "r" (&acc_g[0]),[acc_b] "r" (&acc_b[0])
:"cc", "memory", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10", "d11", "d12", "d13", "d14", "d15",
"d16", "d17", "d18", "d19", "d20", "d21", "d22", "d23",
"d24", "d25", "d26", "d27", "d28", "d29", "d30", "d31");
}
#endif
class QGraphicsVideoItemPrivate
{
public:
QGraphicsVideoItemPrivate()
: q_ptr(0)
, surface(0)
, mediaObject(0)
, service(0)
, rendererControl(0)
, savedViewportUpdateMode(QGraphicsView::FullViewportUpdate)
, aspectRatioMode(Qt::KeepAspectRatio)
, rect(0.0, 0.0, 320, 240)
, softwareRenderingEnabled(false)
{
}
QGraphicsVideoItem *q_ptr;
QXVideoSurface *surface;
QMediaObject *mediaObject;
QMediaService *service;
QVideoRendererControl *rendererControl;
QPointer<QGraphicsView> currentView;
QGraphicsView::ViewportUpdateMode savedViewportUpdateMode;
Qt::AspectRatioMode aspectRatioMode;
QRectF rect;
QRectF boundingRect;
QRectF sourceRect;
QSizeF nativeSize;
QPixmap lastFrame;
QBasicTimer softwareRenderingTimer;
QBasicTimer geometryUpdateTimer;
bool softwareRenderingEnabled;
QRect overlayRect;
void clearService();
void updateRects();
void updateLastFrame();
void _q_present();
void _q_updateNativeSize();
void _q_serviceDestroyed();
void _q_mediaObjectDestroyed();
};
void QGraphicsVideoItemPrivate::clearService()
{
if (rendererControl) {
surface->stop();
rendererControl->setSurface(0);
service->releaseControl(rendererControl);
rendererControl = 0;
}
if (service) {
QObject::disconnect(service, SIGNAL(destroyed()), q_ptr, SLOT(_q_serviceDestroyed()));
service = 0;
}
}
void QGraphicsVideoItemPrivate::updateRects()
{
q_ptr->prepareGeometryChange();
if (nativeSize.isEmpty()) {
boundingRect = QRectF();
} else if (aspectRatioMode == Qt::IgnoreAspectRatio) {
boundingRect = rect;
sourceRect = QRectF(0, 0, 1, 1);
} else if (aspectRatioMode == Qt::KeepAspectRatio) {
QSizeF size = nativeSize;
size.scale(rect.size(), Qt::KeepAspectRatio);
boundingRect = QRectF(0, 0, size.width(), size.height());
boundingRect.moveCenter(rect.center());
sourceRect = QRectF(0, 0, 1, 1);
} else if (aspectRatioMode == Qt::KeepAspectRatioByExpanding) {
boundingRect = rect;
QSizeF size = rect.size();
size.scale(nativeSize, Qt::KeepAspectRatio);
sourceRect = QRectF(
0, 0, size.width() / nativeSize.width(), size.height() / nativeSize.height());
sourceRect.moveCenter(QPointF(0.5, 0.5));
}
}
void QGraphicsVideoItemPrivate::updateLastFrame()
{
lastFrame = QPixmap();
if (!softwareRenderingEnabled)
return;
QVideoFrame lastVideoFrame = surface->lastFrame();
if (!lastVideoFrame.isValid())
return;
if (lastVideoFrame.map(QAbstractVideoBuffer::ReadOnly)) {
#ifdef __ARM_NEON__
if (lastVideoFrame.pixelFormat() == QVideoFrame::Format_UYVY) {
QImage lastImage(lastVideoFrame.size(), QImage::Format_RGB16);
const uchar *src = lastVideoFrame.bits();
uchar *dst = lastImage.bits();
const int srcLineStep = lastVideoFrame.bytesPerLine();
const int dstLineStep = lastImage.bytesPerLine();
const int h = lastVideoFrame.height();
const int w = lastVideoFrame.width();
for (int y=0; y<h; y++) {
uyvy422_to_rgb16_line_neon(dst, src, w);
src += srcLineStep;
dst += dstLineStep;
}
lastFrame = QPixmap::fromImage(
lastImage.scaled(boundingRect.size().toSize(), Qt::IgnoreAspectRatio, Qt::FastTransformation));
} else
#endif
{
QImage::Format imgFormat = QVideoFrame::imageFormatFromPixelFormat(lastVideoFrame.pixelFormat());
if (imgFormat != QImage::Format_Invalid) {
QImage lastImage(lastVideoFrame.bits(),
lastVideoFrame.width(),
lastVideoFrame.height(),
lastVideoFrame.bytesPerLine(),
imgFormat);
lastFrame = QPixmap::fromImage(
lastImage.scaled(boundingRect.size().toSize(), Qt::IgnoreAspectRatio, Qt::FastTransformation));
}
}
lastVideoFrame.unmap();
}
}
void QGraphicsVideoItemPrivate::_q_present()
{
q_ptr->update(boundingRect);
}
void QGraphicsVideoItemPrivate::_q_updateNativeSize()
{
const QSize &size = surface->surfaceFormat().sizeHint();
if (nativeSize != size) {
lastFrame = QPixmap();
nativeSize = size;
updateRects();
emit q_ptr->nativeSizeChanged(nativeSize);
}
}
void QGraphicsVideoItemPrivate::_q_serviceDestroyed()
{
rendererControl = 0;
service = 0;
surface->stop();
}
void QGraphicsVideoItemPrivate::_q_mediaObjectDestroyed()
{
mediaObject = 0;
clearService();
}
QGraphicsVideoItem::QGraphicsVideoItem(QGraphicsItem *parent)
: QGraphicsObject(parent)
, d_ptr(new QGraphicsVideoItemPrivate)
{
d_ptr->q_ptr = this;
d_ptr->surface = new QXVideoSurface;
setCacheMode(NoCache);
setFlag(QGraphicsItem::ItemIgnoresParentOpacity);
setFlag(QGraphicsItem::ItemSendsGeometryChanges);
setFlag(QGraphicsItem::ItemSendsScenePositionChanges);
connect(d_ptr->surface, SIGNAL(surfaceFormatChanged(QVideoSurfaceFormat)),
this, SLOT(_q_updateNativeSize()));
connect(d_ptr->surface, SIGNAL(activeChanged(bool)), this, SLOT(_q_present()));
}
QGraphicsVideoItem::~QGraphicsVideoItem()
{
if (d_ptr->rendererControl) {
d_ptr->rendererControl->setSurface(0);
d_ptr->service->releaseControl(d_ptr->rendererControl);
}
if (d_ptr->currentView)
d_ptr->currentView->setViewportUpdateMode(d_ptr->savedViewportUpdateMode);
delete d_ptr->surface;
delete d_ptr;
}
QMediaObject *QGraphicsVideoItem::mediaObject() const
{
return d_func()->mediaObject;
}
bool QGraphicsVideoItem::setMediaObject(QMediaObject *object)
{
Q_D(QGraphicsVideoItem);
if (object == d->mediaObject)
return true;
d->clearService();
d->mediaObject = object;
if (d->mediaObject) {
d->service = d->mediaObject->service();
if (d->service) {
d->rendererControl = qobject_cast<QVideoRendererControl *>(
d->service->requestControl(QVideoRendererControl_iid));
if (d->rendererControl != 0) {
connect(d->service, SIGNAL(destroyed()), this, SLOT(_q_serviceDestroyed()));
d->rendererControl->setSurface(d->surface);
return true;
}
}
}
return false;
}
Qt::AspectRatioMode QGraphicsVideoItem::aspectRatioMode() const
{
return d_func()->aspectRatioMode;
}
void QGraphicsVideoItem::setAspectRatioMode(Qt::AspectRatioMode mode)
{
Q_D(QGraphicsVideoItem);
d->aspectRatioMode = mode;
d->updateRects();
}
QPointF QGraphicsVideoItem::offset() const
{
return d_func()->rect.topLeft();
}
void QGraphicsVideoItem::setOffset(const QPointF &offset)
{
Q_D(QGraphicsVideoItem);
d->rect.moveTo(offset);
d->updateRects();
}
QSizeF QGraphicsVideoItem::size() const
{
return d_func()->rect.size();
}
void QGraphicsVideoItem::setSize(const QSizeF &size)
{
Q_D(QGraphicsVideoItem);
d->rect.setSize(size.isValid() ? size : QSizeF(0, 0));
d->updateRects();
}
QSizeF QGraphicsVideoItem::nativeSize() const
{
return d_func()->nativeSize;
}
QRectF QGraphicsVideoItem::boundingRect() const
{
return d_func()->boundingRect;
}
void QGraphicsVideoItem::paint(
QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
#ifdef DEBUG_GFX_VIDEO_ITEM
qDebug() << "QGraphicsVideoItem::paint";
#endif
Q_UNUSED(option);
Q_D(QGraphicsVideoItem);
QGraphicsView *view = 0;
if (scene() && !scene()->views().isEmpty())
view = scene()->views().first();
//it's necessary to switch vieport update mode to FullViewportUpdate
//otherwise the video item area can be just scrolled without notifying overlay
//about geometry changes
if (view != d->currentView) {
if (d->currentView) {
d->currentView->setViewportUpdateMode(d->savedViewportUpdateMode);
}
d->currentView = view;
if (view) {
d->savedViewportUpdateMode = view->viewportUpdateMode();
view->setViewportUpdateMode(QGraphicsView::FullViewportUpdate);
}
}
QColor colorKey = Qt::black;
bool geometryChanged = false;
if (d->surface) {
if (widget)
d->surface->setWinId(widget->winId());
QTransform transform = painter->combinedTransform();
QRect overlayRect = transform.mapRect(boundingRect()).toRect();
QRect currentSurfaceRect = d->surface->displayRect();
if (widget) {
//workaround for xvideo issue with U/V planes swapped
QPoint topLeft = widget->mapToGlobal(overlayRect.topLeft());
if ((topLeft.x() & 1) == 0 && topLeft.x() != 0)
overlayRect.moveLeft(overlayRect.left()-1);
}
d->overlayRect = overlayRect;
if (currentSurfaceRect != overlayRect) {
if (!d->surface->displayRect().isEmpty()) {
if (d->softwareRenderingEnabled) {
//recalculate scaled frame pixmap if area is resized
if (currentSurfaceRect.size() != overlayRect.size()) {
d->updateLastFrame();
d->surface->setDisplayRect( overlayRect );
}
} else {
d->softwareRenderingEnabled = true;
d->updateLastFrame();
//don't set new geometry right now,
//but with small delay, to ensure the frame is already
//rendered on top of color key
if (!d->geometryUpdateTimer.isActive())
d->geometryUpdateTimer.start(GEOMETRY_UPDATE_DELAY, this);
}
} else
d->surface->setDisplayRect( overlayRect );
geometryChanged = true;
d->softwareRenderingTimer.start(SOFTWARE_RENDERING_DURATION, this);
#ifdef DEBUG_GFX_VIDEO_ITEM
qDebug() << "set video display rect:" << overlayRect;
#endif
}
colorKey = d->surface->colorKey();
}
if (!d->softwareRenderingEnabled) {
painter->fillRect(d->boundingRect, colorKey);
} else {
if (!d->lastFrame.isNull()) {
painter->drawPixmap(d->boundingRect.topLeft(), d->lastFrame );
} else
painter->fillRect(d->boundingRect, Qt::black);
}
}
QVariant QGraphicsVideoItem::itemChange(GraphicsItemChange change, const QVariant &value)
{
Q_D(QGraphicsVideoItem);
if (change == ItemScenePositionHasChanged) {
update(boundingRect());
} else {
return QGraphicsItem::itemChange(change, value);
}
return value;
}
void QGraphicsVideoItem::timerEvent(QTimerEvent *event)
{
Q_D(QGraphicsVideoItem);
if (event->timerId() == d->softwareRenderingTimer.timerId() && d->softwareRenderingEnabled) {
d->softwareRenderingTimer.stop();
d->softwareRenderingEnabled = false;
d->updateLastFrame();
// repaint last frame, to ensure geometry change is applyed in paused state
d->surface->repaintLastFrame();
d->_q_present();
} else if ((event->timerId() == d->geometryUpdateTimer.timerId())) {
d->geometryUpdateTimer.stop();
//slightly delayed geometry update,
//to avoid flicker at the first geometry change
d->surface->setDisplayRect( d->overlayRect );
}
QGraphicsObject::timerEvent(event);
}
#include "moc_qgraphicsvideoitem.cpp"
QT_END_NAMESPACE

View File

@@ -1,436 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Mobility Components.
**
** $QT_BEGIN_LICENSE:LGPL$
** 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/qpointer.h>
#include <QtCore/qdatetime.h>
#include <QtCore/qbasictimer.h>
#include <QtCore/qcoreevent.h>
#include <QtCore/qdebug.h>
#include <QtGui/qgraphicsscene.h>
#include <QtGui/qgraphicsview.h>
#include <QtGui/qscrollbar.h>
#include <QtGui/qx11info_x11.h>
#include "qgraphicsvideoitem.h"
#ifdef Q_OS_SYMBIAN
#define QGRAPHICSVIDEOITEM_ROTATION_SUPPORT
#endif
#include <qmediaobject.h>
#include <qmediaservice.h>
#include <qvideowindowcontrol.h>
QT_BEGIN_NAMESPACE
#define DEBUG_GFX_VIDEO_ITEM
class QGraphicsVideoItemPrivate : public QObject
{
public:
QGraphicsVideoItemPrivate()
: q_ptr(0)
, mediaObject(0)
, service(0)
, windowControl(0)
, savedViewportUpdateMode(QGraphicsView::FullViewportUpdate)
, aspectRatioMode(Qt::KeepAspectRatio)
, rect(0.0, 0.0, 320, 240)
, videoWidget(0)
{
}
QGraphicsVideoItem *q_ptr;
QMediaObject *mediaObject;
QMediaService *service;
QVideoWindowControl *windowControl;
QPointer<QGraphicsView> currentView;
QList<QPointer<QObject> > eventFilterTargets;
QGraphicsView::ViewportUpdateMode savedViewportUpdateMode;
Qt::AspectRatioMode aspectRatioMode;
QRectF rect;
QRectF boundingRect;
QRectF displayRect;
QSizeF nativeSize;
QWidget *videoWidget;
bool eventFilter(QObject *object, QEvent *event);
void updateEventFilters();
void setWidget(QWidget *widget);
void clearService();
void updateRects();
void updateLastFrame();
void _q_present();
void _q_updateNativeSize();
void _q_serviceDestroyed();
void _q_mediaObjectDestroyed();
};
void QGraphicsVideoItemPrivate::_q_present()
{
}
bool QGraphicsVideoItemPrivate::eventFilter(QObject *object, QEvent *event)
{
if (windowControl && object == videoWidget && QEvent::WinIdChange == event->type()) {
windowControl->setWinId(videoWidget->effectiveWinId());
} else {
bool updateEventFiltersRequired = false;
bool refreshDisplayRequired = false;
foreach (QPointer<QObject> target, eventFilterTargets) {
if (object == target.data()) {
switch (event->type()) {
case QEvent::ParentChange:
updateEventFiltersRequired = true;
refreshDisplayRequired = true;
break;
case QEvent::Move:
case QEvent::Resize:
refreshDisplayRequired = true;
break;
}
}
}
if (updateEventFiltersRequired)
updateEventFilters();
#ifdef Q_OS_SYMBIAN
if (refreshDisplayRequired && windowControl)
QMetaObject::invokeMethod(windowControl, "refreshDisplay");
#endif
}
return false;
}
void QGraphicsVideoItemPrivate::setWidget(QWidget *widget)
{
if (videoWidget != widget) {
videoWidget = widget;
if (widget) {
windowControl->setWinId(widget->winId());
widget->installEventFilter(this);
}
}
}
void QGraphicsVideoItemPrivate::clearService()
{
if (windowControl) {
QObject::disconnect(windowControl, SIGNAL(nativeSizeChanged()), q_ptr, SLOT(_q_updateNativeSize()));
service->releaseControl(windowControl);
windowControl = 0;
}
if (service) {
QObject::disconnect(service, SIGNAL(destroyed()), q_ptr, SLOT(_q_serviceDestroyed()));
service = 0;
}
}
void QGraphicsVideoItemPrivate::updateRects()
{
q_ptr->prepareGeometryChange();
QSizeF videoSize;
if (nativeSize.isEmpty()) {
videoSize = rect.size();
} else if (aspectRatioMode == Qt::IgnoreAspectRatio) {
videoSize = rect.size();
} else {
// KeepAspectRatio or KeepAspectRatioByExpanding
videoSize = nativeSize;
videoSize.scale(rect.size(), aspectRatioMode);
}
displayRect = QRectF(QPointF(0, 0), videoSize);
displayRect.moveCenter(rect.center());
boundingRect = displayRect.intersected(rect);
}
void QGraphicsVideoItemPrivate::updateLastFrame()
{
}
void QGraphicsVideoItemPrivate::updateEventFilters()
{
// In order to determine when the absolute screen position of the item
// changes, we need to receive move events sent to m_currentView
// or any of its ancestors.
foreach (QPointer<QObject> target, eventFilterTargets)
if (target)
target->removeEventFilter(this);
eventFilterTargets.clear();
QObject *target = currentView;
while (target) {
target->installEventFilter(this);
eventFilterTargets.append(target);
target = target->parent();
}
}
void QGraphicsVideoItemPrivate::_q_updateNativeSize()
{
const QSize size = windowControl->nativeSize();
if (nativeSize != size) {
nativeSize = size;
updateRects();
emit q_ptr->nativeSizeChanged(nativeSize);
}
}
void QGraphicsVideoItemPrivate::_q_serviceDestroyed()
{
windowControl = 0;
service = 0;
}
void QGraphicsVideoItemPrivate::_q_mediaObjectDestroyed()
{
mediaObject = 0;
clearService();
}
QGraphicsVideoItem::QGraphicsVideoItem(QGraphicsItem *parent)
: QGraphicsObject(parent)
, d_ptr(new QGraphicsVideoItemPrivate)
{
d_ptr->q_ptr = this;
setCacheMode(NoCache);
setFlag(QGraphicsItem::ItemIgnoresParentOpacity);
setFlag(QGraphicsItem::ItemSendsGeometryChanges);
setFlag(QGraphicsItem::ItemSendsScenePositionChanges);
}
QGraphicsVideoItem::~QGraphicsVideoItem()
{
if (d_ptr->windowControl) {
d_ptr->service->releaseControl(d_ptr->windowControl);
}
if (d_ptr->currentView)
d_ptr->currentView->setViewportUpdateMode(d_ptr->savedViewportUpdateMode);
delete d_ptr;
}
QMediaObject *QGraphicsVideoItem::mediaObject() const
{
return d_func()->mediaObject;
}
bool QGraphicsVideoItem::setMediaObject(QMediaObject *object)
{
Q_D(QGraphicsVideoItem);
if (object == d->mediaObject)
return true;
d->clearService();
d->mediaObject = object;
if (d->mediaObject) {
d->service = d->mediaObject->service();
if (d->service) {
d->windowControl = qobject_cast<QVideoWindowControl *>(
d->service->requestControl(QVideoWindowControl_iid));
if (d->windowControl != 0) {
connect(d->service, SIGNAL(destroyed()), SLOT(_q_serviceDestroyed()));
connect(d->windowControl, SIGNAL(nativeSizeChanged()), SLOT(_q_updateNativeSize()));
d->windowControl->setAspectRatioMode(Qt::IgnoreAspectRatio);
//d->windowControl->setProperty("colorKey", QVariant(QColor(16,7,2)));
d->windowControl->setProperty("autopaintColorKey", QVariant(false));
d->updateRects();
return true;
} else {
qWarning() << "Service doesn't support QVideoWindowControl, overlay item failed";
}
}
}
d->mediaObject = 0;
return false;
}
Qt::AspectRatioMode QGraphicsVideoItem::aspectRatioMode() const
{
return d_func()->aspectRatioMode;
}
void QGraphicsVideoItem::setAspectRatioMode(Qt::AspectRatioMode mode)
{
Q_D(QGraphicsVideoItem);
d->aspectRatioMode = mode;
d->updateRects();
}
QPointF QGraphicsVideoItem::offset() const
{
return d_func()->rect.topLeft();
}
void QGraphicsVideoItem::setOffset(const QPointF &offset)
{
Q_D(QGraphicsVideoItem);
d->rect.moveTo(offset);
d->updateRects();
}
QSizeF QGraphicsVideoItem::size() const
{
return d_func()->rect.size();
}
void QGraphicsVideoItem::setSize(const QSizeF &size)
{
Q_D(QGraphicsVideoItem);
d->rect.setSize(size.isValid() ? size : QSizeF(0, 0));
d->updateRects();
}
QSizeF QGraphicsVideoItem::nativeSize() const
{
return d_func()->nativeSize;
}
QRectF QGraphicsVideoItem::boundingRect() const
{
return d_func()->boundingRect;
}
void QGraphicsVideoItem::paint(
QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
#ifdef DEBUG_GFX_VIDEO_ITEM
qDebug() << "QGraphicsVideoItem::paint";
#endif
Q_UNUSED(option);
Q_D(QGraphicsVideoItem);
QGraphicsView *view = 0;
if (scene() && !scene()->views().isEmpty())
view = scene()->views().first();
//it's necessary to switch vieport update mode to FullViewportUpdate
//otherwise the video item area can be just scrolled without notifying overlay
//about geometry changes
if (view != d->currentView) {
if (d->currentView) {
d->currentView->setViewportUpdateMode(d->savedViewportUpdateMode);
}
d->currentView = view;
if (view) {
d->savedViewportUpdateMode = view->viewportUpdateMode();
view->setViewportUpdateMode(QGraphicsView::FullViewportUpdate);
}
d->updateEventFilters();
}
QColor colorKey = Qt::black;
if (d->windowControl != 0 && widget != 0) {
d->setWidget(widget);
QTransform transform = painter->combinedTransform();
QRect overlayRect = transform.mapRect(d->displayRect).toRect();
QRect currentSurfaceRect = d->windowControl->displayRect();
if (currentSurfaceRect != overlayRect) {
#ifdef DEBUG_GFX_VIDEO_ITEM
qDebug() << "set video display rect:" << overlayRect;
#endif
d->windowControl->setDisplayRect(overlayRect);
}
colorKey = d->windowControl->property("colorKey").value<QColor>();
#ifdef QGRAPHICSVIDEOITEM_ROTATION_SUPPORT
const qreal angle = transform.map(QLineF(0, 0, 1, 0)).angle();
d->windowControl->setProperty("rotation", QVariant::fromValue<qreal>(angle));
#endif
}
if (colorKey.alpha() != 255)
painter->setCompositionMode(QPainter::CompositionMode_Source);
painter->fillRect(d->boundingRect, colorKey);
}
QVariant QGraphicsVideoItem::itemChange(GraphicsItemChange change, const QVariant &value)
{
Q_D(QGraphicsVideoItem);
switch (change) {
case ItemScenePositionHasChanged:
update(boundingRect());
break;
case ItemVisibleChange:
//move overlay out of the screen if video item becomes invisible
if (d->windowControl != 0 && !value.toBool())
d->windowControl->setDisplayRect(QRect(-1,-1,1,1));
break;
default:
break;
}
return QGraphicsItem::itemChange(change, value);
}
void QGraphicsVideoItem::timerEvent(QTimerEvent *event)
{
QGraphicsObject::timerEvent(event);
}
#include "moc_qgraphicsvideoitem.cpp"
QT_END_NAMESPACE

View File

@@ -1,604 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Mobility Components.
**
** $QT_BEGIN_LICENSE:LGPL$
** 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/qglobal.h>
#include <QtCore/QDebug>
#include <QtCore/QEvent>
#include <QtCore/QPointer>
#include <QtGui/QApplication>
#include <QtGui/QGraphicsScene>
#include <QtGui/QGraphicsView>
#include "qgraphicsvideoitem.h"
#include <qmediaobject.h>
#include <qmediaservice.h>
#include <qvideowidgetcontrol.h>
Q_DECLARE_METATYPE(WId)
static const QEvent::Type UpdateViewportTransparencyEvent =
static_cast<QEvent::Type>(QEvent::registerEventType());
QT_BEGIN_NAMESPACE
class QGraphicsVideoItemPrivate : public QObject
{
Q_OBJECT
public:
QGraphicsVideoItemPrivate(QGraphicsVideoItem *parent);
~QGraphicsVideoItemPrivate();
QMediaObject *mediaObject() const;
bool setMediaObject(QMediaObject *mediaObject);
Qt::AspectRatioMode aspectRatioMode() const;
void setAspectRatioMode(Qt::AspectRatioMode mode);
QPointF offset() const;
void setOffset(const QPointF &offset);
QSizeF size() const;
void setSize(const QSizeF &size);
QRectF rect() const;
QRectF boundingRect() const;
QSize nativeSize() const;
void setCurrentView(QGraphicsView *view);
void setVisible(bool visible);
void setZValue(int zValue);
void setTransform(const QTransform &transform);
void setWithinViewBounds(bool within);
bool eventFilter(QObject *watched, QEvent *event);
void customEvent(QEvent *event);
void _q_present();
void _q_updateNativeSize();
void _q_serviceDestroyed();
void _q_mediaObjectDestroyed();
public slots:
void updateWidgetOrdinalPosition();
void updateItemAncestors();
private:
void clearService();
QWidget *videoWidget() const;
void updateGeometry();
void updateViewportAncestorEventFilters();
void updateWidgetVisibility();
void updateTopWinId();
private:
QGraphicsVideoItem *q_ptr;
QMediaService *m_service;
QMediaObject *m_mediaObject;
QVideoWidgetControl *m_widgetControl;
QPointer<QGraphicsView> m_currentView;
QList<QPointer<QObject> > m_viewportAncestors;
QList<QPointer<QObject> > m_itemAncestors;
QGraphicsView::ViewportUpdateMode m_savedViewportUpdateMode;
Qt::AspectRatioMode m_aspectRatioMode;
QRectF m_rect;
QRectF m_boundingRect;
QSize m_nativeSize;
QPointF m_offset;
QTransform m_transform;
bool m_visible;
bool m_withinViewBounds;
};
QGraphicsVideoItemPrivate::QGraphicsVideoItemPrivate(QGraphicsVideoItem *parent)
: q_ptr(parent)
, m_service(0)
, m_mediaObject(0)
, m_widgetControl(0)
, m_savedViewportUpdateMode(QGraphicsView::FullViewportUpdate)
, m_aspectRatioMode(Qt::KeepAspectRatio)
, m_rect(0.0, 0.0, 320.0, 240.0)
, m_visible(false)
, m_withinViewBounds(false)
{
qRegisterMetaType<WId>("WId");
updateItemAncestors();
}
QGraphicsVideoItemPrivate::~QGraphicsVideoItemPrivate()
{
if (m_widgetControl)
m_service->releaseControl(m_widgetControl);
setCurrentView(0);
}
QMediaObject *QGraphicsVideoItemPrivate::mediaObject() const
{
return m_mediaObject;
}
bool QGraphicsVideoItemPrivate::setMediaObject(QMediaObject *mediaObject)
{
bool bound = false;
if (m_mediaObject != mediaObject) {
clearService();
m_mediaObject = mediaObject;
if (m_mediaObject) {
m_service = m_mediaObject->service();
if (m_service) {
connect(m_service, SIGNAL(destroyed()), q_ptr, SLOT(_q_serviceDestroyed()));
m_widgetControl = qobject_cast<QVideoWidgetControl *>(
m_service->requestControl(QVideoWidgetControl_iid));
if (m_widgetControl) {
connect(m_widgetControl, SIGNAL(nativeSizeChanged()), q_ptr, SLOT(_q_updateNativeSize()));
m_widgetControl->setAspectRatioMode(Qt::IgnoreAspectRatio);
updateGeometry();
updateTopWinId();
updateWidgetOrdinalPosition();
updateWidgetVisibility();
bound = true;
}
}
}
}
return bound;
}
Qt::AspectRatioMode QGraphicsVideoItemPrivate::aspectRatioMode() const
{
return m_aspectRatioMode;
}
void QGraphicsVideoItemPrivate::setAspectRatioMode(Qt::AspectRatioMode mode)
{
if (mode != m_aspectRatioMode) {
m_aspectRatioMode = mode;
updateGeometry();
}
}
QPointF QGraphicsVideoItemPrivate::offset() const
{
return m_rect.topLeft();
}
void QGraphicsVideoItemPrivate::setOffset(const QPointF &offset)
{
if (m_offset != offset) {
m_offset = offset;
updateGeometry();
}
}
QSizeF QGraphicsVideoItemPrivate::size() const
{
return m_rect.size();
}
void QGraphicsVideoItemPrivate::setSize(const QSizeF &size)
{
if (m_rect.size() != size) {
m_rect.setSize(size.isValid() ? size : QSizeF(0, 0));
updateGeometry();
}
}
QRectF QGraphicsVideoItemPrivate::rect() const
{
return m_rect;
}
QRectF QGraphicsVideoItemPrivate::boundingRect() const
{
return m_boundingRect;
}
QSize QGraphicsVideoItemPrivate::nativeSize() const
{
return m_nativeSize;
}
void QGraphicsVideoItemPrivate::setCurrentView(QGraphicsView *view)
{
if (m_currentView != view) {
if (m_currentView)
m_currentView->setViewportUpdateMode(m_savedViewportUpdateMode);
m_currentView = view;
updateTopWinId();
if (m_currentView) {
m_savedViewportUpdateMode = m_currentView->viewportUpdateMode();
m_currentView->setViewportUpdateMode(QGraphicsView::FullViewportUpdate);
updateWidgetOrdinalPosition();
updateGeometry();
}
updateViewportAncestorEventFilters();
}
}
void QGraphicsVideoItemPrivate::setVisible(bool visible)
{
if (m_visible != visible) {
m_visible = visible;
updateWidgetVisibility();
}
}
void QGraphicsVideoItemPrivate::setTransform(const QTransform &transform)
{
if (m_transform != transform) {
m_transform = transform;
updateGeometry();
}
}
void QGraphicsVideoItemPrivate::setWithinViewBounds(bool within)
{
if (m_withinViewBounds != within) {
m_withinViewBounds = within;
updateWidgetVisibility();
}
}
bool QGraphicsVideoItemPrivate::eventFilter(QObject *watched, QEvent *event)
{
bool updateViewportAncestorEventFiltersRequired = false;
bool updateGeometryRequired = false;
foreach (QPointer<QObject> target, m_viewportAncestors) {
if (watched == target.data()) {
switch (event->type()) {
case QEvent::ParentChange:
updateViewportAncestorEventFiltersRequired = true;
break;
case QEvent::WinIdChange:
updateViewportAncestorEventFiltersRequired = true;
updateTopWinId();
break;
case QEvent::Move:
case QEvent::Resize:
updateGeometryRequired = true;
break;
}
}
}
if (updateViewportAncestorEventFiltersRequired)
updateViewportAncestorEventFilters();
if (updateGeometryRequired)
updateGeometry();
if (watched == m_currentView) {
switch (event->type()) {
case QEvent::Show:
setVisible(true);
break;
case QEvent::Hide:
setVisible(false);
break;
}
}
return QObject::eventFilter(watched, event);
}
void QGraphicsVideoItemPrivate::customEvent(QEvent *event)
{
if (event->type() == UpdateViewportTransparencyEvent && m_currentView) {
m_currentView->window()->setAttribute(Qt::WA_TranslucentBackground);
m_currentView->window()->update();
}
QObject::customEvent(event);
}
void QGraphicsVideoItemPrivate::clearService()
{
if (m_widgetControl) {
m_service->releaseControl(m_widgetControl);
m_widgetControl = 0;
}
if (m_service) {
m_service->disconnect(q_ptr);
m_service = 0;
}
}
QWidget *QGraphicsVideoItemPrivate::videoWidget() const
{
return m_widgetControl ? m_widgetControl->videoWidget() : 0;
}
void QGraphicsVideoItemPrivate::updateViewportAncestorEventFilters()
{
// In order to determine when the absolute screen position of the item
// changes, we need to receive move events sent to m_currentView
// or any of its ancestors.
foreach (QPointer<QObject> target, m_viewportAncestors)
if (target)
target->removeEventFilter(this);
m_viewportAncestors.clear();
QObject *target = m_currentView;
while (target) {
target->installEventFilter(this);
m_viewportAncestors.append(target);
target = target->parent();
}
}
void QGraphicsVideoItemPrivate::updateItemAncestors()
{
// We need to monitor the ancestors of this item to check for zOrder
// changes and reparenting, both of which influence the stacking order
// of this item and so require changes to the backend window ordinal position.
foreach (QPointer<QObject> target, m_itemAncestors) {
if (target) {
disconnect(target, SIGNAL(zChanged()), this, SLOT(updateWidgetOrdinalPosition()));
disconnect(target, SIGNAL(parentChanged()), this, SLOT(updateItemAncestors()));
disconnect(target, SIGNAL(parentChanged()), this, SLOT(updateWidgetOrdinalPosition()));
}
}
m_itemAncestors.clear();
QGraphicsItem *item = q_ptr;
while (item) {
if (QGraphicsObject *object = item->toGraphicsObject()) {
connect(object, SIGNAL(zChanged()), this, SLOT(updateWidgetOrdinalPosition()));
connect(object, SIGNAL(parentChanged()), this, SLOT(updateItemAncestors()));
connect(object, SIGNAL(parentChanged()), this, SLOT(updateWidgetOrdinalPosition()));
m_itemAncestors.append(object);
}
item = item->parentItem();
}
}
void QGraphicsVideoItemPrivate::updateGeometry()
{
q_ptr->prepareGeometryChange();
QSizeF videoSize;
if (m_nativeSize.isEmpty()) {
videoSize = m_rect.size();
} else if (m_aspectRatioMode == Qt::IgnoreAspectRatio) {
videoSize = m_rect.size();
} else {
// KeepAspectRatio or KeepAspectRatioByExpanding
videoSize = m_nativeSize;
videoSize.scale(m_rect.size(), m_aspectRatioMode);
}
QRectF displayRect(QPointF(0, 0), videoSize);
displayRect.moveCenter(m_rect.center());
m_boundingRect = displayRect.intersected(m_rect);
if (QWidget *widget = videoWidget()) {
QRect widgetGeometry;
QRect extent;
if (m_currentView) {
const QRectF viewRectF = m_transform.mapRect(displayRect);
const QRect viewRect(viewRectF.topLeft().toPoint(), viewRectF.size().toSize());
// Without this, a line of transparent pixels is visible round the edge of the
// item. This is probably down to an error in conversion between scene and
// screen coordinates, but the root cause has not yet been tracked down.
static const QPoint positionFudgeFactor(-1, -1);
static const QSize sizeFudgeFactor(4, 4);
const QRect videoGeometry(m_currentView->mapToGlobal(viewRect.topLeft()) + positionFudgeFactor,
viewRect.size() + sizeFudgeFactor);
QRect viewportGeometry = QRect(m_currentView->viewport()->mapToGlobal(QPoint(0, 0)),
m_currentView->viewport()->size());
widgetGeometry = videoGeometry.intersected(viewportGeometry);
extent = QRect(videoGeometry.topLeft() - widgetGeometry.topLeft(),
videoGeometry.size());
}
setWithinViewBounds(!widgetGeometry.size().isEmpty());
widget->setGeometry(widgetGeometry);
m_widgetControl->setProperty("extentRect", QVariant::fromValue<QRect>(extent));
const qreal angle = m_transform.map(QLineF(0, 0, 1, 0)).angle();
m_widgetControl->setProperty("rotation", QVariant::fromValue<qreal>(angle));
}
}
void QGraphicsVideoItemPrivate::updateWidgetVisibility()
{
if (QWidget *widget = videoWidget())
widget->setVisible(m_visible && m_withinViewBounds);
}
void QGraphicsVideoItemPrivate::updateTopWinId()
{
if (m_widgetControl) {
WId topWinId = m_currentView ? m_currentView->effectiveWinId() : 0;
// Set custom property
m_widgetControl->setProperty("topWinId", QVariant::fromValue<WId>(topWinId));
}
}
void QGraphicsVideoItemPrivate::updateWidgetOrdinalPosition()
{
if (m_currentView) {
QGraphicsScene *scene = m_currentView->scene();
const QGraphicsScene::ItemIndexMethod indexMethod = scene->itemIndexMethod();
scene->setItemIndexMethod(QGraphicsScene::BspTreeIndex);
const QList<QGraphicsItem*> items = m_currentView->items();
QList<QGraphicsVideoItem*> graphicsVideoItems;
foreach (QGraphicsItem *item, items)
if (QGraphicsVideoItem *x = qobject_cast<QGraphicsVideoItem *>(item->toGraphicsObject()))
graphicsVideoItems.append(x);
int ordinalPosition = 1;
foreach (QGraphicsVideoItem *item, graphicsVideoItems)
if (QVideoWidgetControl *widgetControl = item->d_ptr->m_widgetControl)
widgetControl->setProperty("ordinalPosition", ordinalPosition++);
scene->setItemIndexMethod(indexMethod);
}
}
void QGraphicsVideoItemPrivate::_q_present()
{
// Not required for this implementation of QGraphicsVideoItem
}
void QGraphicsVideoItemPrivate::_q_updateNativeSize()
{
const QSize size = m_widgetControl ? m_widgetControl->property("nativeSize").value<QSize>() : QSize();
if (!size.isEmpty() && m_nativeSize != size) {
m_nativeSize = size;
updateGeometry();
emit q_ptr->nativeSizeChanged(m_nativeSize);
}
}
void QGraphicsVideoItemPrivate::_q_serviceDestroyed()
{
m_widgetControl = 0;
m_service = 0;
}
void QGraphicsVideoItemPrivate::_q_mediaObjectDestroyed()
{
m_mediaObject = 0;
clearService();
}
QGraphicsVideoItem::QGraphicsVideoItem(QGraphicsItem *parent)
: QGraphicsObject(parent)
, d_ptr(new QGraphicsVideoItemPrivate(this))
{
setCacheMode(NoCache);
setFlag(QGraphicsItem::ItemIgnoresParentOpacity);
setFlag(QGraphicsItem::ItemSendsGeometryChanges);
setFlag(QGraphicsItem::ItemSendsScenePositionChanges);
}
QGraphicsVideoItem::~QGraphicsVideoItem()
{
delete d_ptr;
}
QMediaObject *QGraphicsVideoItem::mediaObject() const
{
return d_func()->mediaObject();
}
bool QGraphicsVideoItem::setMediaObject(QMediaObject *object)
{
return d_func()->setMediaObject(object);
}
Qt::AspectRatioMode QGraphicsVideoItem::aspectRatioMode() const
{
return d_func()->aspectRatioMode();
}
void QGraphicsVideoItem::setAspectRatioMode(Qt::AspectRatioMode mode)
{
d_func()->setAspectRatioMode(mode);
}
QPointF QGraphicsVideoItem::offset() const
{
return d_func()->offset();
}
void QGraphicsVideoItem::setOffset(const QPointF &offset)
{
d_func()->setOffset(offset);
}
QSizeF QGraphicsVideoItem::size() const
{
return d_func()->size();
}
void QGraphicsVideoItem::setSize(const QSizeF &size)
{
d_func()->setSize(size);
}
QSizeF QGraphicsVideoItem::nativeSize() const
{
return d_func()->nativeSize();
}
QRectF QGraphicsVideoItem::boundingRect() const
{
return d_func()->boundingRect();
}
void QGraphicsVideoItem::paint(
QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
Q_UNUSED(option);
Q_D(QGraphicsVideoItem);
QGraphicsView *view = 0;
if (scene() && !scene()->views().isEmpty())
view = scene()->views().first();
d->setCurrentView(view);
d->setTransform(painter->combinedTransform());
if (widget && !widget->window()->testAttribute(Qt::WA_TranslucentBackground)) {
// On Symbian, setting Qt::WA_TranslucentBackground can cause the
// current window surface to be replaced. Because of this, it cannot
// safely be changed from the context of the viewport paintEvent(), so we
// queue a custom event to set the attribute.
QEvent *event = new QEvent(UpdateViewportTransparencyEvent);
QCoreApplication::instance()->postEvent(d, event);
}
const QPainter::CompositionMode oldCompositionMode = painter->compositionMode();
painter->setCompositionMode(QPainter::CompositionMode_Source);
painter->fillRect(d->boundingRect(), Qt::transparent);
painter->setCompositionMode(oldCompositionMode);
}
QVariant QGraphicsVideoItem::itemChange(GraphicsItemChange change, const QVariant &value)
{
Q_D(QGraphicsVideoItem);
switch (change) {
case ItemScenePositionHasChanged:
update(boundingRect());
break;
case ItemVisibleChange:
d->setVisible(value.toBool());
break;
case ItemZValueHasChanged:
d->updateWidgetOrdinalPosition();
break;
default:
break;
}
return QGraphicsItem::itemChange(change, value);
}
void QGraphicsVideoItem::timerEvent(QTimerEvent *event)
{
QGraphicsObject::timerEvent(event);
}
#include "qgraphicsvideoitem_symbian.moc"
#include "moc_qgraphicsvideoitem.cpp"
QT_END_NAMESPACE

View File

@@ -47,10 +47,6 @@
#include "qmediaserviceproviderplugin.h"
#if defined(Q_OS_SYMBIAN)
# include <f32file.h>
#endif
#if defined(Q_OS_MAC)
# include <CoreFoundation/CoreFoundation.h>
#endif
@@ -61,51 +57,6 @@ typedef QMap<QString,QObjectList> ObjectListMap;
Q_GLOBAL_STATIC(ObjectListMap, staticMediaPlugins);
#if defined(Q_OS_SYMBIAN)
// XXX: Copied over from Mobility, hopefully to be removed at some point
class DirChecker
{
public:
DirChecker();
~DirChecker();
bool checkDir(const QDir& dir);
private:
RFs rfs;
};
DirChecker::DirChecker()
{
qt_symbian_throwIfError(rfs.Connect());
}
bool DirChecker::checkDir(const QDir& dir)
{
bool pathFound = false;
// In Symbian, going cdUp() in a c:/private/<uid3>/ will result in *platsec* error at fileserver (requires AllFiles capability)
// Also, trying to cd() to a nonexistent directory causes *platsec* error. This does not cause functional harm, but should
// nevertheless be changed to use native Symbian methods to avoid unnecessary platsec warnings (as per qpluginloader.cpp).
// Use native Symbian code to check for directory existence, because checking
// for files from under non-existent protected dir like E:/private/<uid> using
// QDir::exists causes platform security violations on most apps.
QString nativePath = QDir::toNativeSeparators(dir.absolutePath());
TPtrC ptr = TPtrC16(static_cast<const TUint16*>(nativePath.utf16()), nativePath.length());
TUint attributes;
TInt err = rfs.Att(ptr, attributes);
if (err == KErrNone) {
// yes, the directory exists.
pathFound = true;
}
return pathFound;
}
DirChecker::~DirChecker()
{
rfs.Close();
}
#endif
QMediaPluginLoader::QMediaPluginLoader(const char *iid, const QString &location, Qt::CaseSensitivity):
m_iid(iid)
{
@@ -139,10 +90,6 @@ QStringList QMediaPluginLoader::availablePlugins() const
QStringList paths;
QStringList plugins;
#if defined(Q_OS_SYMBIAN)
DirChecker dirChecker;
#endif
#if defined(Q_OS_MAC)
QString imageSuffix(qgetenv("DYLD_IMAGE_SUFFIX"));
@@ -174,31 +121,26 @@ QStringList QMediaPluginLoader::availablePlugins() const
foreach (const QString &path, paths) {
QDir typeDir(path + m_location);
#if defined(Q_OS_SYMBIAN)
if (dirChecker.checkDir(typeDir))
#endif
{
foreach (const QString &file, typeDir.entryList(QDir::Files)) {
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")))
if (!imageSuffix.isEmpty()) { // Only add appropriate images
if (file.lastIndexOf(imageSuffix, -6) == -1)
continue;
#elif defined(Q_OS_WIN)
// Ignore non-dlls
if (!file.endsWith(QLatin1String(".dll"), Qt::CaseInsensitive))
} else { // Ignore any images with common suffixes
if (file.endsWith(QLatin1String("_debug.dylib")) ||
file.endsWith(QLatin1String("_profile.dylib")))
continue;
#endif
plugins << typeDir.absoluteFilePath(file);
}
#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);
}
}

View File

@@ -57,18 +57,18 @@
#define QTM_PACKAGE_TAG ""
#include <QtCore/qglobal.h>
#if defined(QTM_BUILD_UNITTESTS) && (defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN)) && defined(QT_MAKEDLL)
#if defined(QTM_BUILD_UNITTESTS) && (defined(Q_OS_WIN)) && defined(QT_MAKEDLL)
# define QM_AUTOTEST_EXPORT Q_DECL_EXPORT
#elif defined(QTM_BUILD_UNITTESTS) && (defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN)) && defined(QT_DLL)
#elif defined(QTM_BUILD_UNITTESTS) && (defined(Q_OS_WIN)) && defined(QT_DLL)
# define QM_AUTOTEST_EXPORT Q_DECL_IMPORT
#elif defined(QTM_BUILD_UNITTESTS) && !(defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN)) && defined(QT_SHARED)
#elif defined(QTM_BUILD_UNITTESTS) && !(defined(Q_OS_WIN)) && defined(QT_SHARED)
# define QM_AUTOTEST_EXPORT Q_DECL_EXPORT
#else
# define QM_AUTOTEST_EXPORT
#endif
#if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN)
#if defined(Q_OS_WIN)
# if defined(QT_NODLL)
# undef QT_MAKEDLL
# undef QT_DLL
@@ -160,11 +160,6 @@
# define Q_LOCATION_EXPORT Q_DECL_IMPORT
# define Q_MULTIMEDIA_EXPORT Q_DECL_IMPORT
# define Q_MESSAGING_EXPORT Q_DECL_IMPORT
# if QTM_SERVICEFW_SYMBIAN_DATABASEMANAGER_SERVER
# define Q_SERVICEFW_EXPORT
# else
# define Q_SERVICEFW_EXPORT Q_DECL_IMPORT
# endif
# define Q_SYSINFO_EXPORT Q_DECL_IMPORT
# define Q_SENSORS_EXPORT Q_DECL_IMPORT
# define Q_FEEDBACK_EXPORT Q_DECL_IMPORT
@@ -211,17 +206,6 @@
#endif
#ifdef QTM_SERVICEFW_SYMBIAN_DATABASEMANAGER_SERVER
# ifdef Q_SERVICEFW_EXPORT
# undef Q_SERVICEFW_EXPORT
# endif
# define Q_SERVICEFW_EXPORT
# ifdef QM_AUTOTEST_EXPORT
# undef QM_AUTOTEST_EXPORT
# endif
# define QM_AUTOTEST_EXPORT
#endif
// The namespace is hardcoded as moc has issues resolving
// macros which would be a prerequisite for a dynmamic namespace
#define QTM_NAMESPACE QtMobility

View File

@@ -76,12 +76,6 @@ QVideoWidgetControlBackend::QVideoWidgetControlBackend(
layout->setMargin(0);
layout->setSpacing(0);
#ifdef Q_OS_SYMBIAN
// On some cases the flag is not reset automatically
// This would lead to viewfinder not being visible on Symbian
control->videoWidget()->setAttribute(Qt::WA_WState_ExplicitShowHide, false);
#endif // Q_OS_SYMBIAN
layout->addWidget(control->videoWidget());
widget->setLayout(layout);

View File

@@ -1,497 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Mobility Components.
**
** $QT_BEGIN_LICENSE:LGPL$
** 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 <QtGui/qx11info_x11.h>
#include <QtCore/qdebug.h>
#include <QtCore/qvariant.h>
#include <qvideosurfaceformat.h>
#include "qxvideosurface_maemo5_p.h"
//#define DEBUG_XV_SURFACE
struct XvFormatRgb
{
QVideoFrame::PixelFormat pixelFormat;
int bits_per_pixel;
int format;
int num_planes;
int depth;
unsigned int red_mask;
unsigned int green_mask;
unsigned int blue_mask;
};
bool operator ==(const XvImageFormatValues &format, const XvFormatRgb &rgb)
{
return format.type == XvRGB
&& format.bits_per_pixel == rgb.bits_per_pixel
&& format.format == rgb.format
&& format.num_planes == rgb.num_planes
&& format.depth == rgb.depth
&& format.red_mask == rgb.red_mask
&& format.blue_mask == rgb.blue_mask;
}
static const XvFormatRgb qt_xvRgbLookup[] =
{
{ QVideoFrame::Format_ARGB32, 32, XvPacked, 1, 32, 0x00FF0000, 0x0000FF00, 0x000000FF },
{ QVideoFrame::Format_RGB32 , 32, XvPacked, 1, 24, 0x00FF0000, 0x0000FF00, 0x000000FF },
{ QVideoFrame::Format_RGB24 , 24, XvPacked, 1, 24, 0x00FF0000, 0x0000FF00, 0x000000FF },
{ QVideoFrame::Format_RGB565, 16, XvPacked, 1, 16, 0x0000F800, 0x000007E0, 0x0000001F },
{ QVideoFrame::Format_BGRA32, 32, XvPacked, 1, 32, 0xFF000000, 0x00FF0000, 0x0000FF00 },
{ QVideoFrame::Format_BGR32 , 32, XvPacked, 1, 24, 0x00FF0000, 0x0000FF00, 0x000000FF },
{ QVideoFrame::Format_BGR24 , 24, XvPacked, 1, 24, 0x00FF0000, 0x0000FF00, 0x000000FF },
{ QVideoFrame::Format_BGR565, 16, XvPacked, 1, 16, 0x0000F800, 0x000007E0, 0x0000001F }
};
struct XvFormatYuv
{
QVideoFrame::PixelFormat pixelFormat;
int bits_per_pixel;
int format;
int num_planes;
unsigned int y_sample_bits;
unsigned int u_sample_bits;
unsigned int v_sample_bits;
unsigned int horz_y_period;
unsigned int horz_u_period;
unsigned int horz_v_period;
unsigned int vert_y_period;
unsigned int vert_u_period;
unsigned int vert_v_period;
char component_order[32];
};
bool operator ==(const XvImageFormatValues &format, const XvFormatYuv &yuv)
{
return format.type == XvYUV
&& format.bits_per_pixel == yuv.bits_per_pixel
&& format.format == yuv.format
&& format.num_planes == yuv.num_planes
&& format.y_sample_bits == yuv.y_sample_bits
&& format.u_sample_bits == yuv.u_sample_bits
&& format.v_sample_bits == yuv.v_sample_bits
&& format.horz_y_period == yuv.horz_y_period
&& format.horz_u_period == yuv.horz_u_period
&& format.horz_v_period == yuv.horz_v_period
&& format.horz_y_period == yuv.vert_y_period
&& format.vert_u_period == yuv.vert_u_period
&& format.vert_v_period == yuv.vert_v_period
&& qstrncmp(format.component_order, yuv.component_order, 32) == 0;
}
static const XvFormatYuv qt_xvYuvLookup[] =
{
{ QVideoFrame::Format_YUV444 , 24, XvPacked, 1, 8, 8, 8, 1, 1, 1, 1, 1, 1, "YUV" },
{ QVideoFrame::Format_YUV420P, 12, XvPlanar, 3, 8, 8, 8, 1, 2, 2, 1, 2, 2, "YUV" },
{ QVideoFrame::Format_YV12 , 12, XvPlanar, 3, 8, 8, 8, 1, 2, 2, 1, 2, 2, "YVU" },
{ QVideoFrame::Format_UYVY , 16, XvPacked, 1, 8, 8, 8, 1, 2, 2, 1, 1, 1, "UYVY" },
{ QVideoFrame::Format_YUYV , 16, XvPacked, 1, 8, 8, 8, 1, 2, 2, 1, 1, 1, "YUY2" },
{ QVideoFrame::Format_YUYV , 16, XvPacked, 1, 8, 8, 8, 1, 2, 2, 1, 1, 1, "YUYV" },
{ QVideoFrame::Format_NV12 , 12, XvPlanar, 2, 8, 8, 8, 1, 2, 2, 1, 2, 2, "YUV" },
{ QVideoFrame::Format_NV12 , 12, XvPlanar, 2, 8, 8, 8, 1, 2, 2, 1, 2, 2, "YVU" },
{ QVideoFrame::Format_Y8 , 8 , XvPlanar, 1, 8, 0, 0, 1, 0, 0, 1, 0, 0, "Y" }
};
QXVideoSurface::QXVideoSurface(QObject *parent)
: QAbstractVideoSurface(parent)
, m_winId(0)
, m_portId(0)
, m_gc(0)
, m_image(0)
, m_colorKey(24,0,24)
{
}
QXVideoSurface::~QXVideoSurface()
{
if (m_gc)
XFreeGC(QX11Info::display(), m_gc);
if (m_portId != 0)
XvUngrabPort(QX11Info::display(), m_portId, 0);
}
WId QXVideoSurface::winId() const
{
return m_winId;
}
void QXVideoSurface::setWinId(WId id)
{
if (id == m_winId)
return;
#ifdef DEBUG_XV_SURFACE
qDebug() << "QXVideoSurface::setWinId" << id;
#endif
if (m_image)
XFree(m_image);
if (m_gc) {
XFreeGC(QX11Info::display(), m_gc);
m_gc = 0;
}
if (m_portId != 0)
XvUngrabPort(QX11Info::display(), m_portId, 0);
QList<QVideoFrame::PixelFormat> prevFormats = m_supportedPixelFormats;
m_supportedPixelFormats.clear();
m_formatIds.clear();
m_winId = id;
if (m_winId && findPort()) {
querySupportedFormats();
m_gc = XCreateGC(QX11Info::display(), m_winId, 0, 0);
if (m_image) {
m_image = 0;
if (!start(surfaceFormat()))
QAbstractVideoSurface::stop();
}
} else if (m_image) {
m_image = 0;
QAbstractVideoSurface::stop();
}
if (m_supportedPixelFormats != prevFormats) {
#ifdef DEBUG_XV_SURFACE
qDebug() << "QXVideoSurface: supportedFormatsChanged";
#endif
emit supportedFormatsChanged();
}
}
QRect QXVideoSurface::displayRect() const
{
return m_displayRect;
}
void QXVideoSurface::setDisplayRect(const QRect &rect)
{
m_displayRect = rect;
}
QColor QXVideoSurface::colorKey() const
{
return m_colorKey;
}
void QXVideoSurface::setColorKey(QColor key)
{
m_colorKey = key;
}
int QXVideoSurface::getAttribute(const char *attribute) const
{
if (m_portId != 0) {
Display *display = QX11Info::display();
Atom atom = XInternAtom(display, attribute, True);
int value = 0;
XvGetPortAttribute(display, m_portId, atom, &value);
return value;
} else {
return 0;
}
}
void QXVideoSurface::setAttribute(const char *attribute, int value)
{
if (m_portId != 0) {
Display *display = QX11Info::display();
Atom atom = XInternAtom(display, attribute, True);
XvSetPortAttribute(display, m_portId, atom, value);
}
}
QList<QVideoFrame::PixelFormat> QXVideoSurface::supportedPixelFormats(
QAbstractVideoBuffer::HandleType handleType) const
{
if ( handleType == QAbstractVideoBuffer::NoHandle ||
handleType == QAbstractVideoBuffer::XvShmImageHandle )
return m_supportedPixelFormats;
else
return QList<QVideoFrame::PixelFormat>();
}
bool QXVideoSurface::start(const QVideoSurfaceFormat &format)
{
#ifdef DEBUG_XV_SURFACE
qDebug() << "QXVideoSurface::start" << format;
#endif
m_lastFrame = QVideoFrame();
if (m_image)
XFree(m_image);
m_xvFormatId = 0;
for (int i = 0; i < m_supportedPixelFormats.count(); ++i) {
if (m_supportedPixelFormats.at(i) == format.pixelFormat()) {
m_xvFormatId = m_formatIds.at(i);
break;
}
}
if (m_xvFormatId == 0) {
setError(UnsupportedFormatError);
} else {
XvImage *image = XvShmCreateImage(
QX11Info::display(),
m_portId,
m_xvFormatId,
0,
format.frameWidth(),
format.frameHeight(),
&m_shminfo
);
if (!image) {
setError(ResourceError);
return false;
}
m_shminfo.shmid = shmget(IPC_PRIVATE, image->data_size, IPC_CREAT | 0777);
m_shminfo.shmaddr = image->data = (char*)shmat(m_shminfo.shmid, 0, 0);
m_shminfo.readOnly = False;
if (!XShmAttach(QX11Info::display(), &m_shminfo)) {
qWarning() << "XShmAttach failed" << format;
return false;
}
if (!image) {
setError(ResourceError);
} else {
m_viewport = format.viewport();
m_image = image;
quint32 c = m_colorKey.rgb();
quint16 colorKey16 = ((c >> 3) & 0x001f)
| ((c >> 5) & 0x07e0)
| ((c >> 8) & 0xf800);
setAttribute("XV_AUTOPAINT_COLORKEY", 0);
setAttribute("XV_COLORKEY", colorKey16);
setAttribute("XV_OMAP_VSYNC", 1);
setAttribute("XV_DOUBLE_BUFFER", 0);
QVideoSurfaceFormat newFormat = format;
newFormat.setProperty("portId", QVariant(quint64(m_portId)));
newFormat.setProperty("xvFormatId", m_xvFormatId);
newFormat.setProperty("dataSize", image->data_size);
return QAbstractVideoSurface::start(newFormat);
}
}
if (m_image) {
m_image = 0;
QAbstractVideoSurface::stop();
}
return false;
}
void QXVideoSurface::stop()
{
if (m_image) {
XFree(m_image);
m_image = 0;
m_lastFrame = QVideoFrame();
QAbstractVideoSurface::stop();
}
}
bool QXVideoSurface::present(const QVideoFrame &frame)
{
if (!m_image) {
setError(StoppedError);
return false;
} else if (m_image->width != frame.width() || m_image->height != frame.height()) {
setError(IncorrectFormatError);
return false;
} else {
m_lastFrame = frame;
if (!m_lastFrame.map(QAbstractVideoBuffer::ReadOnly)) {
qWarning() << "Failed to map video frame";
setError(IncorrectFormatError);
return false;
} else {
bool presented = false;
if (frame.handleType() != QAbstractVideoBuffer::XvShmImageHandle &&
m_image->data_size > m_lastFrame.mappedBytes()) {
qWarning("Insufficient frame buffer size");
setError(IncorrectFormatError);
} else if (frame.handleType() != QAbstractVideoBuffer::XvShmImageHandle &&
m_image->num_planes > 0 &&
m_image->pitches[0] != m_lastFrame.bytesPerLine()) {
qWarning("Incompatible frame pitches");
setError(IncorrectFormatError);
} else {
XvImage *img = 0;
if (frame.handleType() == QAbstractVideoBuffer::XvShmImageHandle) {
img = frame.handle().value<XvImage*>();
} else {
img = m_image;
memcpy(m_image->data, m_lastFrame.bits(), qMin(m_lastFrame.mappedBytes(), m_image->data_size));
}
if (img)
XvShmPutImage(
QX11Info::display(),
m_portId,
m_winId,
m_gc,
img,
m_viewport.x(),
m_viewport.y(),
m_viewport.width(),
m_viewport.height(),
m_displayRect.x(),
m_displayRect.y(),
m_displayRect.width(),
m_displayRect.height(),
false);
presented = true;
}
m_lastFrame.unmap();
return presented;
}
}
}
void QXVideoSurface::repaintLastFrame()
{
if (m_lastFrame.isValid())
present(QVideoFrame(m_lastFrame));
}
bool QXVideoSurface::findPort()
{
unsigned int count = 0;
XvAdaptorInfo *adaptors = 0;
bool portFound = false;
if (XvQueryAdaptors(QX11Info::display(), m_winId, &count, &adaptors) == Success) {
for (unsigned int i = 0; i < count && !portFound; ++i) {
if (adaptors[i].type & XvImageMask) {
m_portId = adaptors[i].base_id;
for (unsigned int j = 0; j < adaptors[i].num_ports && !portFound; ++j, ++m_portId)
portFound = XvGrabPort(QX11Info::display(), m_portId, 0) == Success;
}
}
XvFreeAdaptorInfo(adaptors);
}
if (!portFound)
qWarning() << "QXVideoSurface::findPort: failed to find XVideo port";
return portFound;
}
void QXVideoSurface::querySupportedFormats()
{
int count = 0;
if (XvImageFormatValues *imageFormats = XvListImageFormats(
QX11Info::display(), m_portId, &count)) {
const int rgbCount = sizeof(qt_xvRgbLookup) / sizeof(XvFormatRgb);
const int yuvCount = sizeof(qt_xvYuvLookup) / sizeof(XvFormatYuv);
for (int i = 0; i < count; ++i) {
switch (imageFormats[i].type) {
case XvRGB:
for (int j = 0; j < rgbCount; ++j) {
if (imageFormats[i] == qt_xvRgbLookup[j]) {
m_supportedPixelFormats.append(qt_xvRgbLookup[j].pixelFormat);
m_formatIds.append(imageFormats[i].id);
break;
}
}
break;
case XvYUV:
for (int j = 0; j < yuvCount; ++j) {
//skip YUV420P and YV12 formats, they don't work correctly and slow,
//YUV2 == YUYV is just slow
if (imageFormats[i] == qt_xvYuvLookup[j] &&
qt_xvYuvLookup[j].pixelFormat != QVideoFrame::Format_YUV420P &&
qt_xvYuvLookup[j].pixelFormat != QVideoFrame::Format_YV12) {
m_supportedPixelFormats.append(qt_xvYuvLookup[j].pixelFormat);
m_formatIds.append(imageFormats[i].id);
break;
}
}
break;
}
}
XFree(imageFormats);
}
#ifdef DEBUG_XV_SURFACE
qDebug() << "Supported pixel formats:" << m_supportedPixelFormats;
#endif
}

View File

@@ -1,111 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Mobility Components.
**
** $QT_BEGIN_LICENSE:LGPL$
** 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 QXVIDEOSURFACE_MAEMO5_H
#define QXVIDEOSURFACE_MAEMO5_H
#include <QtCore/qhash.h>
#include <QtGui/qwidget.h>
#include <qabstractvideosurface.h>
#include <X11/Xlib.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <X11/extensions/XShm.h>
#include <X11/Xlib.h>
#include <X11/extensions/Xv.h>
#include <X11/extensions/Xvlib.h>
QT_USE_NAMESPACE
class QXVideoSurface : public QAbstractVideoSurface
{
Q_OBJECT
public:
QXVideoSurface(QObject *parent = 0);
~QXVideoSurface();
WId winId() const;
void setWinId(WId id);
QRect displayRect() const;
void setDisplayRect(const QRect &rect);
QColor colorKey() const;
void setColorKey(QColor key);
QList<QVideoFrame::PixelFormat> supportedPixelFormats(
QAbstractVideoBuffer::HandleType handleType = QAbstractVideoBuffer::NoHandle) const;
QVideoFrame lastFrame() const { return m_lastFrame; }
public slots:
bool start(const QVideoSurfaceFormat &format);
void stop();
bool present(const QVideoFrame &frame);
void repaintLastFrame();
private:
WId m_winId;
XvPortID m_portId;
int m_xvFormatId;
GC m_gc;
XvImage *m_image;
XShmSegmentInfo m_shminfo;
QList<QVideoFrame::PixelFormat> m_supportedPixelFormats;
QVector<int> m_formatIds;
QRect m_viewport;
QRect m_displayRect;
QColor m_colorKey;
QVideoFrame m_lastFrame;
bool findPort();
void querySupportedFormats();
int getAttribute(const char *attribute) const;
void setAttribute(const char *attribute, int value);
};
Q_DECLARE_METATYPE(XvImage*)
#endif