From 490cd29001670b37204dcf5e24398073f610fabd Mon Sep 17 00:00:00 2001 From: Justin McPherson Date: Thu, 25 Mar 2010 13:50:08 +1000 Subject: Update Phonon core to 4.4.0 --- src/3rdparty/phonon/phonon/CMakeLists.txt | 35 ++ src/3rdparty/phonon/phonon/audiooutput.cpp | 106 +++++- src/3rdparty/phonon/phonon/audiooutput.h | 1 + src/3rdparty/phonon/phonon/audiooutput_p.h | 8 +- src/3rdparty/phonon/phonon/audiooutputinterface.h | 2 +- src/3rdparty/phonon/phonon/backendcapabilities.cpp | 2 +- src/3rdparty/phonon/phonon/factory.cpp | 25 +- src/3rdparty/phonon/phonon/factory_p.h | 7 + src/3rdparty/phonon/phonon/globalconfig.cpp | 358 ++++++++++++++++----- src/3rdparty/phonon/phonon/globalconfig_p.h | 31 +- src/3rdparty/phonon/phonon/mediaobject.cpp | 12 +- src/3rdparty/phonon/phonon/objectdescription.cpp | 44 ++- .../phonon/phonon/objectdescriptionmodel.cpp | 2 + .../phonon/phonon/objectdescriptionmodel.h | 36 +-- src/3rdparty/phonon/phonon/path.cpp | 8 +- src/3rdparty/phonon/phonon/phonondefs.h | 5 + src/3rdparty/phonon/phonon/seekslider.cpp | 4 +- src/3rdparty/phonon/phonon/seekslider_p.h | 4 +- src/3rdparty/phonon/phonon/videowidget.cpp | 16 +- src/3rdparty/phonon/phonon/videowidget.h | 1 + src/3rdparty/phonon/phonon/videowidgetinterface.h | 13 + src/3rdparty/phonon/phonon/volumeslider_p.h | 4 +- src/phonon/phonon.pro | 64 ++-- 23 files changed, 571 insertions(+), 217 deletions(-) diff --git a/src/3rdparty/phonon/phonon/CMakeLists.txt b/src/3rdparty/phonon/phonon/CMakeLists.txt index 11d7913..ace934a 100644 --- a/src/3rdparty/phonon/phonon/CMakeLists.txt +++ b/src/3rdparty/phonon/phonon/CMakeLists.txt @@ -8,6 +8,30 @@ endif (PHONON_BUILD_EXAMPLES) add_subdirectory(experimental) +set(PULSEAUDIO_MINIMUM_VERSION "0.9.15") +macro_optional_find_package(PulseAudio) +if (PULSEAUDIO_FOUND) + # PULSEAUDIO_DEVICE_MANAGER feature check could be moved to FindPulseAudio.cmake, hint hint. -- Rex + macro_ensure_version("0.9.21" "${PULSEAUDIO_VERSION}" PULSEAUDIO_DEVICE_MANAGER) +endif (PULSEAUDIO_FOUND) +macro_log_feature(PULSEAUDIO_FOUND "PulseAudio" "A cross-platform, networked sound server." "http://www.pulseaudio.org" FALSE "" "Allows audio playback via the PulseAudio soundserver when it is running") +macro_optional_find_package(GLIB2) +macro_log_feature(GLIB2_FOUND "GLib2" "GLib 2 is required to compile the pulseaudio for Phonon" "http://www.gtk.org/download/" FALSE) + + +if (GLIB2_FOUND AND PULSEAUDIO_FOUND) + add_definitions(-DHAVE_PULSEAUDIO) + include_directories(${GLIB2_INCLUDE_DIR} ${PULSEAUDIO_INCLUDE_DIR}) + if (PULSEAUDIO_DEVICE_MANAGER) + add_definitions(-DHAVE_PULSEAUDIO_DEVICE_MANAGER) + endif(PULSEAUDIO_DEVICE_MANAGER) +else(GLIB2_FOUND AND PULSEAUDIO_FOUND) + set(PULSEAUDIO_INCLUDE_DIR "") + set(PULSEAUDIO_LIBRARY "") + set(PULSEAUDIO_MAINLOOP_LIBRARY "") +endif(GLIB2_FOUND AND PULSEAUDIO_FOUND) + + set(phonon_LIB_SRCS objectdescription.cpp objectdescriptionmodel.cpp @@ -35,9 +59,12 @@ set(phonon_LIB_SRCS videowidget.cpp videoplayer.cpp seekslider.cpp + swiftslider.cpp volumeslider.cpp effectwidget.cpp iodevicestream.cpp + audiodataoutput.cpp + pulsesupport.cpp ) if (QT_QTDBUS_FOUND) @@ -50,6 +77,10 @@ endif (QT_QTDBUS_FOUND) add_definitions(-DPHONON_LIBRARY_PATH="${PLUGIN_INSTALL_DIR}/plugins") automoc4_add_library(phonon SHARED ${phonon_LIB_SRCS}) target_link_libraries(phonon ${QT_QTCORE_LIBRARY} ${QT_QTGUI_LIBRARY}) +if (GLIB2_FOUND AND PULSEAUDIO_FOUND) +target_link_libraries(phonon ${GLIB2_LIBRARIES} ${GOBJECT_LIBRARIES} ${PULSEAUDIO_LIBRARY} ${PULSEAUDIO_MAINLOOP_LIBRARY}) +endif (GLIB2_FOUND AND PULSEAUDIO_FOUND) + if (QT_QTDBUS_FOUND) target_link_libraries(phonon ${QT_QTDBUS_LIBRARY}) endif (QT_QTDBUS_FOUND) @@ -99,6 +130,10 @@ install(FILES volumeslider.h effectwidget.h platformplugin.h + audiodataoutput.h + audiodataoutputinterface.h + globalconfig.h + pulsesupport.h DESTINATION ${INCLUDE_INSTALL_DIR}/phonon COMPONENT Devel) install(FILES org.kde.Phonon.AudioOutput.xml DESTINATION ${DBUS_INTERFACES_INSTALL_DIR}) diff --git a/src/3rdparty/phonon/phonon/audiooutput.cpp b/src/3rdparty/phonon/phonon/audiooutput.cpp index 0f6a49b..932a875 100644 --- a/src/3rdparty/phonon/phonon/audiooutput.cpp +++ b/src/3rdparty/phonon/phonon/audiooutput.cpp @@ -24,10 +24,11 @@ #include "factory_p.h" #include "objectdescription.h" #include "audiooutputadaptor_p.h" -#include "globalconfig_p.h" +#include "globalconfig.h" #include "audiooutputinterface.h" #include "phononnamespace_p.h" #include "platform_p.h" +#include "pulsesupport.h" #include @@ -42,8 +43,12 @@ QT_BEGIN_NAMESPACE namespace Phonon { -static inline bool callSetOutputDevice(MediaNodePrivate *const d, int index) +static inline bool callSetOutputDevice(AudioOutputPrivate *const d, int index) { + PulseSupport *pulse = PulseSupport::getInstance(); + if (pulse->isActive()) + return pulse->setOutputDevice(d->getStreamUuid(), index); + Iface iface(d); if (iface) { return iface->setOutputDevice(AudioOutputDevice::fromIndex(index)); @@ -51,8 +56,12 @@ static inline bool callSetOutputDevice(MediaNodePrivate *const d, int index) return Iface::cast(d)->setOutputDevice(index); } -static inline bool callSetOutputDevice(MediaNodePrivate *const d, const AudioOutputDevice &dev) +static inline bool callSetOutputDevice(AudioOutputPrivate *const d, const AudioOutputDevice &dev) { + PulseSupport *pulse = PulseSupport::getInstance(); + if (pulse->isActive()) + return pulse->setOutputDevice(d->getStreamUuid(), dev.index()); + Iface iface(d); if (iface) { return iface->setOutputDevice(dev); @@ -89,16 +98,20 @@ void AudioOutputPrivate::init(Phonon::Category c) #endif category = c; - - // select hardware device according to the category - device = AudioOutputDevice::fromIndex(GlobalConfig().audioOutputDeviceFor(category, GlobalConfig::AdvancedDevicesFromSettings | GlobalConfig::HideUnavailableDevices)); + streamUuid = QUuid::createUuid().toString(); + PulseSupport *pulse = PulseSupport::getInstance(); + pulse->setStreamPropList(category, streamUuid); + q->connect(pulse, SIGNAL(usingDevice(QString,int)), SLOT(_k_deviceChanged(QString,int))); createBackendObject(); q->connect(Factory::sender(), SIGNAL(availableAudioOutputDevicesChanged()), SLOT(_k_deviceListChanged())); } - +QString AudioOutputPrivate::getStreamUuid() +{ + return streamUuid; +} void AudioOutputPrivate::createBackendObject() { @@ -106,6 +119,7 @@ void AudioOutputPrivate::createBackendObject() return; Q_Q(AudioOutput); m_backendObject = Factory::createAudioOutput(q); + device = AudioOutputDevice::fromIndex(GlobalConfig().audioOutputDeviceFor(category, GlobalConfig::AdvancedDevicesFromSettings | GlobalConfig::HideUnavailableDevices)); if (m_backendObject) { setupBackendObject(); } @@ -220,21 +234,21 @@ bool AudioOutput::setOutputDevice(const AudioOutputDevice &newAudioOutputDevice) { K_D(AudioOutput); if (!newAudioOutputDevice.isValid()) { - d->outputDeviceOverridden = false; + d->outputDeviceOverridden = d->forceMove = false; const int newIndex = GlobalConfig().audioOutputDeviceFor(d->category); if (newIndex == d->device.index()) { return true; } d->device = AudioOutputDevice::fromIndex(newIndex); } else { - d->outputDeviceOverridden = true; + d->outputDeviceOverridden = d->forceMove = true; if (d->device == newAudioOutputDevice) { return true; } d->device = newAudioOutputDevice; } if (k_ptr->backendObject()) { - return callSetOutputDevice(k_ptr, d->device.index()); + return callSetOutputDevice(d, d->device.index()); } return true; } @@ -261,7 +275,10 @@ void AudioOutputPrivate::setupBackendObject() #ifndef QT_NO_PHONON_SETTINGSGROUP // if the output device is not available and the device was not explicitly set - if (!callSetOutputDevice(this, device) && !outputDeviceOverridden) { + // There is no need to set the output device initially if PA is used as + // we know it will not work (stream doesn't exist yet) and that this will be + // handled by _k_deviceChanged() + if (!PulseSupport::getInstance()->isActive() && !callSetOutputDevice(this, device) && !outputDeviceOverridden) { // fall back in the preference list of output devices QList deviceList = GlobalConfig().audioOutputDeviceListFor(category, GlobalConfig::AdvancedDevicesFromSettings | GlobalConfig::HideUnavailableDevices); if (deviceList.isEmpty()) { @@ -306,10 +323,14 @@ void AudioOutputPrivate::_k_revertFallback() void AudioOutputPrivate::_k_audioDeviceFailed() { + if (PulseSupport::getInstance()->isActive()) + return; + +#ifndef QT_NO_PHONON_SETTINGSGROUP + pDebug() << Q_FUNC_INFO; // outputDeviceIndex identifies a failing device // fall back in the preference list of output devices -#ifndef QT_NO_PHONON_SETTINGSGROUP const QList deviceList = GlobalConfig().audioOutputDeviceListFor(category, GlobalConfig::AdvancedDevicesFromSettings | GlobalConfig::HideUnavailableDevices); for (int i = 0; i < deviceList.count(); ++i) { const int devIndex = deviceList.at(i); @@ -331,8 +352,15 @@ void AudioOutputPrivate::_k_audioDeviceFailed() void AudioOutputPrivate::_k_deviceListChanged() { - pDebug() << Q_FUNC_INFO; + if (PulseSupport::getInstance()->isActive()) + return; + #ifndef QT_NO_PHONON_SETTINGSGROUP + pDebug() << Q_FUNC_INFO; + // Check to see if we have an override and do not change to a higher priority device if the overridden device is still present. + if (outputDeviceOverridden && device.property("available").toBool()) { + return; + } // let's see if there's a usable device higher in the preference list const QList deviceList = GlobalConfig().audioOutputDeviceListFor(category, GlobalConfig::AdvancedDevicesFromSettings); DeviceChangeType changeType = HigherPreferenceChange; @@ -361,6 +389,36 @@ void AudioOutputPrivate::_k_deviceListChanged() #endif //QT_NO_PHONON_SETTINGSGROUP } +void AudioOutputPrivate::_k_deviceChanged(QString inStreamUuid, int deviceIndex) +{ + // Note that this method is only used by PulseAudio at present. + if (inStreamUuid == streamUuid) { + // 1. Check to see if we are overridden. If we are, and devices do not match, + // then try and apply our own device as the output device. + // We only do this the first time + if (outputDeviceOverridden && forceMove) { + forceMove = false; + const AudioOutputDevice ¤tDevice = AudioOutputDevice::fromIndex(deviceIndex); + if (currentDevice != device) { + if (!callSetOutputDevice(this, device)) { + // What to do if we are overridden and cannot change to our preferred device? + } + } + } + // 2. If we are not overridden, then we need to update our perception of what + // device we are using. If the devices do not match, something lower in the + // stack is overriding our preferences (e.g. a per-application stream preference, + // specific application move, priority list changed etc. etc.) + else if (!outputDeviceOverridden) { + const AudioOutputDevice ¤tDevice = AudioOutputDevice::fromIndex(deviceIndex); + if (currentDevice != device) { + // The device is not what we think it is, so lets say what is happening. + handleAutomaticDeviceChange(currentDevice, SoundSystemChange); + } + } + } +} + static struct { int first; @@ -405,11 +463,33 @@ void AudioOutputPrivate::handleAutomaticDeviceChange(const AudioOutputDevice &de g_lastFallback.second = 0; } break; + case SoundSystemChange: + { +#ifndef QT_NO_PHONON_PLATFORMPLUGIN + if (device1.property("available").toBool()) { + const QString text = AudioOutput::tr("Switching to the audio playback device %1
" + "which has higher preference or is specifically configured for this stream.").arg(device2.name()); + Platform::notification("AudioDeviceFallback", text, + QStringList(AudioOutput::tr("Revert back to device '%1'").arg(device1.name())), + q, SLOT(_k_revertFallback())); + } else { + const QString &text = + AudioOutput::tr("The audio playback device %1 does not work.
" + "Falling back to %2.").arg(device1.name()).arg(device2.name()); + Platform::notification("AudioDeviceFallback", text); + } +#endif //QT_NO_PHONON_PLATFORMPLUGIN + //outputDeviceOverridden = true; + g_lastFallback.first = 0; + g_lastFallback.second = 0; + } + break; } } AudioOutputPrivate::~AudioOutputPrivate() { + PulseSupport::getInstance()->clearStreamCache(streamUuid); #ifndef QT_NO_DBUS if (adaptor) { emit adaptor->outputDestroyed(); diff --git a/src/3rdparty/phonon/phonon/audiooutput.h b/src/3rdparty/phonon/phonon/audiooutput.h index 4edf135..513a863 100644 --- a/src/3rdparty/phonon/phonon/audiooutput.h +++ b/src/3rdparty/phonon/phonon/audiooutput.h @@ -169,6 +169,7 @@ namespace Phonon Q_PRIVATE_SLOT(k_func(), void _k_revertFallback()) Q_PRIVATE_SLOT(k_func(), void _k_audioDeviceFailed()) Q_PRIVATE_SLOT(k_func(), void _k_deviceListChanged()) + Q_PRIVATE_SLOT(k_func(), void _k_deviceChanged(QString streamUuid, int device)) }; } //namespace Phonon diff --git a/src/3rdparty/phonon/phonon/audiooutput_p.h b/src/3rdparty/phonon/phonon/audiooutput_p.h index fdee299..01dc48f 100644 --- a/src/3rdparty/phonon/phonon/audiooutput_p.h +++ b/src/3rdparty/phonon/phonon/audiooutput_p.h @@ -46,6 +46,7 @@ class AudioOutputPrivate : public AbstractAudioOutputPrivate return 0; } void init(Phonon::Category c); + QString getStreamUuid(); protected: @@ -58,6 +59,7 @@ class AudioOutputPrivate : public AbstractAudioOutputPrivate #endif deviceBeforeFallback(-1), outputDeviceOverridden(false), + forceMove(false), muted(false) { } @@ -66,7 +68,8 @@ class AudioOutputPrivate : public AbstractAudioOutputPrivate enum DeviceChangeType { FallbackChange, - HigherPreferenceChange + HigherPreferenceChange, + SoundSystemChange }; void handleAutomaticDeviceChange(const AudioOutputDevice &newDev, DeviceChangeType type); @@ -74,17 +77,20 @@ class AudioOutputPrivate : public AbstractAudioOutputPrivate void _k_revertFallback(); void _k_audioDeviceFailed(); void _k_deviceListChanged(); + void _k_deviceChanged(QString streamUuid, int deviceIndex); private: QString name; Phonon::AudioOutputDevice device; qreal volume; + QString streamUuid; #ifndef QT_NO_DBUS Phonon::AudioOutputAdaptor *adaptor; #endif Category category; int deviceBeforeFallback; bool outputDeviceOverridden; + bool forceMove; bool muted; }; } //namespace Phonon diff --git a/src/3rdparty/phonon/phonon/audiooutputinterface.h b/src/3rdparty/phonon/phonon/audiooutputinterface.h index 80ba11c..cce12b2 100644 --- a/src/3rdparty/phonon/phonon/audiooutputinterface.h +++ b/src/3rdparty/phonon/phonon/audiooutputinterface.h @@ -64,7 +64,7 @@ class AudioOutputInterface40 * A value of 0.0 means muted, 1.0 means unchanged, 2.0 means double voltage (i.e. all * samples are multiplied by 2). * - * Everytime the volume in the backend changes it should emit volumeChanged(qreal), also + * Every time the volume in the backend changes it should emit volumeChanged(qreal), also * inside this function. */ virtual void setVolume(qreal) = 0; diff --git a/src/3rdparty/phonon/phonon/backendcapabilities.cpp b/src/3rdparty/phonon/phonon/backendcapabilities.cpp index fbeb020..8dad589 100644 --- a/src/3rdparty/phonon/phonon/backendcapabilities.cpp +++ b/src/3rdparty/phonon/phonon/backendcapabilities.cpp @@ -26,7 +26,7 @@ #include "phonondefs_p.h" #include "backendinterface.h" #include "factory_p.h" -#include "globalconfig_p.h" +#include "globalconfig.h" #include "globalstatic_p.h" #include "objectdescription.h" diff --git a/src/3rdparty/phonon/phonon/factory.cpp b/src/3rdparty/phonon/phonon/factory.cpp index 9967c971..24be0f3 100644 --- a/src/3rdparty/phonon/phonon/factory.cpp +++ b/src/3rdparty/phonon/phonon/factory.cpp @@ -134,30 +134,24 @@ bool FactoryPrivate::createBackend() continue; } - QStringList plugins(dir.entryList(QDir::Files)); + QStringList plugins(dir.entryList(QDir::Files)); #ifdef Q_OS_SYMBIAN /* On Symbian OS we might have two plugins, one which uses Symbian - * MMF framework("phonon_mmf"), and one which uses Real Networks's + * MMF framework("mmf"), and one which uses Real Networks's * Helix("hxphonon"). We prefer the latter because it's more * sophisticated, so we make sure the Helix backend is attempted * to be loaded first, and the MMF backend is used for backup. */ { - - const int hxphonon = plugins.indexOf(QLatin1String("hxphonon")); - if (hxphonon != -1) - plugins.move(hxphonon, 0); - - // Code for debugging the MMF backend. - if(hxphonon != -1) { - qDebug() << "Found hxphonon backend and removed it from the lookup list."; - plugins.removeAll(QLatin1String("hxphonon")); - } + const int helix = plugins.indexof(QLatin1String("hxphonon")); + if (helix != -1) + plugins.move(helix, 0); } #endif - for (int i = 0; i < plugins.count(); ++i) { - QPluginLoader pluginLoader(libPath + plugins.at(i)); + const QStringList files = dir.entryList(QDir::Files); + for (int i = 0; i < files.count(); ++i) { + QPluginLoader pluginLoader(libPath + files.at(i)); if (!pluginLoader.load()) { pDebug() << Q_FUNC_INFO << " load failed:" << pluginLoader.errorString(); @@ -350,6 +344,7 @@ FACTORY_IMPL(AudioOutput) #ifndef QT_NO_PHONON_VIDEO FACTORY_IMPL(VideoWidget) #endif //QT_NO_PHONON_VIDEO +FACTORY_IMPL(AudioDataOutput) #undef FACTORY_IMPL @@ -469,7 +464,7 @@ GET_STRING_PROPERTY(backendWebsite) QObject *Factory::registerQObject(QObject *o) { if (o) { - QObject::connect(o, SIGNAL(destroyed(QObject*)), globalFactory, SLOT(objectDestroyed(QObject*)), Qt::DirectConnection); + QObject::connect(o, SIGNAL(destroyed(QObject *)), globalFactory, SLOT(objectDestroyed(QObject *)), Qt::DirectConnection); globalFactory->objects.append(o); } return o; diff --git a/src/3rdparty/phonon/phonon/factory_p.h b/src/3rdparty/phonon/phonon/factory_p.h index dee2b56..41b8c5b 100644 --- a/src/3rdparty/phonon/phonon/factory_p.h +++ b/src/3rdparty/phonon/phonon/factory_p.h @@ -122,6 +122,13 @@ namespace Factory #endif //QT_NO_PHONON_VIDEO /** + * Create a new backend object for a AudioDataOutput. + * + * \return a pointer to the AudioDataOutput the backend provides. + */ + PHONON_EXPORT QObject *createAudioDataOutput(QObject *parent = 0); + + /** * \return a pointer to the backend interface. */ PHONON_EXPORT QObject *backend(bool createWhenNull = true); diff --git a/src/3rdparty/phonon/phonon/globalconfig.cpp b/src/3rdparty/phonon/phonon/globalconfig.cpp index 3b77a18..be751ce 100644 --- a/src/3rdparty/phonon/phonon/globalconfig.cpp +++ b/src/3rdparty/phonon/phonon/globalconfig.cpp @@ -20,6 +20,7 @@ */ +#include "globalconfig.h" #include "globalconfig_p.h" #include "factory_p.h" @@ -29,6 +30,7 @@ #include "backendinterface.h" #include "qsettingsgroup_p.h" #include "phononnamespace_p.h" +#include "pulsesupport.h" #include #include @@ -38,15 +40,18 @@ QT_BEGIN_NAMESPACE namespace Phonon { +GlobalConfigPrivate::GlobalConfigPrivate() : config(QLatin1String("kde.org"), QLatin1String("libphonon")) +{ +} + GlobalConfig::GlobalConfig() -#ifndef QT_NO_SETTINGS - : m_config(QLatin1String("kde.org"), QLatin1String("libphonon")) -#endif //QT_NO_SETTINGS + : k_ptr(new GlobalConfigPrivate) { } GlobalConfig::~GlobalConfig() { + delete k_ptr; } enum WhatToFilter { @@ -59,7 +64,11 @@ static void filter(ObjectDescriptionType type, BackendInterface *backendIface, Q { QMutableListIterator it(*list); while (it.hasNext()) { - const QHash properties = backendIface->objectDescriptionProperties(type, it.next()); + QHash properties; + if (backendIface) + properties = backendIface->objectDescriptionProperties(type, it.next()); + else + properties = PulseSupport::getInstance()->objectDescriptionProperties(type, it.next()); QVariant var; if (whatToFilter & FilterAdvancedDevices) { var = properties.value("isAdvanced"); @@ -73,6 +82,7 @@ static void filter(ObjectDescriptionType type, BackendInterface *backendIface, Q if (var.isValid() && var.toBool()) { it.remove(); continue; +#ifndef QT_NO_PHONON_SETTINGSGROUP } } if (whatToFilter & FilterUnavailableDevices) { @@ -85,9 +95,12 @@ static void filter(ObjectDescriptionType type, BackendInterface *backendIface, Q } } -#ifndef QT_NO_PHONON_SETTINGSGROUP -static QList listSortedByConfig(const QSettingsGroup &backendConfig, Phonon::Category category, QList &defaultList) +static QList sortDevicesByCategoryPriority(const GlobalConfig *config, const QSettingsGroup *backendConfig, ObjectDescriptionType type, Phonon::Category category, QList &defaultList) { + Q_ASSERT(config); + Q_ASSERT(backendConfig); + Q_ASSERT(type == AudioOutputDeviceType || type == AudioCaptureDeviceType); + if (defaultList.size() <= 1) { // nothing to sort return defaultList; @@ -104,20 +117,26 @@ static QList listSortedByConfig(const QSettingsGroup &backendConfig, Phonon } } - QString categoryKey = QLatin1String("Category_") + QString::number(static_cast(category)); - if (!backendConfig.hasKey(categoryKey)) { - // no list in config for the given category - categoryKey = QLatin1String("Category_") + QString::number(static_cast(Phonon::NoCategory)); - if (!backendConfig.hasKey(categoryKey)) { - // no list in config for NoCategory - return defaultList; + QList deviceList; + PulseSupport *pulse = PulseSupport::getInstance(); + if (pulse->isActive()) { + deviceList = pulse->objectIndexesByCategory(type, category); + } else { + QString categoryKey = QLatin1String("Category_") + QString::number(static_cast(category)); + if (!backendConfig->hasKey(categoryKey)) { + // no list in config for the given category + categoryKey = QLatin1String("Category_") + QString::number(static_cast(Phonon::NoCategory)); + if (!backendConfig->hasKey(categoryKey)) { + // no list in config for NoCategory + return defaultList; + } } - } - //Now the list from m_config - QList deviceList = backendConfig.value(categoryKey, QList()); + //Now the list from d->config + deviceList = backendConfig->value(categoryKey, QList()); + } - //if there are devices in m_config that the backend doesn't report, remove them from the list + //if there are devices in d->config that the backend doesn't report, remove them from the list QMutableListIterator i(deviceList); while (i.hasNext()) { if (0 == defaultList.removeAll(i.next())) { @@ -125,58 +144,198 @@ static QList listSortedByConfig(const QSettingsGroup &backendConfig, Phonon } } - //if the backend reports more devices that are not in m_config append them to the list + //if the backend reports more devices that are not in d->config append them to the list deviceList += defaultList; return deviceList; } + +bool GlobalConfig::hideAdvancedDevices() const +{ + K_D(const GlobalConfig); + //The devices need to be stored independently for every backend + const QSettingsGroup generalGroup(&d->config, QLatin1String("General")); + return generalGroup.value(QLatin1String("HideAdvancedDevices"), true); +} + +void GlobalConfig::setHideAdvancedDevices(bool hide) +{ + K_D(GlobalConfig); + QSettingsGroup generalGroup(&d->config, QLatin1String("General")); + generalGroup.setValue(QLatin1String("HideAdvancedDevices"), hide); +} + +static bool isHiddenAudioOutputDevice(const GlobalConfig *config, int i) +{ + Q_ASSERT(config); + + if (!config->hideAdvancedDevices()) + return false; + + AudioOutputDevice ad = AudioOutputDevice::fromIndex(i); + const QVariant var = ad.property("isAdvanced"); + return (var.isValid() && var.toBool()); +} + +#ifndef QT_NO_PHONON_AUDIOCAPTURE +static bool isHiddenAudioCaptureDevice(const GlobalConfig *config, int i) +{ + Q_ASSERT(config); + + if (!config->hideAdvancedDevices()) + return false; + + AudioCaptureDevice ad = AudioCaptureDevice::fromIndex(i); + const QVariant var = ad.property("isAdvanced"); + return (var.isValid() && var.toBool()); +} +#endif + +static QList reindexList(const GlobalConfig *config, Phonon::Category category, QListnewOrder, bool output) +{ + Q_ASSERT(config); +#ifdef QT_NO_PHONON_AUDIOCAPTURE + Q_ASSERT(output); +#endif + + /*QString sb; + sb = QString("(Size %1)").arg(currentList.size()); + foreach (int i, currentList) + sb += QString("%1, ").arg(i); + fprintf(stderr, "=== Reindex Current: %s\n", sb.toUtf8().constData()); + sb = QString("(Size %1)").arg(newOrder.size()); + foreach (int i, newOrder) + sb += QString("%1, ").arg(i); + fprintf(stderr, "=== Reindex Before : %s\n", sb.toUtf8().constData());*/ + + QList currentList; + if (output) + currentList = config->audioOutputDeviceListFor(category, GlobalConfig::ShowUnavailableDevices|GlobalConfig::ShowAdvancedDevices); +#ifndef QT_NO_PHONON_AUDIOCAPTURE + else + currentList = config->audioCaptureDeviceListFor(category, GlobalConfig::ShowUnavailableDevices|GlobalConfig::ShowAdvancedDevices); +#endif + + QList newList; + + foreach (int i, newOrder) { + int found = currentList.indexOf(i); + if (found < 0) { + // It's not in the list, so something is odd (e.g. client error). Ignore it. + continue; + } + + // Iterate through the list from this point onward. If there are hidden devices + // immediately following, take them too. + newList.append(currentList.takeAt(found)); + while (found < currentList.size()) { + bool hidden = true; + if (output) + hidden = isHiddenAudioOutputDevice(config, currentList.at(found)); +#ifndef QT_NO_PHONON_AUDIOCAPTURE + else + hidden = isHiddenAudioCaptureDevice(config, currentList.at(found)); +#endif + + if (!hidden) + break; + newList.append(currentList.takeAt(found)); + } + } + + // If there are any devices left in.. just tack them on the end. + if (currentList.size() > 0) + newList += currentList; + + /*sb = QString("(Size %1)").arg(newList.size()); + foreach (int i, newList) + sb += QString("%1, ").arg(i); + fprintf(stderr, "=== Reindex After : %s\n", sb.toUtf8().constData());*/ + return newList; +} + + +void GlobalConfig::setAudioOutputDeviceListFor(Phonon::Category category, QList order) +{ + PulseSupport *pulse = PulseSupport::getInstance(); + if (pulse->isActive()) { + pulse->setOutputDevicePriorityForCategory(category, order); + return; + } + + K_D(GlobalConfig); + QSettingsGroup backendConfig(&d->config, QLatin1String("AudioOutputDevice")); // + Factory::identifier()); + + order = reindexList(this, category, order, true); + + const QList noCategoryOrder = audioOutputDeviceListFor(Phonon::NoCategory, ShowUnavailableDevices|ShowAdvancedDevices); + if (category != Phonon::NoCategory && order == noCategoryOrder) { + backendConfig.removeEntry(QLatin1String("Category_") + QString::number(category)); + } else { + backendConfig.setValue(QLatin1String("Category_") + QString::number(category), order); + } +} #endif //QT_NO_PHONON_SETTINGSGROUP #ifndef QT_NO_PHONON_SETTINGSGROUP QList GlobalConfig::audioOutputDeviceListFor(Phonon::Category category, int override) const { - //The devices need to be stored independently for every backend - const QSettingsGroup backendConfig(&m_config, QLatin1String("AudioOutputDevice")); // + Factory::identifier()); - const QSettingsGroup generalGroup(&m_config, QLatin1String("General")); - const bool hideAdvancedDevices = ((override & AdvancedDevicesFromSettings) - ? generalGroup.value(QLatin1String("HideAdvancedDevices"), true) + K_D(const GlobalConfig); + + const bool hide = ((override & AdvancedDevicesFromSettings) + ? hideAdvancedDevices() : static_cast(override & HideAdvancedDevices)); QList defaultList; + + PulseSupport *pulse = PulseSupport::getInstance(); + if (pulse->isActive()) { + defaultList = pulse->objectDescriptionIndexes(Phonon::AudioOutputDeviceType); + if (hide || (override & HideUnavailableDevices)) { + filter(AudioOutputDeviceType, NULL, &defaultList, + (hide ? FilterAdvancedDevices : 0) + | ((override & HideUnavailableDevices) ? FilterUnavailableDevices : 0) + ); + } + } else { + BackendInterface *backendIface = qobject_cast(Factory::backend()); + #ifndef QT_NO_PHONON_PLATFORMPLUGIN - if (PlatformPlugin *platformPlugin = Factory::platformPlugin()) { - // the platform plugin lists the audio devices for the platform - // this list already is in default order (as defined by the platform plugin) - defaultList = platformPlugin->objectDescriptionIndexes(Phonon::AudioOutputDeviceType); - if (hideAdvancedDevices) { - QMutableListIterator it(defaultList); - while (it.hasNext()) { - AudioOutputDevice objDesc = AudioOutputDevice::fromIndex(it.next()); - const QVariant var = objDesc.property("isAdvanced"); - if (var.isValid() && var.toBool()) { - it.remove(); + if (PlatformPlugin *platformPlugin = Factory::platformPlugin()) { + // the platform plugin lists the audio devices for the platform + // this list already is in default order (as defined by the platform plugin) + defaultList = platformPlugin->objectDescriptionIndexes(Phonon::AudioOutputDeviceType); + if (hide) { + QMutableListIterator it(defaultList); + while (it.hasNext()) { + AudioOutputDevice objDesc = AudioOutputDevice::fromIndex(it.next()); + const QVariant var = objDesc.property("isAdvanced"); + if (var.isValid() && var.toBool()) { + it.remove(); + } } } } - } #endif //QT_NO_PHONON_PLATFORMPLUGIN - // lookup the available devices directly from the backend (mostly for virtual devices) - if (BackendInterface *backendIface = qobject_cast(Factory::backend())) { - // this list already is in default order (as defined by the backend) - QList list = backendIface->objectDescriptionIndexes(Phonon::AudioOutputDeviceType); - if (hideAdvancedDevices || !defaultList.isEmpty() || (override & HideUnavailableDevices)) { - filter(AudioOutputDeviceType, backendIface, &list, - (hideAdvancedDevices ? FilterAdvancedDevices : 0) - // the platform plugin already provided the hardware devices - | (defaultList.isEmpty() ? 0 : FilterHardwareDevices) - | ((override & HideUnavailableDevices) ? FilterUnavailableDevices : 0) - ); + // lookup the available devices directly from the backend + if (backendIface) { + // this list already is in default order (as defined by the backend) + QList list = backendIface->objectDescriptionIndexes(Phonon::AudioOutputDeviceType); + if (hide || !defaultList.isEmpty() || (override & HideUnavailableDevices)) { + filter(AudioOutputDeviceType, backendIface, &list, + (hide ? FilterAdvancedDevices : 0) + // the platform plugin maybe already provided the hardware devices? + | (defaultList.isEmpty() ? 0 : FilterHardwareDevices) + | ((override & HideUnavailableDevices) ? FilterUnavailableDevices : 0) + ); + } + defaultList += list; } - defaultList += list; } - return listSortedByConfig(backendConfig, category, defaultList); + const QSettingsGroup backendConfig(&d->config, QLatin1String("AudioOutputDevice")); // + Factory::identifier()); + return sortDevicesByCategoryPriority(this, &backendConfig, AudioOutputDeviceType, category, defaultList); } #endif //QT_NO_PHONON_SETTINGSGROUP int GlobalConfig::audioOutputDeviceFor(Phonon::Category category, int override) const @@ -190,54 +349,89 @@ int GlobalConfig::audioOutputDeviceFor(Phonon::Category category, int override) } #ifndef QT_NO_PHONON_AUDIOCAPTURE -QList GlobalConfig::audioCaptureDeviceListFor(Phonon::Category category, int override) const +void GlobalConfig::setAudioCaptureDeviceListFor(Phonon::Category category, QList order) { #ifndef QT_NO_PHONON_SETTINGSGROUP - //The devices need to be stored independently for every backend - const QSettingsGroup backendConfig(&m_config, QLatin1String("AudioCaptureDevice")); // + Factory::identifier()); - const QSettingsGroup generalGroup(&m_config, QLatin1String("General")); - const bool hideAdvancedDevices = ((override & AdvancedDevicesFromSettings) - ? generalGroup.value(QLatin1String("HideAdvancedDevices"), true) + PulseSupport *pulse = PulseSupport::getInstance(); + if (pulse->isActive()) { + pulse->setCaptureDevicePriorityForCategory(category, order); + return; + } + + K_D(GlobalConfig); + QSettingsGroup backendConfig(&d->config, QLatin1String("AudioCaptureDevice")); // + Factory::identifier()); + + order = reindexList(this, category, order, false); + + const QList noCategoryOrder = audioCaptureDeviceListFor(Phonon::NoCategory, ShowUnavailableDevices|ShowAdvancedDevices); + if (category != Phonon::NoCategory && order == noCategoryOrder) { + backendConfig.removeEntry(QLatin1String("Category_") + QString::number(category)); + } else { + backendConfig.setValue(QLatin1String("Category_") + QString::number(category), order); + } +} + +QList GlobalConfig::audioCaptureDeviceListFor(Phonon::Category category, int override) const +{ + K_D(const GlobalConfig); + + const bool hide = ((override & AdvancedDevicesFromSettings) + ? hideAdvancedDevices() : static_cast(override & HideAdvancedDevices)); QList defaultList; + + PulseSupport *pulse = PulseSupport::getInstance(); + if (pulse->isActive()) { + defaultList = pulse->objectDescriptionIndexes(Phonon::AudioCaptureDeviceType); + if (hide || (override & HideUnavailableDevices)) { + filter(AudioCaptureDeviceType, NULL, &defaultList, + (hide ? FilterAdvancedDevices : 0) + | ((override & HideUnavailableDevices) ? FilterUnavailableDevices : 0) + ); + } + } else { + BackendInterface *backendIface = qobject_cast(Factory::backend()); + #ifndef QT_NO_PHONON_PLATFORMPLUGIN - if (PlatformPlugin *platformPlugin = Factory::platformPlugin()) { - // the platform plugin lists the audio devices for the platform - // this list already is in default order (as defined by the platform plugin) - defaultList = platformPlugin->objectDescriptionIndexes(Phonon::AudioCaptureDeviceType); - if (hideAdvancedDevices) { - QMutableListIterator it(defaultList); - while (it.hasNext()) { - AudioCaptureDevice objDesc = AudioCaptureDevice::fromIndex(it.next()); - const QVariant var = objDesc.property("isAdvanced"); - if (var.isValid() && var.toBool()) { - it.remove(); +#else //QT_NO_SETTINGSGROUP + return QList(); +#endif //QT_NO_SETTINGSGROUP + if (PlatformPlugin *platformPlugin = Factory::platformPlugin()) { + // the platform plugin lists the audio devices for the platform + // this list already is in default order (as defined by the platform plugin) + defaultList = platformPlugin->objectDescriptionIndexes(Phonon::AudioCaptureDeviceType); + if (hide) { + QMutableListIterator it(defaultList); + while (it.hasNext()) { + AudioCaptureDevice objDesc = AudioCaptureDevice::fromIndex(it.next()); + const QVariant var = objDesc.property("isAdvanced"); + if (var.isValid() && var.toBool()) { + it.remove(); + } } } } - } #endif //QT_NO_PHONON_PLATFORMPLUGIN - // lookup the available devices directly from the backend (mostly for virtual devices) - if (BackendInterface *backendIface = qobject_cast(Factory::backend())) { - // this list already is in default order (as defined by the backend) - QList list = backendIface->objectDescriptionIndexes(Phonon::AudioCaptureDeviceType); - if (hideAdvancedDevices || !defaultList.isEmpty() || (override & HideUnavailableDevices)) { - filter(AudioCaptureDeviceType, backendIface, &list, - (hideAdvancedDevices ? FilterAdvancedDevices : 0) - // the platform plugin already provided the hardware devices - | (defaultList.isEmpty() ? 0 : FilterHardwareDevices) - | ((override & HideUnavailableDevices) ? FilterUnavailableDevices : 0) - ); + // lookup the available devices directly from the backend + if (backendIface) { + // this list already is in default order (as defined by the backend) + QList list = backendIface->objectDescriptionIndexes(Phonon::AudioCaptureDeviceType); + if (hide || !defaultList.isEmpty() || (override & HideUnavailableDevices)) { + filter(AudioCaptureDeviceType, backendIface, &list, + (hide ? FilterAdvancedDevices : 0) + // the platform plugin maybe already provided the hardware devices? + | (defaultList.isEmpty() ? 0 : FilterHardwareDevices) + | ((override & HideUnavailableDevices) ? FilterUnavailableDevices : 0) + ); + } + defaultList += list; } - defaultList += list; } - return listSortedByConfig(backendConfig, category, defaultList); -#else //QT_NO_SETTINGSGROUP - return QList(); -#endif //QT_NO_SETTINGSGROUP + const QSettingsGroup backendConfig(&d->config, QLatin1String("AudioCaptureDevice")); // + Factory::identifier()); + return sortDevicesByCategoryPriority(this, &backendConfig, AudioCaptureDeviceType, category, defaultList); } int GlobalConfig::audioCaptureDeviceFor(Phonon::Category category, int override) const diff --git a/src/3rdparty/phonon/phonon/globalconfig_p.h b/src/3rdparty/phonon/phonon/globalconfig_p.h index ec70b6f..090ca6b 100644 --- a/src/3rdparty/phonon/phonon/globalconfig_p.h +++ b/src/3rdparty/phonon/phonon/globalconfig_p.h @@ -26,40 +26,19 @@ Copyright (C) 2006-2008 Matthias Kretz #include #include "phonon_export.h" -#include "phononnamespace.h" QT_BEGIN_HEADER QT_BEGIN_NAMESPACE namespace Phonon { - class PHONON_EXPORT GlobalConfig + class GlobalConfigPrivate { - public: - GlobalConfig(); - virtual ~GlobalConfig(); + public: + GlobalConfigPrivate(); + virtual ~GlobalConfigPrivate() {} - enum DevicesToHideFlag { - ShowUnavailableDevices = 0, - ShowAdvancedDevices = 0, - HideAdvancedDevices = 1, - AdvancedDevicesFromSettings = 2, - HideUnavailableDevices = 4 - }; -#ifndef QT_NO_PHONON_SETTINGSGROUP - QList audioOutputDeviceListFor(Phonon::Category category, int override = AdvancedDevicesFromSettings) const; -#endif //QT_NO_PHONON_SETTINGSGROUP - int audioOutputDeviceFor(Phonon::Category category, int override = AdvancedDevicesFromSettings) const; - -#ifndef QT_NO_PHONON_AUDIOCAPTURE - QList audioCaptureDeviceListFor(Phonon::Category category, int override = AdvancedDevicesFromSettings) const; - int audioCaptureDeviceFor(Phonon::Category category, int override = AdvancedDevicesFromSettings) const; -#endif //QT_NO_PHONON_AUDIOCAPTURE - - protected: -#ifndef QT_NO_SETTINGS - QSettings m_config; -#endif //QT_NO_SETTINGS + QSettings config; }; } // namespace Phonon diff --git a/src/3rdparty/phonon/phonon/mediaobject.cpp b/src/3rdparty/phonon/phonon/mediaobject.cpp index 41e8dc2..13d303c 100644 --- a/src/3rdparty/phonon/phonon/mediaobject.cpp +++ b/src/3rdparty/phonon/phonon/mediaobject.cpp @@ -453,9 +453,9 @@ void MediaObjectPrivate::setupBackendObject() //pDebug() << Q_FUNC_INFO; #ifndef QT_NO_PHONON_ABSTRACTMEDIASTREAM - QObject::connect(m_backendObject, SIGNAL(stateChanged(Phonon::State,Phonon::State)), q, SLOT(_k_stateChanged(Phonon::State,Phonon::State))); + QObject::connect(m_backendObject, SIGNAL(stateChanged(Phonon::State, Phonon::State)), q, SLOT(_k_stateChanged(Phonon::State, Phonon::State))); #else - QObject::connect(m_backendObject, SIGNAL(stateChanged(Phonon::State,Phonon::State)), q, SIGNAL(stateChanged(Phonon::State,Phonon::State))); + QObject::connect(m_backendObject, SIGNAL(stateChanged(Phonon::State, Phonon::State)), q, SIGNAL(stateChanged(Phonon::State, Phonon::State))); #endif // QT_NO_PHONON_ABSTRACTMEDIASTREAM QObject::connect(m_backendObject, SIGNAL(tick(qint64)), q, SIGNAL(tick(qint64))); QObject::connect(m_backendObject, SIGNAL(seekableChanged(bool)), q, SIGNAL(seekableChanged(bool))); @@ -467,10 +467,10 @@ void MediaObjectPrivate::setupBackendObject() QObject::connect(m_backendObject, SIGNAL(aboutToFinish()), q, SLOT(_k_aboutToFinish())); QObject::connect(m_backendObject, SIGNAL(prefinishMarkReached(qint32)), q, SIGNAL(prefinishMarkReached(qint32))); QObject::connect(m_backendObject, SIGNAL(totalTimeChanged(qint64)), q, SIGNAL(totalTimeChanged(qint64))); - QObject::connect(m_backendObject, SIGNAL(metaDataChanged(QMultiMap)), - q, SLOT(_k_metaDataChanged(QMultiMap))); - QObject::connect(m_backendObject, SIGNAL(currentSourceChanged(MediaSource)), - q, SLOT(_k_currentSourceChanged(MediaSource))); + QObject::connect(m_backendObject, SIGNAL(metaDataChanged(const QMultiMap &)), + q, SLOT(_k_metaDataChanged(const QMultiMap &))); + QObject::connect(m_backendObject, SIGNAL(currentSourceChanged(const MediaSource&)), + q, SLOT(_k_currentSourceChanged(const MediaSource&))); // set up attributes pINTERFACE_CALL(setTickInterval(tickInterval)); diff --git a/src/3rdparty/phonon/phonon/objectdescription.cpp b/src/3rdparty/phonon/phonon/objectdescription.cpp index e058b89..55e74b5 100644 --- a/src/3rdparty/phonon/phonon/objectdescription.cpp +++ b/src/3rdparty/phonon/phonon/objectdescription.cpp @@ -29,6 +29,7 @@ #include #include "backendinterface.h" #include "platformplugin.h" +#include "pulsesupport.h" QT_BEGIN_NAMESPACE @@ -108,27 +109,38 @@ bool ObjectDescriptionData::isValid() const ObjectDescriptionData *ObjectDescriptionData::fromIndex(ObjectDescriptionType type, int index) { - // prefer to get the ObjectDescriptionData from the platform plugin for audio devices + bool is_audio_device = (AudioOutputDeviceType == type || AudioCaptureDeviceType == type); + + PulseSupport *pulse = PulseSupport::getInstance(); + if (is_audio_device && pulse->isActive()) { + QList indexes = pulse->objectDescriptionIndexes(type); + if (indexes.contains(index)) { + QHash properties = pulse->objectDescriptionProperties(type, index); + return new ObjectDescriptionData(index, properties); + } + } else { + BackendInterface *iface = qobject_cast(Factory::backend()); + + // prefer to get the ObjectDescriptionData from the platform plugin for audio devices #ifndef QT_NO_PHONON_PLATFORMPLUGIN - if (type == AudioOutputDeviceType || type == AudioCaptureDeviceType) { - PlatformPlugin *platformPlugin = Factory::platformPlugin(); - if (platformPlugin) { - QList indexes = platformPlugin->objectDescriptionIndexes(type); - if (indexes.contains(index)) { - QHash properties = platformPlugin->objectDescriptionProperties(type, index); - return new ObjectDescriptionData(index, properties); + if (is_audio_device) { + PlatformPlugin *platformPlugin = Factory::platformPlugin(); + if (platformPlugin) { + QList indexes = platformPlugin->objectDescriptionIndexes(type); + if (indexes.contains(index)) { + QHash properties = platformPlugin->objectDescriptionProperties(type, index); + return new ObjectDescriptionData(index, properties); + } } } - } #endif //QT_NO_PHONON_PLATFORMPLUGIN - QObject *b = Factory::backend(); - BackendInterface *iface = qobject_cast(b); - if (iface) { - QList indexes = iface->objectDescriptionIndexes(type); - if (indexes.contains(index)) { - QHash properties = iface->objectDescriptionProperties(type, index); - return new ObjectDescriptionData(index, properties); + if (iface) { + QList indexes = iface->objectDescriptionIndexes(type); + if (indexes.contains(index)) { + QHash properties = iface->objectDescriptionProperties(type, index); + return new ObjectDescriptionData(index, properties); + } } } return new ObjectDescriptionData(0); // invalid diff --git a/src/3rdparty/phonon/phonon/objectdescriptionmodel.cpp b/src/3rdparty/phonon/phonon/objectdescriptionmodel.cpp index bf5be6d..741a74c 100644 --- a/src/3rdparty/phonon/phonon/objectdescriptionmodel.cpp +++ b/src/3rdparty/phonon/phonon/objectdescriptionmodel.cpp @@ -362,6 +362,7 @@ QStringList ObjectDescriptionModelData::mimeTypes(ObjectDescriptionType type) co return QStringList(QLatin1String("application/x-phonon-objectdescription") + QString::number(static_cast(type))); } +#if !defined(Q_CC_MSVC) || _MSC_VER > 1300 || defined(Q_CC_INTEL) || defined(Q_CC_MINGW) #define INSTANTIATE_META_FUNCTIONS(type) \ template const QMetaObject *ObjectDescriptionModel::metaObject() const; \ template void *ObjectDescriptionModel::qt_metacast(const char *) @@ -371,6 +372,7 @@ INSTANTIATE_META_FUNCTIONS(AudioCaptureDeviceType); INSTANTIATE_META_FUNCTIONS(EffectType); INSTANTIATE_META_FUNCTIONS(AudioChannelType); INSTANTIATE_META_FUNCTIONS(SubtitleType); +#endif /*INSTANTIATE_META_FUNCTIONS(VideoOutputDeviceType); INSTANTIATE_META_FUNCTIONS(VideoCaptureDeviceType); INSTANTIATE_META_FUNCTIONS(AudioCodecType); diff --git a/src/3rdparty/phonon/phonon/objectdescriptionmodel.h b/src/3rdparty/phonon/phonon/objectdescriptionmodel.h index 8fd622f..a1540e8 100644 --- a/src/3rdparty/phonon/phonon/objectdescriptionmodel.h +++ b/src/3rdparty/phonon/phonon/objectdescriptionmodel.h @@ -35,6 +35,18 @@ QT_BEGIN_NAMESPACE #ifndef QT_NO_PHONON_OBJECTDESCRIPTIONMODEL +/* MinGW 3.4.x gives an ICE when trying to instantiate one of the + ObjectDescriptionModel classes because it can't handle + half exported classes correct. gcc 4.3.x has a fix for this but + we currently there's no official gcc 4.3 on windows available. + Because of this we need this little hack + */ +#if defined(Q_CC_MINGW) +#define PHONON_EXPORT_ODM +#else +#define PHONON_EXPORT_ODM PHONON_EXPORT +#endif + namespace Phonon { class ObjectDescriptionModelDataPrivate; @@ -139,21 +151,6 @@ namespace Phonon ObjectDescriptionModelDataPrivate *const d; }; -/* Required to ensure template class vtables are exported on both symbian -and existing builds. */ -#if defined(Q_OS_SYMBIAN) && defined(Q_CC_RVCT) -// RVCT compiler (2.2.686) requires the export declaration to be on the class to export vtables -// MWC compiler works both ways -// GCCE compiler is unknown (it can't compile QtCore yet) -#define PHONON_TEMPLATE_CLASS_EXPORT PHONON_EXPORT -#define PHONON_TEMPLATE_CLASS_MEMBER_EXPORT -#else -// Windows builds (at least) do not support export declaration on templated class -// But if you export a member function, the vtable is implicitly exported -#define PHONON_TEMPLATE_CLASS_EXPORT -#define PHONON_TEMPLATE_CLASS_MEMBER_EXPORT PHONON_EXPORT -#endif - /** \class ObjectDescriptionModel objectdescriptionmodel.h Phonon/ObjectDescriptionModel * \short The ObjectDescriptionModel class provides a model from * a list of ObjectDescription objects. @@ -190,17 +187,16 @@ and existing builds. */ * \author Matthias Kretz */ template - class PHONON_TEMPLATE_CLASS_EXPORT ObjectDescriptionModel : public QAbstractListModel + class ObjectDescriptionModel : public QAbstractListModel { public: Q_OBJECT_CHECK - /** \internal */ - static PHONON_TEMPLATE_CLASS_MEMBER_EXPORT const QMetaObject staticMetaObject; + static PHONON_EXPORT const QMetaObject staticMetaObject; /** \internal */ - PHONON_TEMPLATE_CLASS_MEMBER_EXPORT const QMetaObject *metaObject() const; + PHONON_EXPORT_ODM const QMetaObject *metaObject() const; /** \internal */ - PHONON_TEMPLATE_CLASS_MEMBER_EXPORT void *qt_metacast(const char *_clname); + PHONON_EXPORT_ODM void *qt_metacast(const char *_clname); //int qt_metacall(QMetaObject::Call _c, int _id, void **_a); /** diff --git a/src/3rdparty/phonon/phonon/path.cpp b/src/3rdparty/phonon/phonon/path.cpp index 51c33b2..1c25b89 100644 --- a/src/3rdparty/phonon/phonon/path.cpp +++ b/src/3rdparty/phonon/phonon/path.cpp @@ -310,8 +310,8 @@ bool PathPrivate::executeTransaction( const QList &disconnections, if (!transaction) return false; - QList::const_iterator it = disconnections.constBegin(); - for(;it != disconnections.constEnd();++it) { + QList::const_iterator it = disconnections.begin(); + for(;it != disconnections.end();++it) { const QObjectPair &pair = *it; if (!backend->disconnectNodes(pair.first, pair.second)) { @@ -327,8 +327,8 @@ bool PathPrivate::executeTransaction( const QList &disconnections, } } - for(it = connections.constBegin(); it != connections.constEnd(); ++it) { - const QObjectPair pair = *it; + for(it = connections.begin(); it != connections.end();++it) { + const QObjectPair &pair = *it; if (!backend->connectNodes(pair.first, pair.second)) { //Error: a connection failed QList::const_iterator it2 = connections.begin(); diff --git a/src/3rdparty/phonon/phonon/phonondefs.h b/src/3rdparty/phonon/phonon/phonondefs.h index 15a1815..765eb1c 100644 --- a/src/3rdparty/phonon/phonon/phonondefs.h +++ b/src/3rdparty/phonon/phonon/phonondefs.h @@ -29,6 +29,11 @@ QT_BEGIN_HEADER QT_BEGIN_NAMESPACE +#ifdef PHONON_BACKEND_VERSION_4_4 +# ifndef PHONON_BACKEND_VERSION_4_3 +# define PHONON_BACKEND_VERSION_4_3 +# endif +#endif #ifdef PHONON_BACKEND_VERSION_4_3 # ifndef PHONON_BACKEND_VERSION_4_2 # define PHONON_BACKEND_VERSION_4_2 diff --git a/src/3rdparty/phonon/phonon/seekslider.cpp b/src/3rdparty/phonon/phonon/seekslider.cpp index 41baf2d..b5b25f0 100644 --- a/src/3rdparty/phonon/phonon/seekslider.cpp +++ b/src/3rdparty/phonon/phonon/seekslider.cpp @@ -72,12 +72,12 @@ void SeekSlider::setMediaObject(MediaObject *media) d->media = media; if (media) { - connect(media, SIGNAL(stateChanged(Phonon::State,Phonon::State)), + connect(media, SIGNAL(stateChanged(Phonon::State, Phonon::State)), SLOT(_k_stateChanged(Phonon::State))); connect(media, SIGNAL(totalTimeChanged(qint64)), SLOT(_k_length(qint64))); connect(media, SIGNAL(tick(qint64)), SLOT(_k_tick(qint64))); connect(media, SIGNAL(seekableChanged(bool)), SLOT(_k_seekableChanged(bool))); - connect(media, SIGNAL(currentSourceChanged(Phonon::MediaSource)), SLOT(_k_currentSourceChanged())); + connect(media, SIGNAL(currentSourceChanged(const Phonon::MediaSource&)), SLOT(_k_currentSourceChanged())); d->_k_stateChanged(media->state()); d->_k_seekableChanged(media->isSeekable()); d->_k_length(media->totalTime()); diff --git a/src/3rdparty/phonon/phonon/seekslider_p.h b/src/3rdparty/phonon/phonon/seekslider_p.h index c87a4b0..911ab25 100644 --- a/src/3rdparty/phonon/phonon/seekslider_p.h +++ b/src/3rdparty/phonon/phonon/seekslider_p.h @@ -24,8 +24,8 @@ #define SEEKSLIDER_P_H #include "seekslider.h" +#include "swiftslider_p.h" #include -#include #include #include #include @@ -84,7 +84,7 @@ class SeekSliderPrivate void _k_currentSourceChanged(); QBoxLayout layout; - QSlider slider; + SwiftSlider slider; QLabel iconLabel; QPointer media; bool ticking; diff --git a/src/3rdparty/phonon/phonon/videowidget.cpp b/src/3rdparty/phonon/phonon/videowidget.cpp index a9e83a6..4575dfd 100644 --- a/src/3rdparty/phonon/phonon/videowidget.cpp +++ b/src/3rdparty/phonon/phonon/videowidget.cpp @@ -28,8 +28,9 @@ #include "phononnamespace_p.h" #include - -#define PHONON_INTERFACENAME VideoWidgetInterface +#define IFACES4 VideoWidgetInterface44 +#define IFACES0 VideoWidgetInterface, IFACES4 +#define PHONON_INTERFACENAME IFACES0 QT_BEGIN_NAMESPACE @@ -48,6 +49,8 @@ VideoWidget::VideoWidget(QWidget *parent) setMouseTracking(true); } + + VideoWidget::VideoWidget(VideoWidgetPrivate &dd, QWidget *parent) : QWidget(parent), Phonon::AbstractVideoOutput(dd) @@ -98,6 +101,15 @@ PHONON_INTERFACE_SETTER(setHue, hue, qreal) PHONON_INTERFACE_GETTER(qreal, saturation, d->saturation) PHONON_INTERFACE_SETTER(setSaturation, saturation, qreal) + +QImage VideoWidget::snapshot() const { + K_D(const VideoWidget); + ConstIface iface(d); + if(iface) return iface->snapshot(); + return QImage(); // TODO not implemented in VideoInterface +} + + void VideoWidget::setFullScreen(bool newFullScreen) { pDebug() << Q_FUNC_INFO << newFullScreen; diff --git a/src/3rdparty/phonon/phonon/videowidget.h b/src/3rdparty/phonon/phonon/videowidget.h index 1d95490..804e61a 100644 --- a/src/3rdparty/phonon/phonon/videowidget.h +++ b/src/3rdparty/phonon/phonon/videowidget.h @@ -172,6 +172,7 @@ class AbstractVideoOutput; qreal contrast() const; qreal hue() const; qreal saturation() const; + QImage snapshot() const; //TODO: bar colors property public Q_SLOTS: diff --git a/src/3rdparty/phonon/phonon/videowidgetinterface.h b/src/3rdparty/phonon/phonon/videowidgetinterface.h index 3e6fd22..0c33956 100644 --- a/src/3rdparty/phonon/phonon/videowidgetinterface.h +++ b/src/3rdparty/phonon/phonon/videowidgetinterface.h @@ -53,8 +53,21 @@ class VideoWidgetInterface //X virtual int overlayCapabilities() const = 0; //X virtual bool createOverlay(QWidget *widget, int type) = 0; }; + +class VideoWidgetInterface44 : public VideoWidgetInterface +{ + public: + virtual QImage snapshot() const = 0; +}; } +#ifdef PHONON_BACKEND_VERSION_4_4 +namespace Phonon { typedef VideoWidgetInterface44 VideoWidgetInterfaceLatest; } +#else +namespace Phonon { typedef VideoWidgetInterface VideoWidgetInterfaceLatest; } +#endif + +Q_DECLARE_INTERFACE(Phonon::VideoWidgetInterface44, "VideoWidgetInterface44.phonon.kde.org") Q_DECLARE_INTERFACE(Phonon::VideoWidgetInterface, "VideoWidgetInterface3.phonon.kde.org") #endif //QT_NO_PHONON_VIDEO diff --git a/src/3rdparty/phonon/phonon/volumeslider_p.h b/src/3rdparty/phonon/phonon/volumeslider_p.h index 3827659..623275f 100644 --- a/src/3rdparty/phonon/phonon/volumeslider_p.h +++ b/src/3rdparty/phonon/phonon/volumeslider_p.h @@ -24,8 +24,8 @@ #define VOLUMESLIDER_P_H #include "volumeslider.h" +#include "swiftslider_p.h" #include -#include #include #include #include @@ -83,7 +83,7 @@ class VolumeSliderPrivate private: QBoxLayout layout; - QSlider slider; + SwiftSlider slider; QToolButton muteButton; QIcon volumeIcon; QIcon mutedIcon; diff --git a/src/phonon/phonon.pro b/src/phonon/phonon.pro index 0469839..7f79d0b 100644 --- a/src/phonon/phonon.pro +++ b/src/phonon/phonon.pro @@ -2,8 +2,8 @@ TARGET = phonon include(../qbase.pri) PHONON_MAJOR_VERSION = $${QT_MAJOR_VERSION} -PHONON_MINOR_VERSION = 3 -PHONON_PATCH_VERSION = 1 +PHONON_MINOR_VERSION = 4 +PHONON_PATCH_VERSION = 0 VERSION = $${PHONON_MAJOR_VERSION}.$${PHONON_MINOR_VERSION}.$${PHONON_PATCH_VERSION} DEPENDPATH += . @@ -21,6 +21,9 @@ HEADERS += $$PHONON_DIR/abstractaudiooutput.h \ $$PHONON_DIR/abstractvideooutput.h \ $$PHONON_DIR/abstractvideooutput_p.h \ $$PHONON_DIR/addoninterface.h \ + $$PHONON_DIR/audiodataoutput_p.h \ + $$PHONON_DIR/audiodataoutput.h \ + $$PHONON_DIR/audiodataoutputinterface.h \ $$PHONON_DIR/audiooutput.h \ $$PHONON_DIR/audiooutput_p.h \ $$PHONON_DIR/audiooutputinterface.h \ @@ -36,6 +39,7 @@ HEADERS += $$PHONON_DIR/abstractaudiooutput.h \ $$PHONON_DIR/effectwidget_p.h \ $$PHONON_DIR/factory_p.h \ $$PHONON_DIR/frontendinterface_p.h \ + $$PHONON_DIR/globalconfig.h \ $$PHONON_DIR/globalconfig_p.h \ $$PHONON_DIR/iodevicestream_p.h \ $$PHONON_DIR/mediacontroller.h \ @@ -53,6 +57,7 @@ HEADERS += $$PHONON_DIR/abstractaudiooutput.h \ $$PHONON_DIR/objectdescriptionmodel_p.h \ $$PHONON_DIR/path.h \ $$PHONON_DIR/path_p.h \ + $$PHONON_DIR/pulsesupport.h \ $$PHONON_DIR/phonondefs.h \ $$PHONON_DIR/phonondefs_p.h \ $$PHONON_DIR/phononnamespace.h \ @@ -64,6 +69,7 @@ HEADERS += $$PHONON_DIR/abstractaudiooutput.h \ $$PHONON_DIR/seekslider_p.h \ $$PHONON_DIR/streaminterface.h \ $$PHONON_DIR/streaminterface_p.h \ + $$PHONON_DIR/swiftslider_p.h \ $$PHONON_DIR/videoplayer.h \ $$PHONON_DIR/videowidget.h \ $$PHONON_DIR/videowidget_p.h \ @@ -73,35 +79,39 @@ HEADERS += $$PHONON_DIR/abstractaudiooutput.h \ $$PHONON_DIR/volumefaderinterface.h \ $$PHONON_DIR/volumeslider.h \ $$PHONON_DIR/volumeslider_p.h -SOURCES += $$PHONON_DIR/objectdescription.cpp \ - $$PHONON_DIR/objectdescriptionmodel.cpp \ - $$PHONON_DIR/phononnamespace.cpp \ - $$PHONON_DIR/mediasource.cpp \ - $$PHONON_DIR/abstractmediastream.cpp \ - $$PHONON_DIR/streaminterface.cpp \ - $$PHONON_DIR/mediaobject.cpp \ - $$PHONON_DIR/medianode.cpp \ - $$PHONON_DIR/path.cpp \ - $$PHONON_DIR/effectparameter.cpp \ - $$PHONON_DIR/effect.cpp \ - $$PHONON_DIR/volumefadereffect.cpp \ - $$PHONON_DIR/abstractaudiooutput.cpp \ + +SOURCES += $$PHONON_DIR/abstractaudiooutput.cpp \ $$PHONON_DIR/abstractaudiooutput_p.cpp \ - $$PHONON_DIR/audiooutput.cpp \ - $$PHONON_DIR/audiooutputinterface.cpp \ + $$PHONON_DIR/abstractmediastream.cpp \ $$PHONON_DIR/abstractvideooutput.cpp \ $$PHONON_DIR/abstractvideooutput_p.cpp \ + $$PHONON_DIR/audiodataoutput.cpp \ + $$PHONON_DIR/audiooutput.cpp \ + $$PHONON_DIR/audiooutputinterface.cpp \ $$PHONON_DIR/backendcapabilities.cpp \ - $$PHONON_DIR/globalconfig.cpp \ + $$PHONON_DIR/effect.cpp \ + $$PHONON_DIR/effectparameter.cpp \ + $$PHONON_DIR/effectwidget.cpp \ $$PHONON_DIR/factory.cpp \ - $$PHONON_DIR/platform.cpp \ + $$PHONON_DIR/globalconfig.cpp \ + $$PHONON_DIR/iodevicestream.cpp \ $$PHONON_DIR/mediacontroller.cpp \ - $$PHONON_DIR/videowidget.cpp \ - $$PHONON_DIR/videoplayer.cpp \ + $$PHONON_DIR/medianode.cpp \ + $$PHONON_DIR/mediaobject.cpp \ + $$PHONON_DIR/mediasource.cpp \ + $$PHONON_DIR/objectdescription.cpp \ + $$PHONON_DIR/objectdescriptionmodel.cpp \ + $$PHONON_DIR/path.cpp \ + $$PHONON_DIR/phononnamespace.cpp \ + $$PHONON_DIR/platform.cpp \ + $$PHONON_DIR/pulsesupport.cpp \ $$PHONON_DIR/seekslider.cpp \ - $$PHONON_DIR/volumeslider.cpp \ - $$PHONON_DIR/effectwidget.cpp \ - $$PHONON_DIR/iodevicestream.cpp + $$PHONON_DIR/streaminterface.cpp \ + $$PHONON_DIR/swiftslider.cpp \ + $$PHONON_DIR/videoplayer.cpp \ + $$PHONON_DIR/videowidget.cpp \ + $$PHONON_DIR/volumefadereffect.cpp \ + $$PHONON_DIR/volumeslider.cpp contains(QT_CONFIG, dbus) { QT += dbus @@ -114,6 +124,12 @@ contains(QT_CONFIG, dbus) { contains(QT_CONFIG, reduce_exports): CONFIG += hide_symbols +unix:!isEmpty(QT_CFLAGS_PULSEAUDIO) { + DEFINES += HAVE_PULSEAUDIO + QMAKE_CXXFLAGS += $$QT_CFLAGS_PULSEAUDIO + LIBS += $$QT_LIBS_PULSEAUDIO +} + symbian: { # Phonon depends on numeric_limits. Enabling STL support in Qt # would bring in link dependencies, and we don't need that for -- cgit v0.12 From edb67f204302fff4f1e46676112931ea054deb88 Mon Sep 17 00:00:00 2001 From: Justin McPherson Date: Thu, 25 Mar 2010 13:57:36 +1000 Subject: Update Phonon GStreamer backend to 4.4.0. --- src/3rdparty/phonon/gstreamer/CMakeLists.txt | 18 +- .../phonon/gstreamer/ConfigureChecks.cmake | 7 +- src/3rdparty/phonon/gstreamer/audiodataoutput.cpp | 143 ++++++++++ src/3rdparty/phonon/gstreamer/audiodataoutput.h | 84 ++++++ src/3rdparty/phonon/gstreamer/audiooutput.cpp | 16 +- src/3rdparty/phonon/gstreamer/backend.cpp | 46 ++-- src/3rdparty/phonon/gstreamer/backend.h | 1 - src/3rdparty/phonon/gstreamer/devicemanager.cpp | 70 +++-- src/3rdparty/phonon/gstreamer/devicemanager.h | 6 +- src/3rdparty/phonon/gstreamer/effectmanager.cpp | 2 +- src/3rdparty/phonon/gstreamer/glrenderer.cpp | 2 +- src/3rdparty/phonon/gstreamer/gsthelper.cpp | 2 +- src/3rdparty/phonon/gstreamer/gstreamer.desktop | 57 ++++ src/3rdparty/phonon/gstreamer/medianode.cpp | 4 +- src/3rdparty/phonon/gstreamer/mediaobject.cpp | 296 ++++++++++++++++----- src/3rdparty/phonon/gstreamer/mediaobject.h | 12 +- src/3rdparty/phonon/gstreamer/qwidgetvideosink.h | 1 + src/3rdparty/phonon/gstreamer/videowidget.h | 1 + src/3rdparty/phonon/gstreamer/x11renderer.cpp | 3 +- src/plugins/phonon/gstreamer/gstreamer.pro | 22 +- 20 files changed, 651 insertions(+), 142 deletions(-) create mode 100644 src/3rdparty/phonon/gstreamer/audiodataoutput.cpp create mode 100644 src/3rdparty/phonon/gstreamer/audiodataoutput.h diff --git a/src/3rdparty/phonon/gstreamer/CMakeLists.txt b/src/3rdparty/phonon/gstreamer/CMakeLists.txt index 08f892a..2249ac3 100644 --- a/src/3rdparty/phonon/gstreamer/CMakeLists.txt +++ b/src/3rdparty/phonon/gstreamer/CMakeLists.txt @@ -19,7 +19,7 @@ include(ConfigureChecks.cmake) if (BUILD_PHONON_GSTREAMER) include_directories( ${CMAKE_CURRENT_BINARY_DIR} - ${GSTREAMER_INCLUDE_DIR} + ${GSTREAMER_INCLUDE_DIR} ${GLIB2_INCLUDE_DIR} ${LIBXML2_INCLUDE_DIR} ${X11_X11_INCLUDE_PATH}) @@ -34,7 +34,6 @@ if (BUILD_PHONON_GSTREAMER) set(phonon_gstreamer_SRCS audiooutput.cpp - artssink.cpp backend.cpp devicemanager.cpp effectmanager.cpp @@ -50,14 +49,20 @@ if (BUILD_PHONON_GSTREAMER) message.cpp audioeffect.cpp abstractrenderer.cpp - x11renderer.cpp widgetrenderer.cpp glrenderer.cpp volumefadereffect.cpp + audiodataoutput.cpp ) - find_package(Alsa) - macro_ensure_version("0.10.22" ${GSTREAMER_VERSION} GSTREAMER_HAS_NONBLOCKING_ALSASINK) + if(NOT WIN32) + set(phonon_gstreamer_SRCS + ${phonon_gstreamer_SRCS} + artssink.cpp + x11renderer.cpp) + macro_optional_find_package(Alsa) + macro_ensure_version("0.10.22" ${GSTREAMER_VERSION} GSTREAMER_HAS_NONBLOCKING_ALSASINK) + endif(NOT WIN32) if(ALSA_FOUND AND NOT GSTREAMER_HAS_NONBLOCKING_ALSASINK) add_definitions(-DUSE_ALSASINK2) include_directories(${ALSA_INCLUDES}) @@ -78,6 +83,9 @@ if (BUILD_PHONON_GSTREAMER) if(ALSA_FOUND) target_link_libraries(phonon_gstreamer ${ASOUND_LIBRARY}) endif(ALSA_FOUND) + if(USE_INSTALL_PLUGIN) + target_link_libraries(phonon_gstreamer ${GSTREAMER_PLUGIN_PBUTILS_LIBRARIES}) + endif(USE_INSTALL_PLUGIN) install(TARGETS phonon_gstreamer DESTINATION ${PLUGIN_INSTALL_DIR}/plugins/phonon_backend) install(FILES gstreamer.desktop DESTINATION ${SERVICES_INSTALL_DIR}/phononbackends) diff --git a/src/3rdparty/phonon/gstreamer/ConfigureChecks.cmake b/src/3rdparty/phonon/gstreamer/ConfigureChecks.cmake index f2922e1..eaf5b99 100644 --- a/src/3rdparty/phonon/gstreamer/ConfigureChecks.cmake +++ b/src/3rdparty/phonon/gstreamer/ConfigureChecks.cmake @@ -17,6 +17,7 @@ macro_log_feature(GSTREAMER_FOUND "GStreamer" "gstreamer 0.10 is required for th macro_optional_find_package(GStreamerPlugins) macro_log_feature(GSTREAMER_PLUGIN_VIDEO_LIBRARIES "GStreamer video plugin" "The gstreamer video plugin (part of gstreamer-plugins-base 0.10) is required for the multimedia gstreamer backend" "http://gstreamer.freedesktop.org/modules/" FALSE "0.10") +macro_log_feature(GSTREAMER_PLUGIN_AUDIO_LIBRARIES "GStreamer audio plugin" "The gstreamer audio plugin (part of gstreamer-plugins-base 0.10) is required for the multimedia gstreamer backend" "http://gstreamer.freedesktop.org/modules/" FALSE "0.10") macro_optional_find_package(GLIB2) macro_log_feature(GLIB2_FOUND "GLib2" "GLib 2 is required to compile the gstreamer backend for Phonon" "http://www.gtk.org/download/" FALSE) @@ -30,8 +31,8 @@ macro_log_feature(LIBXML2_FOUND "LibXml2" "LibXml2 is required to compile the gs macro_optional_find_package(OpenGL) macro_log_feature(OPENGL_FOUND "OpenGL" "OpenGL support is required to compile the gstreamer backend for Phonon" "" FALSE) -if (GSTREAMER_FOUND AND GSTREAMER_PLUGIN_VIDEO_LIBRARIES AND GLIB2_FOUND AND GOBJECT_FOUND AND LIBXML2_FOUND AND OPENGL_FOUND) +if (GSTREAMER_FOUND AND GSTREAMER_PLUGIN_VIDEO_LIBRARIES AND GSTREAMER_PLUGIN_AUDIO_LIBRARIES AND GLIB2_FOUND AND GOBJECT_FOUND AND LIBXML2_FOUND AND OPENGL_FOUND) set(BUILD_PHONON_GSTREAMER TRUE) -else (GSTREAMER_FOUND AND GSTREAMER_PLUGIN_VIDEO_LIBRARIES AND GLIB2_FOUND AND GOBJECT_FOUND AND LIBXML2_FOUND AND OPENGL_FOUND) +else (GSTREAMER_FOUND AND GSTREAMER_PLUGIN_VIDEO_LIBRARIES AND GSTREAMER_PLUGIN_AUDIO_LIBRARIES AND GLIB2_FOUND AND GOBJECT_FOUND AND LIBXML2_FOUND AND OPENGL_FOUND) set(BUILD_PHONON_GSTREAMER FALSE) -endif (GSTREAMER_FOUND AND GSTREAMER_PLUGIN_VIDEO_LIBRARIES AND GLIB2_FOUND AND GOBJECT_FOUND AND LIBXML2_FOUND AND OPENGL_FOUND) +endif (GSTREAMER_FOUND AND GSTREAMER_PLUGIN_VIDEO_LIBRARIES AND GSTREAMER_PLUGIN_AUDIO_LIBRARIES AND GLIB2_FOUND AND GOBJECT_FOUND AND LIBXML2_FOUND AND OPENGL_FOUND) diff --git a/src/3rdparty/phonon/gstreamer/audiodataoutput.cpp b/src/3rdparty/phonon/gstreamer/audiodataoutput.cpp new file mode 100644 index 0000000..30dabdf --- /dev/null +++ b/src/3rdparty/phonon/gstreamer/audiodataoutput.cpp @@ -0,0 +1,143 @@ +/* This file is part of the KDE project + Copyright (C) 2006 Matthias Kretz + Copyright (C) 2009 Martin Sandsmark + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) version 3, or any + later version accepted by the membership of KDE e.V. (or its + successor approved by the membership of KDE e.V.), Nokia Corporation + (or its successors, if any) and the KDE Free Qt Foundation, which shall + act as a proxy defined in Section 6 of version 3 of the license. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. If not, see . + +*/ + +#include "audiodataoutput.h" +#include "gsthelper.h" +#include "medianode.h" +#include "mediaobject.h" +#include +#include +#include + +namespace Phonon +{ +namespace Gstreamer +{ +AudioDataOutput::AudioDataOutput(Backend *backend, QObject *parent) + : QObject(parent), + MediaNode(backend, AudioSink | AudioSource) +{ + static int count = 0; + m_name = "AudioDataOutput" + QString::number(count++); + + m_queue = gst_element_factory_make ("identity", NULL); + gst_object_ref(m_queue); + m_isValid = true; +} + +AudioDataOutput::~AudioDataOutput() +{ + gst_element_set_state(m_queue, GST_STATE_NULL); + gst_object_unref(m_queue); +} + +int AudioDataOutput::dataSize() const +{ + return m_dataSize; +} + +int AudioDataOutput::sampleRate() const +{ + return 44100; +} + +void AudioDataOutput::setDataSize(int size) +{ + m_dataSize = size; +} + +typedef QMap > FloatMap; +typedef QMap > IntMap; + +inline void AudioDataOutput::convertAndEmit(const QVector &leftBuffer, const QVector &rightBuffer) +{ + //TODO: Floats + IntMap map; + map.insert(Phonon::AudioDataOutput::LeftChannel, leftBuffer); + map.insert(Phonon::AudioDataOutput::RightChannel, rightBuffer); + emit dataReady(map); +} + +void AudioDataOutput::processBuffer(GstPad*, GstBuffer* buffer, gpointer gThat) +{ + // TODO emit endOfMedia + AudioDataOutput *that = reinterpret_cast(gThat); + + // determine the number of channels + GstStructure* structure = gst_caps_get_structure (GST_BUFFER_CAPS(buffer), 0); + gst_structure_get_int (structure, "channels", &that->m_channels); + + if (that->m_channels > 2 || that->m_channels < 0) { + qWarning() << Q_FUNC_INFO << ": Number of channels not supported: " << that->m_channels; + return; + } + + gint16 *data = reinterpret_cast(GST_BUFFER_DATA(buffer)); + guint size = GST_BUFFER_SIZE(buffer) / sizeof(gint16); + + that->m_pendingData.reserve(that->m_pendingData.size() + size); + + for (uint i=0; im_pendingData.append(data[i]); + } + + while (that->m_pendingData.size() > that->m_dataSize * that->m_channels) { + if (that->m_channels == 1) { + QVector intBuffer(that->m_dataSize); + memcpy(intBuffer.data(), that->m_pendingData.constData(), that->m_dataSize * sizeof(qint16)); + + that->convertAndEmit(intBuffer, intBuffer); + int newSize = that->m_pendingData.size() - that->m_dataSize; + memmove(that->m_pendingData.data(), that->m_pendingData.constData() + that->m_dataSize, newSize * sizeof(qint16)); + that->m_pendingData.resize(newSize); + } else { + QVector left(that->m_dataSize), right(that->m_dataSize); + for (int i=0; im_dataSize; i++) { + left[i] = that->m_pendingData[i*2]; + right[i] = that->m_pendingData[i*2+1]; + } + that->m_pendingData.resize(that->m_pendingData.size() - that->m_dataSize*2); + that->convertAndEmit(left, right); + } + } +} + +void AudioDataOutput::mediaNodeEvent(const MediaNodeEvent *event) +{ + if (event->type() == MediaNodeEvent::MediaObjectConnected && root()) { + g_object_set(G_OBJECT(audioElement()), "sync", true, (const char*)NULL); + GstPad *audiopad = gst_element_get_pad (audioElement(), "src"); + gst_pad_add_buffer_probe (audiopad, G_CALLBACK(processBuffer), this); + gst_object_unref (audiopad); + return; + } + + MediaNode::mediaNodeEvent(event); +} + +}} //namespace Phonon::Gstreamer + +#include "moc_audiodataoutput.cpp" +// vim: sw=4 ts=4 + diff --git a/src/3rdparty/phonon/gstreamer/audiodataoutput.h b/src/3rdparty/phonon/gstreamer/audiodataoutput.h new file mode 100644 index 0000000..5e30a1d --- /dev/null +++ b/src/3rdparty/phonon/gstreamer/audiodataoutput.h @@ -0,0 +1,84 @@ +/* This file is part of the KDE project + Copyright (C) 2006 Matthias Kretz + Copyright (C) 2009 Martin Sandsmark + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) version 3, or any + later version accepted by the membership of KDE e.V. (or its + successor approved by the membership of KDE e.V.), Nokia Corporation + (or its successors, if any) and the KDE Free Qt Foundation, which shall + act as a proxy defined in Section 6 of version 3 of the license. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. If not, see . +*/ + +#ifndef Phonon_GSTREAMER_AUDIODATAOUTPUT_H +#define Phonon_GSTREAMER_AUDIODATAOUTPUT_H + +#include "abstractaudiooutput.h" +#include "backend.h" +#include "medianode.h" +#include +#include + +namespace Phonon +{ +namespace Gstreamer +{ + /** + * \author Martin Sandsmark + */ + class AudioDataOutput : public QObject, + public AudioDataOutputInterface, + public MediaNode + { + Q_OBJECT + Q_INTERFACES(Phonon::AudioDataOutputInterface Phonon::Gstreamer::MediaNode) + + public: + AudioDataOutput(Backend *, QObject *); + ~AudioDataOutput(); + + public Q_SLOTS: + int dataSize() const; + int sampleRate() const; + void setDataSize(int size); + + public: + /// callback function for handling new audio data + static void processBuffer(GstPad*, GstBuffer*, gpointer); + + Phonon::AudioDataOutput* frontendObject() const { return m_frontend; } + void setFrontendObject(Phonon::AudioDataOutput *frontend) { m_frontend = frontend; } + + GstElement *audioElement() { return m_queue; } + + void mediaNodeEvent(const MediaNodeEvent *event); + + + signals: + void dataReady(const QMap > &data); + void dataReady(const QMap > &data); + void endOfMedia(int remainingSamples); + + private: + void convertAndEmit(const QVector&, const QVector&); + + GstElement *m_queue; + int m_dataSize; + QVector m_pendingData; + Phonon::AudioDataOutput *m_frontend; + int m_channels; + }; +}} //namespace Phonon::Gstreamer + +// vim: sw=4 ts=4 tw=80 +#endif // Phonon_FAKE_AUDIODATAOUTPUT_H diff --git a/src/3rdparty/phonon/gstreamer/audiooutput.cpp b/src/3rdparty/phonon/gstreamer/audiooutput.cpp index 641ff6b..f3137b2 100644 --- a/src/3rdparty/phonon/gstreamer/audiooutput.cpp +++ b/src/3rdparty/phonon/gstreamer/audiooutput.cpp @@ -125,6 +125,7 @@ void AudioOutput::setVolume(qreal newVolume) bool AudioOutput::setOutputDevice(int newDevice) { m_backend->logMessage(Q_FUNC_INFO + QString::number(newDevice), Backend::Info, this); + if (newDevice == m_device) return true; @@ -135,20 +136,11 @@ bool AudioOutput::setOutputDevice(int newDevice) } bool success = false; - const QList deviceList = m_backend->deviceManager()->audioOutputDevices(); - int deviceIdx = -1; - for (int i=0; i= 0) { + if (m_audioSink && newDevice >= 0) { // Save previous state GstState oldState = GST_STATE(m_audioSink); const QByteArray oldDeviceValue = GstHelper::property(m_audioSink, "device"); - const QByteArray deviceId = deviceList.at(deviceIdx).gstId; + const QByteArray deviceId = m_backend->deviceManager()->gstId(newDevice); m_device = newDevice; // We test if the device can be opened by checking if it can go from NULL to READY state @@ -170,7 +162,7 @@ bool AudioOutput::setOutputDevice(int newDevice) deviceId, Backend::Info, this); } - // Note the stopped state should not really be neccessary, but seems to be required to + // Note the stopped state should not really be necessary, but seems to be required to // properly reset after changing the audio state if (root()) { QMetaObject::invokeMethod(root(), "setState", Qt::QueuedConnection, Q_ARG(State, StoppedState)); diff --git a/src/3rdparty/phonon/gstreamer/backend.cpp b/src/3rdparty/phonon/gstreamer/backend.cpp index dab6f35..8c2b42f 100644 --- a/src/3rdparty/phonon/gstreamer/backend.cpp +++ b/src/3rdparty/phonon/gstreamer/backend.cpp @@ -18,6 +18,7 @@ #include "common.h" #include "backend.h" #include "audiooutput.h" +#include "audiodataoutput.h" #include "audioeffect.h" #include "mediaobject.h" #include "videowidget.h" @@ -26,6 +27,7 @@ #include "message.h" #include "volumefadereffect.h" #include +#include #include #include @@ -49,13 +51,17 @@ Backend::Backend(QObject *parent, const QVariantList &) , m_debugLevel(Warning) , m_isValid(false) { + // Initialise PulseAudio support + PulseSupport *pulse = PulseSupport::getInstance(); + pulse->enable(); + connect(pulse, SIGNAL(objectDescriptionChanged(ObjectDescriptionType)), SIGNAL(objectDescriptionChanged(ObjectDescriptionType))); + // In order to support reloading, we only set the app name once... static bool first = true; if (first) { first = false; g_set_application_name(qApp->applicationName().toUtf8()); } - GError *err = 0; bool wasInit = gst_init_check(0, 0, &err); //init gstreamer: must be called before any gst-related functions if (err) @@ -92,6 +98,9 @@ Backend::Backend(QObject *parent, const QVariantList &) Backend::~Backend() { + delete m_effectManager; + delete m_deviceManager; + PulseSupport::shutdown(); } gboolean Backend::busCall(GstBus *bus, GstMessage *msg, gpointer data) @@ -119,18 +128,15 @@ QObject *Backend::createObject(BackendInterface::Class c, QObject *parent, const case MediaObjectClass: return new MediaObject(this, parent); - case AudioOutputClass: { - AudioOutput *ao = new AudioOutput(this, parent); - m_audioOutputs.append(ao); - return ao; - } + case AudioOutputClass: + return new AudioOutput(this, parent); + #ifndef QT_NO_PHONON_EFFECT case EffectClass: return new AudioEffect(this, args[0].toInt(), parent); #endif //QT_NO_PHONON_EFFECT case AudioDataOutputClass: - logMessage("createObject() : AudioDataOutput not implemented"); - break; + return new AudioDataOutput(this, parent); #ifndef QT_NO_PHONON_VIDEO case VideoDataOutputClass: @@ -244,6 +250,15 @@ QStringList Backend::availableMimeTypes() const } } g_list_free(factoryList); + if (availableMimeTypes.contains("audio/x-vorbis") + && availableMimeTypes.contains("application/x-ogm-audio")) { + if (!availableMimeTypes.contains("audio/x-vorbis+ogg")) + availableMimeTypes.append("audio/x-vorbis+ogg"); + if (!availableMimeTypes.contains("application/ogg")) /* *.ogg */ + availableMimeTypes.append("application/ogg"); + if (!availableMimeTypes.contains("audio/ogg")) /* *.oga */ + availableMimeTypes.append("audio/ogg"); + } availableMimeTypes.sort(); return availableMimeTypes; } @@ -293,14 +308,11 @@ QHash Backend::objectDescriptionProperties(ObjectDescripti switch (type) { case Phonon::AudioOutputDeviceType: { - QList audioDevices = deviceManager()->audioOutputDevices(); - foreach(const AudioDevice &device, audioDevices) { - if (device.id == index) { - ret.insert("name", device.gstId); - ret.insert("description", device.description); - ret.insert("icon", QLatin1String("audio-card")); - break; - } + AudioDevice* ad; + if ((ad = deviceManager()->audioDevice(index))) { + ret.insert("name", ad->gstId); + ret.insert("description", ad->description); + ret.insert("icon", ad->icon); } } break; @@ -429,7 +441,7 @@ EffectManager* Backend::effectManager() const /** * Returns a debuglevel that is determined by the - * PHONON_GSTREAMER_DEBUG environment variable. + * PHONON_GST_DEBUG environment variable. * * Warning - important warnings * Info - general info diff --git a/src/3rdparty/phonon/gstreamer/backend.h b/src/3rdparty/phonon/gstreamer/backend.h index 2aab6fa..d157f11 100644 --- a/src/3rdparty/phonon/gstreamer/backend.h +++ b/src/3rdparty/phonon/gstreamer/backend.h @@ -86,7 +86,6 @@ private Q_SLOTS: private: static gboolean busCall(GstBus *bus, GstMessage *msg, gpointer data); - QList > m_audioOutputs; DeviceManager *m_deviceManager; EffectManager *m_effectManager; diff --git a/src/3rdparty/phonon/gstreamer/devicemanager.cpp b/src/3rdparty/phonon/gstreamer/devicemanager.cpp index 60e860f..c3826eb 100644 --- a/src/3rdparty/phonon/gstreamer/devicemanager.cpp +++ b/src/3rdparty/phonon/gstreamer/devicemanager.cpp @@ -24,6 +24,7 @@ #include "widgetrenderer.h" #include "x11renderer.h" #include "artssink.h" +#include "pulsesupport.h" #ifdef USE_ALSASINK2 #include "alsasink2.h" @@ -44,9 +45,12 @@ namespace Gstreamer AudioDevice::AudioDevice(DeviceManager *manager, const QByteArray &gstId) : gstId(gstId) { - //get an id - static int counter = 0; - id = counter++; + // This should never be called when PulseAudio is active. + Q_ASSERT(!PulseSupport::getInstance()->isActive()); + + id = manager->allocateDeviceId(); + icon = "audio-card"; + //get name from device if (gstId == "default") { description = "Default audio device"; @@ -71,22 +75,25 @@ AudioDevice::AudioDevice(DeviceManager *manager, const QByteArray &gstId) DeviceManager::DeviceManager(Backend *backend) : QObject(backend) , m_backend(backend) + , m_audioDeviceCounter(0) { - m_audioSink = qgetenv("PHONON_GST_AUDIOSINK"); - m_videoSinkWidget = qgetenv("PHONON_GST_VIDEOMODE"); - -#ifndef QT_NO_SETTINGS QSettings settings(QLatin1String("Trolltech")); settings.beginGroup(QLatin1String("Qt")); + PulseSupport *pulse = PulseSupport::getInstance(); + m_audioSink = qgetenv("PHONON_GST_AUDIOSINK"); if (m_audioSink.isEmpty()) { m_audioSink = settings.value(QLatin1String("audiosink"), "Auto").toByteArray().toLower(); + if (m_audioSink == "auto" && pulse->isActive()) + m_audioSink = "pulsesink"; } + if ("pulsesink" != m_audioSink) + pulse->enable(false); + m_videoSinkWidget = qgetenv("PHONON_GST_VIDEOMODE"); if (m_videoSinkWidget.isEmpty()) { m_videoSinkWidget = settings.value(QLatin1String("videomode"), "Auto").toByteArray().toLower(); } -#endif //QT_NO_SETTINGS if (m_backend->isValid()) updateDeviceList(); @@ -271,9 +278,17 @@ AbstractRenderer *DeviceManager::createVideoRenderer(VideoWidget *parent) } #endif //QT_NO_PHONON_VIDEO -/* - * Returns a positive device id or -1 if device - * does not exist +/** + * Allocate a device id for a new audio device + */ +int DeviceManager::allocateDeviceId() +{ + return m_audioDeviceCounter++; +} + + +/** + * Returns a positive device id or -1 if device does not exist * * The gstId is typically in the format hw:1,0 */ @@ -288,16 +303,30 @@ int DeviceManager::deviceId(const QByteArray &gstId) const } /** - * Get a human-readable description from a device id + * Returns a gstId or "default" if device does not exist + * + * The gstId is typically in the format hw:1,0 */ -QByteArray DeviceManager::deviceDescription(int id) const +const QByteArray DeviceManager::gstId(int deviceId) +{ + if (!PulseSupport::getInstance()->isActive()) { + AudioDevice *ad = audioDevice(deviceId); + if (ad) + return QByteArray(ad->gstId); + } + return QByteArray("default"); +} + +/** +* Get the AudioDevice for a given device id +*/ +AudioDevice* DeviceManager::audioDevice(int id) { for (int i = 0 ; i < m_audioDeviceList.size() ; ++i) { - if (m_audioDeviceList[i].id == id) { - return m_audioDeviceList[i].description; - } + if (m_audioDeviceList[i].id == id) + return &m_audioDeviceList[i]; } - return QByteArray(); + return NULL; } /** @@ -311,8 +340,11 @@ void DeviceManager::updateDeviceList() QList list; if (audioSink) { - list = GstHelper::extractProperties(audioSink, "device"); - list.prepend("default"); + if (!PulseSupport::getInstance()->isActive()) { + // If we're using pulse, the PulseSupport class takes care of things for us. + list = GstHelper::extractProperties(audioSink, "device"); + list.prepend("default"); + } for (int i = 0 ; i < list.size() ; ++i) { QByteArray gstId = list.at(i); diff --git a/src/3rdparty/phonon/gstreamer/devicemanager.h b/src/3rdparty/phonon/gstreamer/devicemanager.h index a5e8289..9c6aa8d 100644 --- a/src/3rdparty/phonon/gstreamer/devicemanager.h +++ b/src/3rdparty/phonon/gstreamer/devicemanager.h @@ -42,6 +42,7 @@ public : int id; QByteArray gstId; QByteArray description; + QString icon; }; class DeviceManager : public QObject { @@ -51,8 +52,10 @@ public: virtual ~DeviceManager(); const QList audioOutputDevices() const; GstPad *requestPad(int device) const; + int allocateDeviceId(); int deviceId(const QByteArray &gstId) const; - QByteArray deviceDescription(int id) const; + const QByteArray gstId(int id); + AudioDevice* audioDevice(int id); GstElement *createGNOMEAudioSink(Category category); GstElement *createAudioSink(Category category = NoCategory); AbstractRenderer *createVideoRenderer(VideoWidget *parent); @@ -68,6 +71,7 @@ private: bool canOpenDevice(GstElement *element) const; Backend *m_backend; QList m_audioDeviceList; + int m_audioDeviceCounter; QTimer m_devicePollTimer; QByteArray m_audioSink; QByteArray m_videoSinkWidget; diff --git a/src/3rdparty/phonon/gstreamer/effectmanager.cpp b/src/3rdparty/phonon/gstreamer/effectmanager.cpp index 563e6fc..6c88148 100644 --- a/src/3rdparty/phonon/gstreamer/effectmanager.cpp +++ b/src/3rdparty/phonon/gstreamer/effectmanager.cpp @@ -54,7 +54,7 @@ EffectManager::EffectManager(Backend *backend) // "volume" not needed // "equalizer-nbands" not really useful at the moment - // These plugins simply dont work or have major stability issues: + // These plugins simply don't work or have major stability issues: // "iir" Does not seem to do much at the moment // "audioinvert" Only works for some streams, should be invesigated // "lpwsinc" Crashes for large values of filter kernel diff --git a/src/3rdparty/phonon/gstreamer/glrenderer.cpp b/src/3rdparty/phonon/gstreamer/glrenderer.cpp index 6cf3459..c72780a 100644 --- a/src/3rdparty/phonon/gstreamer/glrenderer.cpp +++ b/src/3rdparty/phonon/gstreamer/glrenderer.cpp @@ -266,7 +266,7 @@ GLRenderWidgetImplementation::GLRenderWidgetImplementation(VideoWidget*videoWidg palette.setColor(QPalette::Background, Qt::black); setPalette(palette); setAutoFillBackground(true); - // Videowidget allways have this property to allow hiding the mouse cursor + // Videowidget always have this property to allow hiding the mouse cursor setMouseTracking(true); } diff --git a/src/3rdparty/phonon/gstreamer/gsthelper.cpp b/src/3rdparty/phonon/gstreamer/gsthelper.cpp index 34d99fa..69bb75c 100644 --- a/src/3rdparty/phonon/gstreamer/gsthelper.cpp +++ b/src/3rdparty/phonon/gstreamer/gsthelper.cpp @@ -121,7 +121,7 @@ GstElement* GstHelper::createPluggablePlaybin() { GstElement *playbin = 0; //init playbin and add to our pipeline - playbin = gst_element_factory_make("playbin", NULL); + playbin = gst_element_factory_make("playbin2", NULL); //Create an identity element to redirect sound GstElement *audioSinkBin = gst_bin_new (NULL); diff --git a/src/3rdparty/phonon/gstreamer/gstreamer.desktop b/src/3rdparty/phonon/gstreamer/gstreamer.desktop index b62472b..0861762 100644 --- a/src/3rdparty/phonon/gstreamer/gstreamer.desktop +++ b/src/3rdparty/phonon/gstreamer/gstreamer.desktop @@ -10,28 +10,81 @@ Icon=phonon-gstreamer InitialPreference=10 Name=GStreamer +Name[bg]=GStreamer +Name[ca]=GStreamer +Name[ca@valencia]=GStreamer +Name[cs]=GStreamer +Name[da]=GStreamer +Name[de]=GStreamer +Name[el]=GStreamer +Name[en_GB]=GStreamer +Name[es]=GStreamer +Name[et]=GStreamer +Name[eu]=GStreamer +Name[fi]=GStreamer +Name[fr]=GStreamer +Name[ga]=GStreamer +Name[gl]=GStreamer +Name[hsb]=GStreamer +Name[hu]=GStreamer +Name[id]=GStreamer +Name[is]=GStreamer +Name[it]=GStreamer +Name[ja]=GStreamer +Name[ko]=GStreamer +Name[ku]=GStreamer +Name[lt]=GStreamer +Name[lv]=GStreamer +Name[nb]=GStreamer +Name[nds]=GStreamer +Name[nl]=GStreamer +Name[nn]=GStreamer Name[pa]=ਜੀਸਟੀਰਮਰ +Name[pl]=GStreamer +Name[pt]=GStreamer +Name[pt_BR]=GStreamer +Name[ru]=GStreamer +Name[se]=GStreamer +Name[sk]=GStreamer +Name[sl]=GStreamer Name[sr]=Гстример +Name[sr@ijekavian]=Гстример +Name[sr@ijekavianlatin]=GStreamer +Name[sr@latin]=GStreamer Name[sv]=Gstreamer +Name[tr]=GStreamer +Name[uk]=GStreamer Name[x-test]=xxGStreamerxx +Name[zh_CN]=GStreamer +Name[zh_TW]=GStreamer Comment=Phonon GStreamer backend Comment[bg]=Phonon GStreamer Comment[ca]=Dorsal GStreamer del Phonon +Comment[ca@valencia]=Dorsal GStreamer del Phonon +Comment[cs]=Phonon GStreamer backend Comment[da]=GStreamer-backend til Phonon Comment[de]=Phonon-Treiber für GStreamer Comment[el]=Σύστημα υποστήριξης GStreamer του Phonon +Comment[en_GB]=Phonon GStreamer backend Comment[es]=Motor GStreamer para Phonon Comment[et]=Phononi GStreameri taustaprogramm +Comment[eu]=Phonon GStreamer backend +Comment[fi]=Phonon GStreamer-taustaohjelma Comment[fr]=Système de gestion GStreamer pour Phonon Comment[ga]=Inneall GStreamer le haghaidh Phonon Comment[gl]=Infraestrutura de GStreamer para Phonon +Comment[hsb]=Phonon GStreamer backend +Comment[hu]=Phonon GStreamer modul +Comment[id]=Phonon GStreamer backend Comment[is]=Phonon GStreamer bakendi Comment[it]=Motore Gstreamer di Phonon Comment[ja]=Phonon GStreamer バックエンド Comment[ko]=Phonon GStreamer 백엔드 Comment[ku]=Binesaza Phonon GStreamer +Comment[lt]=Phonon GStreamer galinė sąsaja Comment[lv]=Phonon GStreamer aizmugure +Comment[nb]=Phonon-motor for GStreamer Comment[nds]=Phonon-Hülpprogramm GStreamer Comment[nl]=GStreamer-backend (Phonon) Comment[nn]=Phonon-motor for GStreamer @@ -39,9 +92,13 @@ Comment[pa]=ਫੋਨੋਨ ਜਸਟੀਰਮਰ ਬੈਕਐਂਡ Comment[pl]=Obsługa GStreamera przez Phonon Comment[pt]=Infra-estrutura do GStreamer para o Phonon Comment[pt_BR]=Infraestrutura Phonon GStreamer +Comment[ru]=Механизм GStreamer для Phonon +Comment[se]=Phonon GStreamer duogášmohtor Comment[sk]=GStreamer podsystém Comment[sl]=Phononova hrbtenica GStreamer Comment[sr]=Гстример као позадина Фонона +Comment[sr@ijekavian]=Гстример као позадина Фонона +Comment[sr@ijekavianlatin]=GStreamer kao pozadina Phonona Comment[sr@latin]=GStreamer kao pozadina Phonona Comment[sv]=Phonon Gstreamer-gränssnitt Comment[tr]=Phonon GStreamer arka ucu diff --git a/src/3rdparty/phonon/gstreamer/medianode.cpp b/src/3rdparty/phonon/gstreamer/medianode.cpp index 7257972..1a84592 100644 --- a/src/3rdparty/phonon/gstreamer/medianode.cpp +++ b/src/3rdparty/phonon/gstreamer/medianode.cpp @@ -198,9 +198,9 @@ bool MediaNode::disconnectNode(QObject *obj) // Disconnecting elements while playing or paused seems to cause // potential deadlock. Hence we force the pipeline into ready state // before any nodes are disconnected. - gst_element_set_state(root()->pipeline(), GST_STATE_READY); + gst_element_set_state(root()->pipeline(), GST_STATE_READY); - Q_ASSERT(sink->root()); //sink has to have a root since it is onnected + Q_ASSERT(sink->root()); //sink has to have a root since it is connected if (sink->description() & (AudioSink)) { GstPad *sinkPad = gst_element_get_pad(sink->audioElement(), "sink"); diff --git a/src/3rdparty/phonon/gstreamer/mediaobject.cpp b/src/3rdparty/phonon/gstreamer/mediaobject.cpp index b6d23ec..3e0addc 100644 --- a/src/3rdparty/phonon/gstreamer/mediaobject.cpp +++ b/src/3rdparty/phonon/gstreamer/mediaobject.cpp @@ -16,6 +16,7 @@ */ #include #include +#include #include "common.h" #include "mediaobject.h" #include "videowidget.h" @@ -53,6 +54,7 @@ MediaObject::MediaObject(Backend *backend, QObject *parent) , m_tickTimer(new QTimer(this)) , m_prefinishMark(0) , m_transitionTime(0) + , m_isStream(false) , m_posAtSeek(-1) , m_prefinishMarkReachedNotEmitted(true) , m_aboutToFinishEmitted(false) @@ -79,6 +81,7 @@ MediaObject::MediaObject(Backend *backend, QObject *parent) , m_autoplayTitles(true) , m_availableTitles(0) , m_currentTitle(1) + , m_pendingTitle(1) { qRegisterMetaType("GstCaps*"); qRegisterMetaType("State"); @@ -95,8 +98,8 @@ MediaObject::MediaObject(Backend *backend, QObject *parent) m_backend->addBusWatcher(this); connect(m_tickTimer, SIGNAL(timeout()), SLOT(emitTick())); } - connect(this, SIGNAL(stateChanged(Phonon::State,Phonon::State)), - this, SLOT(notifyStateChange(Phonon::State,Phonon::State))); + connect(this, SIGNAL(stateChanged(Phonon::State, Phonon::State)), + this, SLOT(notifyStateChange(Phonon::State, Phonon::State))); } @@ -136,6 +139,14 @@ QString stateString(const Phonon::State &state) return QString(); } +void +pluginInstallationDone( GstInstallPluginsReturn res, gpointer userData ) +{ + // Nothing inside yet + Q_UNUSED(res); + Q_UNUSED(userData); +} + void MediaObject::saveState() { //Only first resumeState is respected @@ -195,13 +206,35 @@ void MediaObject::noMorePadsAvailable () if (m_missingCodecs.size() > 0) { bool canPlay = (m_hasAudio || m_videoStreamFound); Phonon::ErrorType error = canPlay ? Phonon::NormalError : Phonon::FatalError; +#ifdef PLUGIN_INSTALL_API + GstInstallPluginsContext *ctx = gst_install_plugins_context_new (); + gchar *details[2]; + details[0] = m_missingCodecs[0].toLocal8Bit().data(); + details[1] = NULL; + GstInstallPluginsReturn status; + + status = gst_install_plugins_async( details, ctx, pluginInstallationDone, NULL ); + gst_install_plugins_context_free ( ctx ); + + if ( status != GST_INSTALL_PLUGINS_STARTED_OK ) + { + if( status == GST_INSTALL_PLUGINS_HELPER_MISSING ) + setError(QString(tr("Missing codec helper script assistant.")), Phonon::FatalError ); + else + setError(QString(tr("Plugin codec installation failed for codec: %0")) + .arg(m_missingCodecs[0].split("|")[3]), error); + } + m_missingCodecs.clear(); +#else + QString codecs = m_missingCodecs.join(", "); + if (error == Phonon::NormalError && m_hasVideo && !m_videoStreamFound) { m_hasVideo = false; emit hasVideoChanged(false); } - QString codecs = m_missingCodecs.join(", "); setError(QString(tr("A required codec is missing. You need to install the following codec(s) to play this content: %0")).arg(codecs), error); m_missingCodecs.clear(); +#endif } } @@ -248,7 +281,16 @@ void MediaObject::cb_unknown_type (GstElement *decodebin, GstPad *pad, GstCaps * value = QString::fromUtf8(gst_structure_get_name (str)); } - media->addMissingCodecName(value); + +#ifdef PLUGIN_INSTALL_API + QString plugins = QString("gstreamer|0.10|%0|%1|decoder-%2") + .arg( qApp->applicationName() ) + .arg( value ) + .arg( QString::fromUtf8(gst_caps_to_string (caps) ) ); + media->addMissingCodecName( plugins ); +#else + media->addMissingCodecName( value ); +#endif } static void notifyVideoCaps(GObject *obj, GParamSpec *, gpointer data) @@ -309,7 +351,7 @@ void MediaObject::connectVideo(GstPad *pad) m_backend->logMessage("Video track connected", Backend::Info, this); // Note that the notify::caps _must_ be installed after linking to work with Dapper m_capsHandler = g_signal_connect(pad, "notify::caps", G_CALLBACK(notifyVideoCaps), this); - + if (!m_loading && !m_hasVideo) { m_hasVideo = m_videoStreamFound; emit hasVideoChanged(m_hasVideo); @@ -368,7 +410,10 @@ bool MediaObject::createPipefromURL(const QUrl &url) } // Create a new datasource based on the input URL - QByteArray encoded_cstr_url = url.toEncoded(); + // add the 'file' scheme if it's missing; the double '/' is needed! + QByteArray encoded_cstr_url = (url.scheme() == QLatin1String("") ? + "file://" + url.toEncoded() : + url.toEncoded()); m_datasource = gst_element_make_from_uri(GST_URI_SRC, encoded_cstr_url.constData(), (const char*)NULL); if (!m_datasource) return false; @@ -388,6 +433,14 @@ bool MediaObject::createPipefromURL(const QUrl &url) g_object_set (G_OBJECT (m_datasource), "read-speed", 2, (const char*)NULL); m_backend->logMessage(QString("new device speed : 2X"), Backend::Info, this); } + } + + /* make HTTP sources send extra headers so we get icecast + * metadata in case the stream is an icecast stream */ + if (encoded_cstr_url.startsWith("http://") + && g_object_class_find_property (G_OBJECT_GET_CLASS (m_datasource), "iradio-mode")) { + g_object_set (m_datasource, "iradio-mode", TRUE, NULL); + m_isStream = true; } // Link data source into pipeline @@ -442,7 +495,7 @@ void MediaObject::createPipeline() gst_object_ref (GST_OBJECT (m_pipeline)); gst_object_sink (GST_OBJECT (m_pipeline)); - m_decodebin = gst_element_factory_make ("decodebin", NULL); + m_decodebin = gst_element_factory_make ("decodebin2", NULL); g_signal_connect (m_decodebin, "new-decoded-pad", G_CALLBACK (&cb_newpad), this); g_signal_connect (m_decodebin, "unknown-type", G_CALLBACK (&cb_unknown_type), this); g_signal_connect (m_decodebin, "no-more-pads", G_CALLBACK (&cb_no_more_pads), this); @@ -646,7 +699,7 @@ void MediaObject::setState(State newstate) m_backend->logMessage("EOS already reached", Backend::Info, this); } else if (currentState == GST_STATE_PLAYING) { changeState(Phonon::PlayingState); - } else if (!m_atEndOfStream && gst_element_set_state(m_pipeline, GST_STATE_PLAYING) != GST_STATE_CHANGE_FAILURE) { + } else if (gst_element_set_state(m_pipeline, GST_STATE_PLAYING) != GST_STATE_CHANGE_FAILURE) { m_pendingState = Phonon::PlayingState; } else { m_backend->logMessage("phonon state request failed", Backend::Info, this); @@ -676,7 +729,7 @@ void MediaObject::changeState(State newstate) return; Phonon::State oldState = m_state; - m_state = newstate; // m_state must be set before emitting, since + m_state = newstate; // m_state must be set before emitting, since // Error state requires that state() will return the new value m_pendingState = newstate; emit stateChanged(newstate, oldState); @@ -696,6 +749,8 @@ void MediaObject::changeState(State newstate) case Phonon::StoppedState: m_backend->logMessage("phonon state changed: Stopped", Backend::Info, this); + // We must reset the pipeline when playing again + m_resetNeeded = true; m_tickTimer->stop(); break; @@ -861,7 +916,7 @@ void MediaObject::setSource(const MediaSource &source) // such as failing duration queries etc GstState state; gst_element_set_state(m_pipeline, GST_STATE_NULL); - gst_element_get_state (m_pipeline, &state, NULL, 2000); + gst_element_get_state(m_pipeline, &state, NULL, 2000); m_source = source; emit currentSourceChanged(m_source); @@ -871,7 +926,9 @@ void MediaObject::setSource(const MediaSource &source) // Go into to loading state changeState(Phonon::LoadingState); m_loading = true; - m_resetNeeded = false; + // IMPORTANT: Honor the m_resetNeeded flag as it currently stands. + // See https://qa.mandriva.com/show_bug.cgi?id=56807 + //m_resetNeeded = false; m_resumeState = false; m_pendingState = Phonon::StoppedState; @@ -884,8 +941,8 @@ void MediaObject::setSource(const MediaSource &source) // Clear any existing errors m_aboutToFinishEmitted = false; m_error = NoError; - m_errorString = QString(); - + m_errorString.clear(); + m_bufferPercent = 0; m_prefinishMarkReachedNotEmitted = true; m_aboutToFinishEmitted = false; @@ -894,22 +951,23 @@ void MediaObject::setSource(const MediaSource &source) setTotalTime(-1); m_atEndOfStream = false; - // Clear exising meta tags + m_availableTitles = 0; + m_pendingTitle = 1; + m_currentTitle = 1; + + // Clear existing meta tags m_metaData.clear(); + m_isStream = false; switch (source.type()) { - case MediaSource::Url: { - if (createPipefromURL(source.url())) - m_loading = true; - else + case MediaSource::Url: { + if (!createPipefromURL(source.url())) setError(tr("Could not open media source.")); } break; case MediaSource::LocalFile: { - if (createPipefromURL(QUrl::fromLocalFile(source.fileName()))) - m_loading = true; - else + if (!createPipefromURL(QUrl::fromLocalFile(source.fileName()))) setError(tr("Could not open media source.")); } break; @@ -922,17 +980,15 @@ void MediaObject::setSource(const MediaSource &source) break; case MediaSource::Stream: - if (createPipefromStream(source)) - m_loading = true; - else + if (!createPipefromStream(source)) setError(tr("Could not open media source.")); break; case MediaSource::Disc: { - QString mediaUrl; - switch (source.discType()) { - case Phonon::NoDisc: + QString mediaUrl; + switch (source.discType()) { + case Phonon::NoDisc: qWarning() << "I should never get to see a MediaSource that is a disc but doesn't specify which one"; return; case Phonon::Cd: // CD tracks can be specified by setting the url in the following way uri=cdda:4 @@ -948,9 +1004,7 @@ void MediaObject::setSource(const MediaSource &source) qWarning() << "media " << source.discType() << " not implemented"; return; } - if (!mediaUrl.isEmpty() && createPipefromURL(QUrl(mediaUrl))) - m_loading = true; - else + if (mediaUrl.isEmpty() || !createPipefromURL(QUrl(mediaUrl))) setError(tr("Could not open media source.")); } break; @@ -966,8 +1020,7 @@ void MediaObject::setSource(const MediaSource &source) // We need to link this node to ensure that fake sinks are connected // before loading, otherwise the stream will be blocked - if (m_loading) - link(); + link(); beginLoad(); } @@ -1004,22 +1057,22 @@ void MediaObject::getStreamInfo() emit hasVideoChanged(m_hasVideo); } - m_availableTitles = 1; - gint64 titleCount; - GstFormat format = gst_format_get_by_nick("track"); - if (gst_element_query_duration (m_pipeline, &format, &titleCount)) { + if (m_source.discType() == Phonon::Cd) { + gint64 titleCount; + GstFormat format = gst_format_get_by_nick("track"); + if (gst_element_query_duration (m_pipeline, &format, &titleCount)) { //check if returned format is still "track", //gstreamer sometimes returns the total time, if tracks information is not available. - if (qstrcmp(gst_format_get_name(format), "track") == 0) { - int oldAvailableTitles = m_availableTitles; - m_availableTitles = (int)titleCount; - if (m_availableTitles != oldAvailableTitles) { - emit availableTitlesChanged(m_availableTitles); - m_backend->logMessage(QString("Available titles changed: %0").arg(m_availableTitles), Backend::Info, this); + if (qstrcmp(gst_format_get_name(format), "track") == 0) { + int oldAvailableTitles = m_availableTitles; + m_availableTitles = (int)titleCount; + if (m_availableTitles != oldAvailableTitles) { + emit availableTitlesChanged(m_availableTitles); + m_backend->logMessage(QString("Available titles changed: %0").arg(m_availableTitles), Backend::Info, this); + } } } } - } void MediaObject::setPrefinishMark(qint32 newPrefinishMark) @@ -1077,7 +1130,7 @@ void MediaObject::seek(qint64 time) } quint64 current = currentTime(); - quint64 total = totalTime(); + quint64 total = totalTime(); if (current < total - m_prefinishMark) m_prefinishMarkReachedNotEmitted = true; @@ -1098,7 +1151,7 @@ void MediaObject::emitTick() if (m_tickInterval > 0 && currentTime != m_previousTickTime) { emit tick(currentTime); - m_previousTickTime = currentTime; + m_previousTickTime = currentTime; } if (m_state == Phonon::PlayingState) { if (currentTime >= totalTime - m_prefinishMark) { @@ -1109,7 +1162,12 @@ void MediaObject::emitTick() } // Prepare load of next source if (currentTime >= totalTime - ABOUT_TO_FINNISH_TIME) { - if (!m_aboutToFinishEmitted) { + if (m_source.type() == MediaSource::Disc && + m_autoplayTitles && + m_availableTitles > 1 && + m_currentTitle < m_availableTitles) { + m_aboutToFinishEmitted = false; + } else if (!m_aboutToFinishEmitted) { m_aboutToFinishEmitted = true; // track is about to finish emit aboutToFinish(); } @@ -1213,8 +1271,8 @@ void MediaObject::handleBusMessage(const Message &message) switch (GST_MESSAGE_TYPE (gstMessage)) { - case GST_MESSAGE_EOS: - m_backend->logMessage("EOS recieved", Backend::Info, this); + case GST_MESSAGE_EOS: + m_backend->logMessage("EOS received", Backend::Info, this); handleEndOfStream(); break; @@ -1222,14 +1280,98 @@ void MediaObject::handleBusMessage(const Message &message) GstTagList* tag_list = 0; gst_message_parse_tag(gstMessage, &tag_list); if (tag_list) { + TagMap newTags; + gst_tag_list_foreach (tag_list, &foreach_tag_function, &newTags); + gst_tag_list_free(tag_list); + + // Determine if we should no fake the album/artist tags. + // This is a little confusing as we want to fake it on initial + // connection where title, album and artist are all missing. + // There are however times when we get just other information, + // e.g. codec, and so we want to only do clever stuff if we + // have a commonly available tag (ORGANIZATION) or we have a + // change in title + bool fake_it = + (m_isStream + && ((!newTags.contains("TITLE") + && newTags.contains("ORGANIZATION")) + || (newTags.contains("TITLE") + && m_metaData.value("TITLE") != newTags.value("TITLE"))) + && !newTags.contains("ALBUM") + && !newTags.contains("ARTIST")); + TagMap oldMap = m_metaData; // Keep a copy of the old one for reference - // Append any new meta tags to the existing tag list - gst_tag_list_foreach (tag_list, &foreach_tag_function, &m_metaData); + + // Now we've checked the new data, append any new meta tags to the existing tag list + // We cannot use TagMap::iterator as this is a multimap and when streaming data + // could in theory be lost. + QList keys = newTags.keys(); + for (QList::iterator i = keys.begin(); i != keys.end(); ++i) { + QString key = *i; + if (m_isStream) { + // If we're streaming, we need to remove data in m_metaData + // in order to stop it filling up indefinitely (as it's a multimap) + m_metaData.remove(key); + } + QList values = newTags.values(key); + for (QList::iterator j = values.begin(); j != values.end(); ++j) { + QString value = *j; + QString currVal = m_metaData.value(key); + if (!m_metaData.contains(key) || currVal != value) { + m_metaData.insert(key, value); + } + } + } + m_backend->logMessage("Meta tags found", Backend::Info, this); - if (oldMap != m_metaData && !m_loading) - emit metaDataChanged(m_metaData); - gst_tag_list_free(tag_list); - } + if (oldMap != m_metaData) { + // This is a bit of a hack to ensure that stream metadata is + // returned. We get as much as we can from the Shoutcast server's + // StreamTitle= header. If further info is decoded from the stream + // itself later, then it will overwrite this info. + if (m_isStream && fake_it) { + m_metaData.remove("ALBUM"); + m_metaData.remove("ARTIST"); + + // Detect whether we want to "fill in the blanks" + QString str; + if (m_metaData.contains("TITLE")) + { + str = m_metaData.value("TITLE"); + int splitpoint; + // Check to see if our title matches "%s - %s" + // Where neither %s are empty... + if ((splitpoint = str.indexOf(" - ")) > 0 + && str.size() > (splitpoint+3)) { + m_metaData.insert("ARTIST", str.left(splitpoint)); + m_metaData.replace("TITLE", str.mid(splitpoint+3)); + } + } else { + str = m_metaData.value("GENRE"); + if (!str.isEmpty()) + m_metaData.insert("TITLE", str); + else + m_metaData.insert("TITLE", "Streaming Data"); + } + if (!m_metaData.contains("ARTIST")) { + str = m_metaData.value("LOCATION"); + if (!str.isEmpty()) + m_metaData.insert("ARTIST", str); + else + m_metaData.insert("ARTIST", "Streaming Data"); + } + str = m_metaData.value("ORGANIZATION"); + if (!str.isEmpty()) + m_metaData.insert("ALBUM", str); + else + m_metaData.insert("ALBUM", "Streaming Data"); + } + // As we manipulate the title, we need to recompare + // oldMap and m_metaData here... + if (oldMap != m_metaData && !m_loading) + emit metaDataChanged(m_metaData); + } + } } break; @@ -1255,6 +1397,9 @@ void MediaObject::handleBusMessage(const Message &message) m_backend->logMessage("gstreamer: pipeline state set to playing", Backend::Info, this); m_tickTimer->start(); changeState(Phonon::PlayingState); + if ((m_source.type() == MediaSource::Disc) && (m_currentTitle != m_pendingTitle)) { + setTrack(m_pendingTitle); + } if (m_resumeState && m_oldState == Phonon::PlayingState) { seek(m_oldPos); m_resumeState = false; @@ -1290,6 +1435,9 @@ void MediaObject::handleBusMessage(const Message &message) changeState(Phonon::StoppedState); m_backend->logMessage("gstreamer: pipeline state set to ready", Backend::Debug, this); m_tickTimer->stop(); + if ((m_source.type() == MediaSource::Disc) && (m_currentTitle != m_pendingTitle)) { + setTrack(m_pendingTitle); + } break; case GST_STATE_VOID_PENDING : @@ -1328,7 +1476,7 @@ void MediaObject::handleBusMessage(const Message &message) setError(err->message, Phonon::FatalError); gst_caps_unref (caps); gst_object_unref (sinkPad); - } + } } else { setError(QString(err->message), Phonon::FatalError); } @@ -1400,8 +1548,8 @@ void MediaObject::handleBusMessage(const Message &message) //case GST_MESSAGE_STEP_DONE: //case GST_MESSAGE_LATENCY: only from 0.10.12 //case GST_MESSAGE_ASYNC_DONE: only from 0.10.13 - default: - break; + default: + break; } } @@ -1417,7 +1565,8 @@ void MediaObject::handleEndOfStream() if (!m_seekable) m_atEndOfStream = true; - if (m_autoplayTitles && + if (m_source.type() == MediaSource::Disc && + m_autoplayTitles && m_availableTitles > 1 && m_currentTitle < m_availableTitles) { _iface_setCurrentTitle(m_currentTitle + 1); @@ -1444,6 +1593,14 @@ void MediaObject::handleEndOfStream() } } +void MediaObject::invalidateGraph() +{ + m_resetNeeded = true; + if (m_state == Phonon::PlayingState || m_state == Phonon::PausedState) { + changeState(Phonon::StoppedState); + } +} + // Notifes the pipeline about state changes in the media object void MediaObject::notifyStateChange(Phonon::State newstate, Phonon::State oldstate) { @@ -1502,15 +1659,30 @@ int MediaObject::_iface_currentTitle() const void MediaObject::_iface_setCurrentTitle(int title) { - GstFormat trackFormat = gst_format_get_by_nick("track"); m_backend->logMessage(QString("setCurrentTitle %0").arg(title), Backend::Info, this); - if ((title == m_currentTitle) || (title < 1) || (title > m_availableTitles)) + if ((title == m_currentTitle) || (title == m_pendingTitle)) + return; + + m_pendingTitle = title; + + if (m_state == Phonon::PlayingState || m_state == Phonon::StoppedState) { + setTrack(m_pendingTitle); + } else { + setState(Phonon::StoppedState); + } +} + +void MediaObject::setTrack(int title) +{ + if (((m_state != Phonon::PlayingState) && (m_state != Phonon::StoppedState)) || (title < 1) || (title > m_availableTitles)) return; - m_currentTitle = title; //let's seek to the beginning of the song - if (gst_element_seek_simple(m_pipeline, trackFormat, GST_SEEK_FLAG_FLUSH, m_currentTitle - 1)) { + GstFormat trackFormat = gst_format_get_by_nick("track"); + m_backend->logMessage(QString("setTrack %0").arg(title), Backend::Info, this); + if (gst_element_seek_simple(m_pipeline, trackFormat, GST_SEEK_FLAG_FLUSH, title - 1)) { + m_currentTitle = title; updateTotalTime(); m_atEndOfStream = false; emit titleChanged(title); diff --git a/src/3rdparty/phonon/gstreamer/mediaobject.h b/src/3rdparty/phonon/gstreamer/mediaobject.h index 64b3510..d588ffc 100644 --- a/src/3rdparty/phonon/gstreamer/mediaobject.h +++ b/src/3rdparty/phonon/gstreamer/mediaobject.h @@ -55,6 +55,7 @@ class MediaObject : public QObject, public MediaObjectInterface , public MediaNode { friend class Stream; + friend class AudioDataOutput; Q_OBJECT Q_INTERFACES(Phonon::MediaObjectInterface #ifndef QT_NO_PHONON_MEDIACONTROLLER @@ -144,12 +145,8 @@ public: void handleBusMessage(const Message &msg); void handleEndOfStream(); void addMissingCodecName(const QString &codec) { m_missingCodecs.append(codec); } - void invalidateGraph() { - m_resetNeeded = true; - if (m_state == Phonon::PlayingState || m_state == Phonon::PausedState) { - changeState(Phonon::StoppedState); - } - } + void invalidateGraph(); + static void cb_newpad (GstElement *decodebin, GstPad *pad, gboolean last, gpointer data); static void cb_pad_added (GstElement *decodebin, GstPad *pad, gpointer data); static void cb_unknown_type (GstElement *decodebin, GstPad *pad, GstCaps *caps, gpointer data); @@ -236,6 +233,7 @@ private: int _iface_availableTitles() const; int _iface_currentTitle() const; void _iface_setCurrentTitle(int title); + void setTrack(int title); bool m_resumeState; State m_oldState; @@ -250,6 +248,7 @@ private: MediaSource m_nextSource; qint32 m_prefinishMark; qint32 m_transitionTime; + bool m_isStream; qint64 m_posAtSeek; @@ -285,6 +284,7 @@ private: bool m_autoplayTitles; int m_availableTitles; int m_currentTitle; + int m_pendingTitle; }; } } //namespace Phonon::Gstreamer diff --git a/src/3rdparty/phonon/gstreamer/qwidgetvideosink.h b/src/3rdparty/phonon/gstreamer/qwidgetvideosink.h index 73a494a..f83dba5 100644 --- a/src/3rdparty/phonon/gstreamer/qwidgetvideosink.h +++ b/src/3rdparty/phonon/gstreamer/qwidgetvideosink.h @@ -19,6 +19,7 @@ #define Phonon_GSTREAMER_VIDEOSINK_H #include "common.h" +#include "qwidgetvideosink.h" #include #include diff --git a/src/3rdparty/phonon/gstreamer/videowidget.h b/src/3rdparty/phonon/gstreamer/videowidget.h index dc0754d..8603f6a 100644 --- a/src/3rdparty/phonon/gstreamer/videowidget.h +++ b/src/3rdparty/phonon/gstreamer/videowidget.h @@ -25,6 +25,7 @@ #include "common.h" #include "medianode.h" #include "abstractrenderer.h" +#include "videowidget.h" #include diff --git a/src/3rdparty/phonon/gstreamer/x11renderer.cpp b/src/3rdparty/phonon/gstreamer/x11renderer.cpp index 73877a8..968f3a8 100644 --- a/src/3rdparty/phonon/gstreamer/x11renderer.cpp +++ b/src/3rdparty/phonon/gstreamer/x11renderer.cpp @@ -90,7 +90,7 @@ GstElement* X11Renderer::createVideoSink() gst_object_unref(GST_OBJECT(videoSink)); videoSink = 0; } else { - // Note that this should not really be neccessary as these are + // Note that this should not really be necessary as these are // default values, though under certain conditions values are retained // even between application instances. (reproducible on 0.10.16/Gutsy) g_object_set(G_OBJECT(videoSink), "brightness", 0, (const char*)NULL); @@ -138,6 +138,7 @@ void X11Renderer::scaleModeChanged(Phonon::VideoWidget::ScaleMode) void X11Renderer::movieSizeChanged(const QSize &movieSize) { Q_UNUSED(movieSize); + if (m_renderWidget) { m_renderWidget->setGeometry(m_videoWidget->calculateDrawFrameRect()); } diff --git a/src/plugins/phonon/gstreamer/gstreamer.pro b/src/plugins/phonon/gstreamer/gstreamer.pro index ae597fa..1013205 100644 --- a/src/plugins/phonon/gstreamer/gstreamer.pro +++ b/src/plugins/phonon/gstreamer/gstreamer.pro @@ -15,6 +15,7 @@ PHONON_GSTREAMER_DIR = $$QT_SOURCE_TREE/src/3rdparty/phonon/gstreamer HEADERS += $$PHONON_GSTREAMER_DIR/common.h \ $$PHONON_GSTREAMER_DIR/audiooutput.h \ + $$PHONON_GSTREAMER_DIR/audiodataoutput.h \ $$PHONON_GSTREAMER_DIR/artssink.h \ $$PHONON_GSTREAMER_DIR/abstractrenderer.h \ $$PHONON_GSTREAMER_DIR/backend.h \ @@ -35,26 +36,27 @@ HEADERS += $$PHONON_GSTREAMER_DIR/common.h \ $$PHONON_GSTREAMER_DIR/audioeffect.h \ $$PHONON_GSTREAMER_DIR/volumefadereffect.h -SOURCES += $$PHONON_GSTREAMER_DIR/audiooutput.cpp \ - $$PHONON_GSTREAMER_DIR/abstractrenderer.cpp \ +SOURCES += $$PHONON_GSTREAMER_DIR/abstractrenderer.cpp \ $$PHONON_GSTREAMER_DIR/artssink.cpp \ + $$PHONON_GSTREAMER_DIR/audioeffect.cpp \ + $$PHONON_GSTREAMER_DIR/audiooutput.cpp \ + $$PHONON_GSTREAMER_DIR/audiodataoutput.cpp \ $$PHONON_GSTREAMER_DIR/backend.cpp \ $$PHONON_GSTREAMER_DIR/devicemanager.cpp \ $$PHONON_GSTREAMER_DIR/effect.cpp \ $$PHONON_GSTREAMER_DIR/effectmanager.cpp \ + $$PHONON_GSTREAMER_DIR/glrenderer.cpp \ $$PHONON_GSTREAMER_DIR/gsthelper.cpp \ - $$PHONON_GSTREAMER_DIR/mediaobject.cpp \ $$PHONON_GSTREAMER_DIR/medianode.cpp \ $$PHONON_GSTREAMER_DIR/medianodeevent.cpp \ - $$PHONON_GSTREAMER_DIR/widgetrenderer.cpp \ - $$PHONON_GSTREAMER_DIR/videowidget.cpp \ - $$PHONON_GSTREAMER_DIR/glrenderer.cpp \ - $$PHONON_GSTREAMER_DIR/qwidgetvideosink.cpp \ + $$PHONON_GSTREAMER_DIR/mediaobject.cpp \ + $$PHONON_GSTREAMER_DIR/message.cpp \ $$PHONON_GSTREAMER_DIR/phononsrc.cpp \ + $$PHONON_GSTREAMER_DIR/qwidgetvideosink.cpp \ $$PHONON_GSTREAMER_DIR/streamreader.cpp \ - $$PHONON_GSTREAMER_DIR/message.cpp \ - $$PHONON_GSTREAMER_DIR/audioeffect.cpp \ - $$PHONON_GSTREAMER_DIR/volumefadereffect.cpp + $$PHONON_GSTREAMER_DIR/videowidget.cpp \ + $$PHONON_GSTREAMER_DIR/volumefadereffect.cpp \ + $$PHONON_GSTREAMER_DIR/widgetrenderer.cpp !embedded { HEADERS += $$PHONON_GSTREAMER_DIR/x11renderer.h -- cgit v0.12 From 19a3fc3bd817628070e5637caf158b0be79eee82 Mon Sep 17 00:00:00 2001 From: Justin McPherson Date: Thu, 25 Mar 2010 14:00:31 +1000 Subject: Update Phonon ds9 backend to 4.4.0. --- src/3rdparty/phonon/ds9/abstractvideorenderer.cpp | 4 +- src/3rdparty/phonon/ds9/backend.cpp | 14 +- src/3rdparty/phonon/ds9/backend.h | 4 - src/3rdparty/phonon/ds9/backendnode.cpp | 19 -- src/3rdparty/phonon/ds9/ds9.desktop | 17 +- src/3rdparty/phonon/ds9/effect.cpp | 4 +- src/3rdparty/phonon/ds9/fakesource.cpp | 34 +++- src/3rdparty/phonon/ds9/iodevicereader.cpp | 92 ++++++--- src/3rdparty/phonon/ds9/iodevicereader.h | 1 + src/3rdparty/phonon/ds9/mediagraph.cpp | 38 ++-- src/3rdparty/phonon/ds9/mediaobject.cpp | 201 +++++++++++--------- src/3rdparty/phonon/ds9/mediaobject.h | 8 +- src/3rdparty/phonon/ds9/qasyncreader.cpp | 72 +++++--- src/3rdparty/phonon/ds9/qasyncreader.h | 6 +- src/3rdparty/phonon/ds9/qaudiocdreader.cpp | 54 ++++-- src/3rdparty/phonon/ds9/qaudiocdreader.h | 2 +- src/3rdparty/phonon/ds9/qbasefilter.cpp | 33 ++-- src/3rdparty/phonon/ds9/qbasefilter.h | 4 +- src/3rdparty/phonon/ds9/qevr9.h | 143 -------------- src/3rdparty/phonon/ds9/qmeminputpin.cpp | 113 ++++++++---- src/3rdparty/phonon/ds9/qmeminputpin.h | 9 +- src/3rdparty/phonon/ds9/qpin.cpp | 73 +++++--- src/3rdparty/phonon/ds9/qpin.h | 7 +- src/3rdparty/phonon/ds9/videorenderer_default.cpp | 153 --------------- src/3rdparty/phonon/ds9/videorenderer_default.h | 55 ------ src/3rdparty/phonon/ds9/videorenderer_evr.cpp | 215 ---------------------- src/3rdparty/phonon/ds9/videorenderer_evr.h | 56 ------ src/3rdparty/phonon/ds9/videorenderer_soft.cpp | 15 +- src/3rdparty/phonon/ds9/videorenderer_vmr9.cpp | 113 +++++++++++- src/3rdparty/phonon/ds9/videorenderer_vmr9.h | 1 + src/3rdparty/phonon/ds9/videowidget.cpp | 50 +---- src/3rdparty/phonon/ds9/volumeeffect.cpp | 5 +- src/3rdparty/phonon/ds9/volumeeffect.h | 2 +- 33 files changed, 621 insertions(+), 996 deletions(-) delete mode 100644 src/3rdparty/phonon/ds9/qevr9.h delete mode 100644 src/3rdparty/phonon/ds9/videorenderer_default.cpp delete mode 100644 src/3rdparty/phonon/ds9/videorenderer_default.h delete mode 100644 src/3rdparty/phonon/ds9/videorenderer_evr.cpp delete mode 100644 src/3rdparty/phonon/ds9/videorenderer_evr.h diff --git a/src/3rdparty/phonon/ds9/abstractvideorenderer.cpp b/src/3rdparty/phonon/ds9/abstractvideorenderer.cpp index a9d0694..e932e70 100644 --- a/src/3rdparty/phonon/ds9/abstractvideorenderer.cpp +++ b/src/3rdparty/phonon/ds9/abstractvideorenderer.cpp @@ -99,8 +99,8 @@ namespace Phonon m_dstX = m_dstY = 0; if (ratio > 0) { - if ((realWidth / realHeight > ratio && scaleMode == Phonon::VideoWidget::FitInView) - || (realWidth / realHeight < ratio && scaleMode == Phonon::VideoWidget::ScaleAndCrop)) { + if (realWidth / realHeight > ratio && scaleMode == Phonon::VideoWidget::FitInView + || realWidth / realHeight < ratio && scaleMode == Phonon::VideoWidget::ScaleAndCrop) { //the height is correct, let's change the width m_dstWidth = qRound(realHeight * ratio); m_dstX = qRound((realWidth - realHeight * ratio) / 2.); diff --git a/src/3rdparty/phonon/ds9/backend.cpp b/src/3rdparty/phonon/ds9/backend.cpp index fbc4bdc..2c56af7 100644 --- a/src/3rdparty/phonon/ds9/backend.cpp +++ b/src/3rdparty/phonon/ds9/backend.cpp @@ -41,8 +41,6 @@ namespace Phonon { namespace DS9 { - QMutex *Backend::directShowMutex = 0; - bool Backend::AudioMoniker::operator==(const AudioMoniker &other) { return other->IsEqual(*this) == S_OK; @@ -52,8 +50,6 @@ namespace Phonon Backend::Backend(QObject *parent, const QVariantList &) : QObject(parent) { - directShowMutex = &m_directShowMutex; - ::CoInitialize(0); //registering meta types @@ -66,8 +62,6 @@ namespace Phonon m_audioOutputs.clear(); m_audioEffects.clear(); ::CoUninitialize(); - - directShowMutex = 0; } QObject *Backend::createObject(BackendInterface::Class c, QObject *parent, const QList &args) @@ -137,7 +131,6 @@ namespace Phonon QList Backend::objectDescriptionIndexes(Phonon::ObjectDescriptionType type) const { - QMutexLocker locker(&m_directShowMutex); QList ret; switch(type) @@ -164,7 +157,7 @@ namespace Phonon while (S_OK == enumMon->Next(1, mon.pparam(), 0)) { LPOLESTR str = 0; mon->GetDisplayName(0,0,&str); - const QString name = QString::fromWCharArray(str); + const QString name = QString::fromUtf16((unsigned short*)str); ComPointer alloc; ::CoGetMalloc(1, alloc.pparam()); alloc->Free(str); @@ -211,7 +204,6 @@ namespace Phonon QHash Backend::objectDescriptionProperties(Phonon::ObjectDescriptionType type, int index) const { - QMutexLocker locker(&m_directShowMutex); QHash ret; switch (type) { @@ -224,7 +216,7 @@ namespace Phonon LPOLESTR str = 0; HRESULT hr = mon->GetDisplayName(0,0, &str); if (SUCCEEDED(hr)) { - QString name = QString::fromWCharArray(str); + QString name = QString::fromUtf16((unsigned short*)str); ComPointer alloc; ::CoGetMalloc(1, alloc.pparam()); alloc->Free(str); @@ -239,7 +231,7 @@ namespace Phonon WCHAR name[80]; // 80 is clearly stated in the MSDN doc HRESULT hr = ::DMOGetName(m_audioEffects[index], name); if (SUCCEEDED(hr)) { - ret["name"] = QString::fromWCharArray(name); + ret["name"] = QString::fromUtf16((unsigned short*)name); } } break; diff --git a/src/3rdparty/phonon/ds9/backend.h b/src/3rdparty/phonon/ds9/backend.h index 7c3c109..ad638f2 100644 --- a/src/3rdparty/phonon/ds9/backend.h +++ b/src/3rdparty/phonon/ds9/backend.h @@ -23,7 +23,6 @@ along with this library. If not, see . #include #include -#include #include "compointer.h" #include "backendnode.h" @@ -64,8 +63,6 @@ namespace Phonon Filter getAudioOutputFilter(int index) const; - static QMutex *directShowMutex; - Q_SIGNALS: void objectDescriptionChanged(ObjectDescriptionType); @@ -77,7 +74,6 @@ namespace Phonon }; mutable QVector m_audioOutputs; mutable QVector m_audioEffects; - mutable QMutex m_directShowMutex; }; } } diff --git a/src/3rdparty/phonon/ds9/backendnode.cpp b/src/3rdparty/phonon/ds9/backendnode.cpp index 737ab7b..7e0b3cd 100644 --- a/src/3rdparty/phonon/ds9/backendnode.cpp +++ b/src/3rdparty/phonon/ds9/backendnode.cpp @@ -57,25 +57,6 @@ namespace Phonon BackendNode::~BackendNode() { - //this will remove the filter from the graph - FILTER_INFO info; - for(int i = 0; i < FILTER_COUNT; ++i) { - const Filter &filter = m_filters[i]; - if (!filter) - continue; - filter->QueryFilterInfo(&info); - if (info.pGraph) { - HRESULT hr = info.pGraph->RemoveFilter(filter); - - if (FAILED(hr) && m_mediaObject) { - m_mediaObject->ensureStopped(); - - hr = info.pGraph->RemoveFilter(filter); - } - Q_ASSERT(SUCCEEDED(hr)); - info.pGraph->Release(); - } - } } void BackendNode::setMediaObject(MediaObject *mo) diff --git a/src/3rdparty/phonon/ds9/ds9.desktop b/src/3rdparty/phonon/ds9/ds9.desktop index 764390e..1bc3451 100644 --- a/src/3rdparty/phonon/ds9/ds9.desktop +++ b/src/3rdparty/phonon/ds9/ds9.desktop @@ -5,12 +5,13 @@ MimeType=application/x-annodex;video/quicktime;video/x-quicktime;audio/x-m4a;app X-KDE-Library=phonon_ds9 X-KDE-PhononBackendInfo-InterfaceVersion=1 X-KDE-PhononBackendInfo-Version=0.1 -X-KDE-PhononBackendInfo-Website=http://qt.nokia.com/ +X-KDE-PhononBackendInfo-Website=http://www.trolltech.com/ InitialPreference=15 Name=DirectShow9 Name[bg]=DirectShow9 Name[ca]=DirectShow9 +Name[ca@valencia]=DirectShow9 Name[cs]=DirectShow9 Name[da]=DirectShow9 Name[de]=DirectShow9 @@ -19,11 +20,14 @@ Name[en_GB]=DirectShow9 Name[es]=DirectShow9 Name[et]=DirectShow9 Name[eu]=DirectShow9 +Name[fi]=DirectShow9 Name[fr]=DirectShow9 Name[ga]=DirectShow9 Name[gl]=DirectShow9 +Name[hr]=DirectShow9 Name[hsb]=DirectShow9 Name[hu]=DirectShow9 +Name[id]=DirectShow9 Name[is]=DirectShow9 Name[it]=DirectShow9 Name[ja]=DirectShow9 @@ -31,6 +35,7 @@ Name[ko]=DirectShow9 Name[ku]=DirectShow9 Name[lt]=DirectShow9 Name[lv]=DirectShow9 +Name[nb]=DirectShow9 Name[nds]=DirectShow9 Name[nl]=DirectShow9 Name[nn]=DirectShow9 @@ -38,10 +43,13 @@ Name[pa]=ਡਾਇਰੈਕਸ਼ੋ9 Name[pl]=DirectShow9 Name[pt]=DirectShow9 Name[pt_BR]=DirectShow9 +Name[ru]=DirectShow9 Name[se]=DirectShow9 Name[sk]=DirectShow 9 Name[sl]=DirectShow 9 Name[sr]=Директшоу‑9 +Name[sr@ijekavian]=Директшоу‑9 +Name[sr@ijekavianlatin]=DirectShow‑9 Name[sr@latin]=DirectShow‑9 Name[sv]=Directshow 9 Name[tr]=DirectShow9 @@ -53,6 +61,7 @@ Name[zh_TW]=DirectShow9 Comment=Phonon DirectShow9 backend Comment[bg]=Phonon DirectShow9 Comment[ca]=Dorsal DirectShow9 del Phonon +Comment[ca@valencia]=Dorsal DirectShow9 del Phonon Comment[cs]=Phonon DirectShow9 backend Comment[da]=DirectShow9-backend til Phonon Comment[de]=Phonon-Treiber für DirectShow9 @@ -61,11 +70,13 @@ Comment[en_GB]=Phonon DirectShow9 backend Comment[es]=Motor DirectShow9 para Phonon Comment[et]=Phononi DirectShow9 taustaprogramm Comment[eu]=Phonon DirectShow9 backend +Comment[fi]=Phonon DirectShow9-taustaohjelma Comment[fr]=Système de gestion DirectShow9 pour Phonon Comment[ga]=Inneall DirectShow9 le haghaidh Phonon Comment[gl]=Infraestrutura de DirectShow9 para Phonon Comment[hsb]=Phonon DirectShow9 backend Comment[hu]=Phonon DirectShow9 modul +Comment[id]=Phonon DirectShow9 backend Comment[is]=Phonon DirectShow9 bakendi Comment[it]=Motore DirectShow9 di Phonon Comment[ja]=Phonon DirectShow9 バックエンド @@ -73,6 +84,7 @@ Comment[ko]=Phonon DirectShow9 백엔드 Comment[ku]=Binesaza Phonon DirectShow9 Comment[lt]=Phonon DirectShow9 galinė sąsaja Comment[lv]=Phonon DirectShow9 aizmugure +Comment[nb]=Phonon-motor for DirectShow9 Comment[nds]=Phonon-Hülpprogrmm DirectShow9 Comment[nl]=DirectShow9-backend (Phonon) Comment[nn]=Phonon-motor for DirectShow9 @@ -80,10 +92,13 @@ Comment[pa]=ਫੋਨੋਨ ਡਾਇਰੈਕਟਸ਼ੋ9 ਬੈਕਐਂਡ Comment[pl]=Obsługa DirectShow9 przez Phonon Comment[pt]=Infra-estrutura do DirectShow9 para o Phonon Comment[pt_BR]=Infraestrutura Phonon DirectShow9 +Comment[ru]=Механизм DirectShow9 для Phonon Comment[se]=Phonon DirectShow9 duogášmohtor Comment[sk]=Phonon DirectShow 9 podsystém Comment[sl]=Phononova Hrbtenica DirectShow 9 Comment[sr]=Директшоу‑9 као позадина Фонона +Comment[sr@ijekavian]=Директшоу‑9 као позадина Фонона +Comment[sr@ijekavianlatin]=DirectShow‑9 kao pozadina Phonona Comment[sr@latin]=DirectShow‑9 kao pozadina Phonona Comment[sv]=Phonon Directshow 9-gränssnitt Comment[tr]=Phonon DirectShow9 arka ucu diff --git a/src/3rdparty/phonon/ds9/effect.cpp b/src/3rdparty/phonon/ds9/effect.cpp index ebe976b..104a3c1 100644 --- a/src/3rdparty/phonon/ds9/effect.cpp +++ b/src/3rdparty/phonon/ds9/effect.cpp @@ -82,7 +82,7 @@ namespace Phonon current += wcslen(current) + 1; //skip the name current += wcslen(current) + 1; //skip the unit for(; *current; current += wcslen(current) + 1) { - values.append( QString::fromWCharArray(current) ); + values.append( QString::fromUtf16((unsigned short*)current) ); } } //FALLTHROUGH @@ -107,7 +107,7 @@ namespace Phonon Phonon::EffectParameter::Hints hint = info.mopCaps == MP_CAPS_CURVE_INVSQUARE ? Phonon::EffectParameter::LogarithmicHint : Phonon::EffectParameter::Hints(0); - const QString n = QString::fromWCharArray(name); + const QString n = QString::fromUtf16((unsigned short*)name); ret.append(Phonon::EffectParameter(i, n, hint, def, min, max, values)); ::CoTaskMemFree(name); //let's free the memory } diff --git a/src/3rdparty/phonon/ds9/fakesource.cpp b/src/3rdparty/phonon/ds9/fakesource.cpp index 4dce138..9a61a2e 100644 --- a/src/3rdparty/phonon/ds9/fakesource.cpp +++ b/src/3rdparty/phonon/ds9/fakesource.cpp @@ -29,10 +29,8 @@ namespace Phonon namespace DS9 { static WAVEFORMATEX g_defaultWaveFormat = {WAVE_FORMAT_PCM, 2, 44100, 176400, 4, 16, 0}; - static VIDEOINFOHEADER2 g_defaultVideoInfo = { { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, 0, 0, 0, 0, 0, 0, 0, {0}, 0, {sizeof(BITMAPINFOHEADER), 1, 1, 1, 0, 0, 0, 0, 0, 0, 0} }; - - static const AM_MEDIA_TYPE g_fakeAudioType = {MEDIATYPE_Audio, MEDIASUBTYPE_PCM, 0, 0, 2, FORMAT_WaveFormatEx, 0, sizeof(WAVEFORMATEX), reinterpret_cast(&g_defaultWaveFormat)}; - static const AM_MEDIA_TYPE g_fakeVideoType = {MEDIATYPE_Video, MEDIASUBTYPE_RGB32, TRUE, FALSE, 0, FORMAT_VideoInfo2, 0, sizeof(VIDEOINFOHEADER2), reinterpret_cast(&g_defaultVideoInfo)}; + static BITMAPINFOHEADER g_defautBitmapHeader = { sizeof(BITMAPINFOHEADER), 1, 1, 1, 0, 0, 0, 0, 0, 0, 0}; + static VIDEOINFOHEADER2 g_defaultVideoInfo = { { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; class FakePin : public QPin { @@ -130,12 +128,36 @@ namespace Phonon void FakeSource::createFakeAudioPin() { - new FakePin(this, g_fakeAudioType); + AM_MEDIA_TYPE mt; + qMemSet(&mt, 0, sizeof(AM_MEDIA_TYPE)); + mt.majortype = MEDIATYPE_Audio; + mt.subtype = MEDIASUBTYPE_PCM; + mt.formattype = FORMAT_WaveFormatEx; + mt.lSampleSize = 2; + + //fake the format (stereo 44.1 khz stereo 16 bits) + mt.cbFormat = sizeof(WAVEFORMATEX); + mt.pbFormat = reinterpret_cast(&g_defaultWaveFormat); + + new FakePin(this, mt); } void FakeSource::createFakeVideoPin() { - new FakePin(this, g_fakeVideoType); + AM_MEDIA_TYPE mt; + qMemSet(&mt, 0, sizeof(AM_MEDIA_TYPE)); + mt.majortype = MEDIATYPE_Video; + mt.subtype = MEDIASUBTYPE_RGB32; + mt.formattype = FORMAT_VideoInfo2; + mt.bFixedSizeSamples = 1; + + g_defaultVideoInfo.bmiHeader = g_defautBitmapHeader; + + //fake the format + mt.cbFormat = sizeof(VIDEOINFOHEADER2); + mt.pbFormat = reinterpret_cast(&g_defaultVideoInfo); + + new FakePin(this, mt); } } diff --git a/src/3rdparty/phonon/ds9/iodevicereader.cpp b/src/3rdparty/phonon/ds9/iodevicereader.cpp index 695af59..2dff1fe 100644 --- a/src/3rdparty/phonon/ds9/iodevicereader.cpp +++ b/src/3rdparty/phonon/ds9/iodevicereader.cpp @@ -36,20 +36,18 @@ namespace Phonon //these mediatypes define a stream, its type will be autodetected by DirectShow static QVector getMediaTypes() { - //the order here is important because otherwise, - //directshow might not be able to detect the stream type correctly - - AM_MEDIA_TYPE mt = { MEDIATYPE_Stream, MEDIASUBTYPE_Avi, TRUE, FALSE, 1, GUID_NULL, 0, 0, 0}; + AM_MEDIA_TYPE mt = { MEDIATYPE_Stream, MEDIASUBTYPE_NULL, TRUE, FALSE, 1, GUID_NULL, 0, 0, 0}; QVector ret; + //normal auto-detect stream + mt.subtype = MEDIASUBTYPE_NULL; + ret << mt; //AVI stream + mt.subtype = MEDIASUBTYPE_Avi; ret << mt; //WAVE stream mt.subtype = MEDIASUBTYPE_WAVE; ret << mt; - //normal auto-detect stream (must be at the end!) - mt.subtype = MEDIASUBTYPE_NULL; - ret << mt; return ret; } @@ -66,6 +64,7 @@ namespace Phonon //for Phonon::StreamInterface void writeData(const QByteArray &data) { + QWriteLocker locker(&m_lock); m_pos += data.size(); m_buffer += data; } @@ -76,22 +75,54 @@ namespace Phonon void setStreamSize(qint64 newSize) { - QMutexLocker locker(&m_mutex); + QWriteLocker locker(&m_lock); m_size = newSize; } + qint64 streamSize() const + { + QReadLocker locker(&m_lock); + return m_size; + } + void setStreamSeekable(bool s) { - QMutexLocker locker(&m_mutex); + QWriteLocker locker(&m_lock); m_seekable = s; } + bool streamSeekable() const + { + QReadLocker locker(&m_lock); + return m_seekable; + } + + void setCurrentPos(qint64 pos) + { + QWriteLocker locker(&m_lock); + m_pos = pos; + seekStream(pos); + m_buffer.clear(); + } + + qint64 currentPos() const + { + QReadLocker locker(&m_lock); + return m_pos; + } + + int currentBufferSize() const + { + QReadLocker locker(&m_lock); + return m_buffer.size(); + } + //virtual pure members //implementation from IAsyncReader STDMETHODIMP Length(LONGLONG *total, LONGLONG *available) { - QMutexLocker locker(&m_mutex); + QReadLocker locker(&m_lock); if (total) { *total = m_size; } @@ -106,42 +137,44 @@ namespace Phonon HRESULT read(LONGLONG pos, LONG length, BYTE *buffer, LONG *actual) { - Q_ASSERT(!m_mutex.tryLock()); + QMutexLocker locker(&m_mutexRead); + if (m_mediaGraph->isStopping()) { return VFW_E_WRONG_STATE; } - if(m_size != 1 && pos + length > m_size) { + if(streamSize() != 1 && pos + length > streamSize()) { //it tries to read outside of the boundaries return E_FAIL; } - if (m_pos - m_buffer.size() != pos) { - if (!m_seekable) { + if (currentPos() - currentBufferSize() != pos) { + if (!streamSeekable()) { return S_FALSE; } - m_pos = pos; - seekStream(pos); - m_buffer.clear(); + setCurrentPos(pos); } - int oldSize = m_buffer.size(); - while (m_buffer.size() < int(length)) { + int oldSize = currentBufferSize(); + while (currentBufferSize() < int(length)) { needData(); if (m_mediaGraph->isStopping()) { return VFW_E_WRONG_STATE; } - if (oldSize == m_buffer.size()) { + if (oldSize == currentBufferSize()) { break; //we didn't get any data } - oldSize = m_buffer.size(); + oldSize = currentBufferSize(); } - int bytesRead = qMin(m_buffer.size(), int(length)); - qMemCopy(buffer, m_buffer.data(), bytesRead); - //truncate the buffer - m_buffer = m_buffer.mid(bytesRead); + DWORD bytesRead = qMin(currentBufferSize(), int(length)); + { + QWriteLocker locker(&m_lock); + qMemCopy(buffer, m_buffer.data(), bytesRead); + //truncate the buffer + m_buffer = m_buffer.mid(bytesRead); + } if (actual) { *actual = bytesRead; //initialization @@ -157,6 +190,7 @@ namespace Phonon qint64 m_pos; qint64 m_size; + QMutex m_mutexRead; const MediaGraph *m_mediaGraph; }; @@ -170,6 +204,14 @@ namespace Phonon IODeviceReader::~IODeviceReader() { } + + STDMETHODIMP IODeviceReader::Stop() + { + HRESULT hr = QBaseFilter::Stop(); + m_streamReader->enoughData(); //this asks to cancel any blocked call to needData + return hr; + } + } } diff --git a/src/3rdparty/phonon/ds9/iodevicereader.h b/src/3rdparty/phonon/ds9/iodevicereader.h index c8b91c3..af4b271 100644 --- a/src/3rdparty/phonon/ds9/iodevicereader.h +++ b/src/3rdparty/phonon/ds9/iodevicereader.h @@ -41,6 +41,7 @@ namespace Phonon public: IODeviceReader(const MediaSource &source, const MediaGraph *); ~IODeviceReader(); + STDMETHODIMP Stop(); private: StreamReader *m_streamReader; diff --git a/src/3rdparty/phonon/ds9/mediagraph.cpp b/src/3rdparty/phonon/ds9/mediagraph.cpp index 3e7a68b..db0ec84 100644 --- a/src/3rdparty/phonon/ds9/mediagraph.cpp +++ b/src/3rdparty/phonon/ds9/mediagraph.cpp @@ -68,8 +68,6 @@ namespace Phonon return ret; } - -/* static HRESULT saveToFile(Graph graph, const QString &filepath) { const WCHAR wszStreamName[] = L"ActiveMovieGraph"; @@ -105,7 +103,7 @@ namespace Phonon return hr; } -*/ + MediaGraph::MediaGraph(MediaObject *mo, short index) : m_graph(CLSID_FilterGraph, IID_IGraphBuilder), @@ -379,12 +377,11 @@ namespace Phonon FILTER_INFO info; filter->QueryFilterInfo(&info); #ifdef GRAPH_DEBUG - qDebug() << "removeFilter" << QString((const QChar *)info.achName); + qDebug() << "removeFilter" << QString::fromUtf16(info.achName); #endif if (info.pGraph) { info.pGraph->Release(); - if (info.pGraph == m_graph) - return m_graph->RemoveFilter(filter); + return m_graph->RemoveFilter(filter); } //already removed @@ -540,11 +537,11 @@ namespace Phonon const QList outputs = BackendNode::pins(filter, PINDIR_OUTPUT); for(int i = 0; i < outputs.count(); ++i) { const OutputPin &pin = outputs.at(i); - if (HRESULT(VFW_E_NOT_CONNECTED) == pin->ConnectedTo(inPin.pparam())) { + if (VFW_E_NOT_CONNECTED == pin->ConnectedTo(inPin.pparam())) { return SUCCEEDED(pin->Connect(newIn, 0)); } } - //we shoud never go here + //we should never go here return false; } else { QAMMediaType type; @@ -682,6 +679,7 @@ namespace Phonon #ifndef QT_NO_PHONON_MEDIACONTROLLER } else if (source.discType() == Phonon::Cd) { m_realSource = Filter(new QAudioCDPlayer); + m_result = m_graph->AddFilter(m_realSource, 0); #endif //QT_NO_PHONON_MEDIACONTROLLER } else { @@ -811,7 +809,7 @@ namespace Phonon for (int i = 0; i < outputs.count(); ++i) { const OutputPin &out = outputs.at(i); InputPin pin; - if (out->ConnectedTo(pin.pparam()) == HRESULT(VFW_E_NOT_CONNECTED)) { + if (out->ConnectedTo(pin.pparam()) == VFW_E_NOT_CONNECTED) { m_decoderPins += out; //unconnected outputs can be decoded outputs } } @@ -822,7 +820,7 @@ namespace Phonon //let's reestablish the connections for (int i = 0; i < connections.count(); ++i) { const GraphConnection &connection = connections.at(i); - //check if we shoud transfer the sink node + //check if we should transfer the sink node grabFilter(connection.input); grabFilter(connection.output); @@ -875,7 +873,7 @@ namespace Phonon { FILTER_INFO info; filter->QueryFilterInfo(&info); - qDebug() << Q_FUNC_INFO << QString((const QChar *)info.achName); + qDebug() << Q_FUNC_INFO << QString::fromUtf16(info.achName); if (info.pGraph) { info.pGraph->Release(); } @@ -921,7 +919,7 @@ namespace Phonon { FILTER_INFO info; filter->QueryFilterInfo(&info); - qDebug() << "found a decoder filter" << QString((const QChar *)info.achName); + qDebug() << "found a decoder filter" << QString::fromUtf16(info.achName); if (info.pGraph) { info.pGraph->Release(); } @@ -937,7 +935,7 @@ namespace Phonon { FILTER_INFO info; filter->QueryFilterInfo(&info); - qDebug() << Q_FUNC_INFO << QString((const QChar *)info.achName); + qDebug() << Q_FUNC_INFO << QString::fromUtf16(info.achName); if (info.pGraph) { info.pGraph->Release(); } @@ -956,7 +954,7 @@ namespace Phonon { FILTER_INFO info; filter->QueryFilterInfo(&info); - qDebug() << Q_FUNC_INFO << QString((const QChar *)info.achName); + qDebug() << Q_FUNC_INFO << QString::fromUtf16(info.achName); if (info.pGraph) { info.pGraph->Release(); } @@ -990,7 +988,7 @@ namespace Phonon { FILTER_INFO info; filter->QueryFilterInfo(&info); - qDebug() << "found a demuxer filter" << QString((const QChar *)info.achName); + qDebug() << "found a demuxer filter" << QString::fromUtf16(info.achName); if (info.pGraph) { info.pGraph->Release(); } @@ -1008,27 +1006,27 @@ namespace Phonon BSTR str; HRESULT hr = mediaContent->get_AuthorName(&str); if (SUCCEEDED(hr)) { - ret.insert(QLatin1String("ARTIST"), QString::fromWCharArray(str)); + ret.insert(QLatin1String("ARTIST"), QString::fromUtf16((const unsigned short*)str)); SysFreeString(str); } hr = mediaContent->get_Title(&str); if (SUCCEEDED(hr)) { - ret.insert(QLatin1String("TITLE"), QString::fromWCharArray(str)); + ret.insert(QLatin1String("TITLE"), QString::fromUtf16((const unsigned short*)str)); SysFreeString(str); } hr = mediaContent->get_Description(&str); if (SUCCEEDED(hr)) { - ret.insert(QLatin1String("DESCRIPTION"), QString::fromWCharArray(str)); + ret.insert(QLatin1String("DESCRIPTION"), QString::fromUtf16((const unsigned short*)str)); SysFreeString(str); } hr = mediaContent->get_Copyright(&str); if (SUCCEEDED(hr)) { - ret.insert(QLatin1String("COPYRIGHT"), QString::fromWCharArray(str)); + ret.insert(QLatin1String("COPYRIGHT"), QString::fromUtf16((const unsigned short*)str)); SysFreeString(str); } hr = mediaContent->get_MoreInfoText(&str); if (SUCCEEDED(hr)) { - ret.insert(QLatin1String("MOREINFO"), QString::fromWCharArray(str)); + ret.insert(QLatin1String("MOREINFO"), QString::fromUtf16((const unsigned short*)str)); SysFreeString(str); } } diff --git a/src/3rdparty/phonon/ds9/mediaobject.cpp b/src/3rdparty/phonon/ds9/mediaobject.cpp index 34f92c2..d1e15c0 100644 --- a/src/3rdparty/phonon/ds9/mediaobject.cpp +++ b/src/3rdparty/phonon/ds9/mediaobject.cpp @@ -23,10 +23,11 @@ along with this library. If not, see . #ifndef Q_CC_MSVC #include -#endif +#endif //Q_CC_MSVC #include #include #include +#include #include #include "mediaobject.h" @@ -49,7 +50,7 @@ namespace Phonon //first the definition of the WorkerThread class WorkerThread::WorkerThread() - : QThread(), m_finished(false), m_currentWorkId(1) + : QThread(), m_currentRenderId(0), m_finished(false), m_currentWorkId(1) { } @@ -57,6 +58,24 @@ namespace Phonon { } + WorkerThread::Work WorkerThread::dequeueWork() + { + QMutexLocker locker(&m_mutex); + if (m_finished) { + return Work(); + } + Work ret = m_queue.dequeue(); + + //we ensure to have the wait condition in the right state + if (m_queue.isEmpty()) { + m_waitCondition.reset(); + } else { + m_waitCondition.set(); + } + + return ret; + } + void WorkerThread::run() { while (m_finished == false) { @@ -70,6 +89,11 @@ namespace Phonon } DWORD result = ::WaitForMultipleObjects(count, handles, FALSE, INFINITE); if (result == WAIT_OBJECT_0) { + if (m_finished) { + //that's the end of the thread execution + return; + } + handleTask(); } else { //this is the event management @@ -157,7 +181,6 @@ namespace Phonon //we create a new graph w.graph = Graph(CLSID_FilterGraph, IID_IGraphBuilder); w.filter = filter; - w.graph->AddFilter(filter, 0); w.id = m_currentWorkId++; m_queue.enqueue(w); m_waitCondition.set(); @@ -177,29 +200,23 @@ namespace Phonon void WorkerThread::handleTask() { - QMutexLocker locker(Backend::directShowMutex); - { - QMutexLocker locker(&m_mutex); - if (m_finished || m_queue.isEmpty()) { - return; - } - - m_currentWork = m_queue.dequeue(); + const Work w = dequeueWork(); - //we ensure to have the wait condition in the right state - if (m_queue.isEmpty()) { - m_waitCondition.reset(); - } else { - m_waitCondition.set(); - } + if (m_finished) { + return; } HRESULT hr = S_OK; - if (m_currentWork.task == ReplaceGraph) { + m_currentRender = w.graph; + m_currentRenderId = w.id; + if (w.task == ReplaceGraph) { + QMutexLocker locker(&m_mutex); + HANDLE h; + int index = -1; for(int i = 0; i < FILTER_COUNT; ++i) { - if (m_graphHandle[i].graph == m_currentWork.oldGraph) { + if (m_graphHandle[i].graph == w.oldGraph) { m_graphHandle[i].graph = Graph(); index = i; break; @@ -212,40 +229,51 @@ namespace Phonon Q_ASSERT(index != -1); //add the new graph - HANDLE h; - if (SUCCEEDED(ComPointer(m_currentWork.graph, IID_IMediaEvent) + if (SUCCEEDED(ComPointer(w.graph, IID_IMediaEvent) ->GetEventHandle(reinterpret_cast(&h)))) { - m_graphHandle[index].graph = m_currentWork.graph; + m_graphHandle[index].graph = w.graph; m_graphHandle[index].handle = h; } - } else if (m_currentWork.task == Render) { - if (m_currentWork.filter) { + } else if (w.task == Render) { + if (w.filter) { //let's render pins - const QList outputs = BackendNode::pins(m_currentWork.filter, PINDIR_OUTPUT); - for (int i = 0; SUCCEEDED(hr) && i < outputs.count(); ++i) { - hr = m_currentWork.graph->Render(outputs.at(i)); + w.graph->AddFilter(w.filter, 0); + const QList outputs = BackendNode::pins(w.filter, PINDIR_OUTPUT); + for (int i = 0; i < outputs.count(); ++i) { + //blocking call + hr = w.graph->Render(outputs.at(i)); + if (FAILED(hr)) { + break; + } } - } else if (!m_currentWork.url.isEmpty()) { + } else if (!w.url.isEmpty()) { //let's render a url (blocking call) - hr = m_currentWork.graph->RenderFile(reinterpret_cast(m_currentWork.url.utf16()), 0); + hr = w.graph->RenderFile(reinterpret_cast(w.url.utf16()), 0); } if (hr != E_ABORT) { - emit asyncRenderFinished(m_currentWork.id, hr, m_currentWork.graph); + emit asyncRenderFinished(w.id, hr, w.graph); } - } else if (m_currentWork.task == Seek) { + } else if (w.task == Seek) { //that's a seekrequest - ComPointer mediaSeeking(m_currentWork.graph, IID_IMediaSeeking); - qint64 newtime = m_currentWork.time * 10000; + ComPointer mediaSeeking(w.graph, IID_IMediaSeeking); + qint64 newtime = w.time * 10000; hr = mediaSeeking->SetPositions(&newtime, AM_SEEKING_AbsolutePositioning, 0, AM_SEEKING_NoPositioning); - emit asyncSeekingFinished(m_currentWork.id, newtime / 10000); + qint64 currentTime = -1; + if (SUCCEEDED(hr)) { + hr = mediaSeeking->GetCurrentPosition(¤tTime); + if (SUCCEEDED(hr)) { + currentTime /= 10000; //convert to ms + } + } + emit asyncSeekingFinished(w.id, currentTime); hr = E_ABORT; //to avoid emitting asyncRenderFinished - } else if (m_currentWork.task == ChangeState) { + } else if (w.task == ChangeState) { //remove useless decoders QList unused; - for (int i = 0; i < m_currentWork.decoders.count(); ++i) { - const Filter &filter = m_currentWork.decoders.at(i); + for (int i = 0; i < w.decoders.count(); ++i) { + const Filter &filter = w.decoders.at(i); bool used = false; const QList pins = BackendNode::pins(filter, PINDIR_OUTPUT); for( int i = 0; i < pins.count(); ++i) { @@ -262,15 +290,15 @@ namespace Phonon //we can get the state for (int i = 0; i < unused.count(); ++i) { //we should remove this filter from the graph - m_currentWork.graph->RemoveFilter(unused.at(i)); + w.graph->RemoveFilter(unused.at(i)); } //we can get the state - ComPointer mc(m_currentWork.graph, IID_IMediaControl); + ComPointer mc(w.graph, IID_IMediaControl); //we change the state here - switch(m_currentWork.state) + switch(w.state) { case State_Stopped: mc->Stop(); @@ -288,38 +316,36 @@ namespace Phonon if (SUCCEEDED(hr)) { if (s == State_Stopped) { - emit stateReady(m_currentWork.graph, Phonon::StoppedState); + emit stateReady(w.graph, Phonon::StoppedState); } else if (s == State_Paused) { - emit stateReady(m_currentWork.graph, Phonon::PausedState); + emit stateReady(w.graph, Phonon::PausedState); } else /*if (s == State_Running)*/ { - emit stateReady(m_currentWork.graph, Phonon::PlayingState); + emit stateReady(w.graph, Phonon::PlayingState); } } } - { - QMutexLocker locker(&m_mutex); - m_currentWork = Work(); //reinitialize - } + m_currentRender = Graph(); + m_currentRenderId = 0; + } - void WorkerThread::abortCurrentRender(qint16 renderId) - { + void WorkerThread::abortCurrentRender(qint16 renderId) + { QMutexLocker locker(&m_mutex); - if (m_currentWork.id == renderId) { - m_currentWork.graph->Abort(); - } bool found = false; + //we try to see if there is already an attempt to seek and we remove it for(int i = 0; !found && i < m_queue.size(); ++i) { const Work &w = m_queue.at(i); if (w.id == renderId) { found = true; m_queue.removeAt(i); - if (m_queue.isEmpty()) { - m_waitCondition.reset(); - } } } + + if (m_currentRender && m_currentRenderId == renderId) { + m_currentRender->Abort(); + } } //tells the thread to stop processing @@ -327,9 +353,9 @@ namespace Phonon { QMutexLocker locker(&m_mutex); m_queue.clear(); - if (m_currentWork.graph) { + if (m_currentRender) { //in case we're currently rendering something - m_currentWork.graph->Abort(); + m_currentRender->Abort(); } @@ -361,17 +387,17 @@ namespace Phonon m_graphs[i] = new MediaGraph(this, i); } - connect(&m_thread, SIGNAL(stateReady(Graph,Phonon::State)), - SLOT(slotStateReady(Graph,Phonon::State))); + connect(&m_thread, SIGNAL(stateReady(Graph, Phonon::State)), + SLOT(slotStateReady(Graph, Phonon::State))); - connect(&m_thread, SIGNAL(eventReady(Graph,long,long)), - SLOT(handleEvents(Graph,long,long))); + connect(&m_thread, SIGNAL(eventReady(Graph, long, long)), + SLOT(handleEvents(Graph, long, long))); - connect(&m_thread, SIGNAL(asyncRenderFinished(quint16,HRESULT,Graph)), - SLOT(finishLoading(quint16,HRESULT,Graph))); + connect(&m_thread, SIGNAL(asyncRenderFinished(quint16, HRESULT, Graph)), + SLOT(finishLoading(quint16, HRESULT, Graph))); - connect(&m_thread, SIGNAL(asyncSeekingFinished(quint16,qint64)), - SLOT(finishSeeking(quint16,qint64))); + connect(&m_thread, SIGNAL(asyncSeekingFinished(quint16, qint64)), + SLOT(finishSeeking(quint16, qint64))); //really special case m_mediaObject = this; m_thread.start(); @@ -494,18 +520,6 @@ namespace Phonon qSwap(m_graphs[0], m_graphs[1]); //swap the graphs - if (m_transitionTime >= 0) - m_graphs[1]->stop(); //make sure we stop the previous graph - - if (currentGraph()->mediaSource().type() != Phonon::MediaSource::Invalid && - catchComError(currentGraph()->renderResult())) { - setState(Phonon::ErrorState); - return; - } - - //we need to play the next media - play(); - //we tell the video widgets to switch now to the new source #ifndef QT_NO_PHONON_VIDEO for (int i = 0; i < m_videoWidgets.count(); ++i) { @@ -514,6 +528,15 @@ namespace Phonon #endif //QT_NO_PHONON_VIDEO emit currentSourceChanged(currentGraph()->mediaSource()); + + if (currentGraph()->isLoading()) { + //will simply tell that when loading is finished + //it should start the playback + play(); + } + + + emit metaDataChanged(currentGraph()->metadata()); if (nextGraph()->hasVideo() != currentGraph()->hasVideo()) { @@ -526,6 +549,15 @@ namespace Phonon #ifndef QT_NO_PHONON_MEDIACONTROLLER setTitles(currentGraph()->titles()); #endif //QT_NO_PHONON_MEDIACONTROLLER + + //this manages only gapless transitions + if (currentGraph()->mediaSource().type() != Phonon::MediaSource::Invalid) { + if (catchComError(currentGraph()->renderResult())) { + setState(Phonon::ErrorState); + } else { + play(); + } + } } Phonon::State MediaObject::state() const @@ -760,16 +792,15 @@ namespace Phonon case Phonon::PausedState: pause(); break; + case Phonon::StoppedState: + stop(); + break; case Phonon::PlayingState: play(); break; case Phonon::ErrorState: setState(Phonon::ErrorState); break; - case Phonon::StoppedState: - default: - stop(); - break; } } } @@ -817,11 +848,11 @@ namespace Phonon #endif LPAMGETERRORTEXT getErrorText = (LPAMGETERRORTEXT)QLibrary::resolve(QLatin1String("quartz"), "AMGetErrorTextW"); - WCHAR buffer[MAX_ERROR_TEXT_LEN]; - if (getErrorText && getErrorText(hr, buffer, MAX_ERROR_TEXT_LEN)) { - m_errorString = QString::fromWCharArray(buffer); + ushort buffer[MAX_ERROR_TEXT_LEN]; + if (getErrorText && getErrorText(hr, (WCHAR*)buffer, MAX_ERROR_TEXT_LEN)) { + m_errorString = QString::fromUtf16(buffer); } else { - m_errorString = QString::fromLatin1("Unknown error"); + m_errorString = QString::fromUtf16((ushort*)_com_error(hr).ErrorMessage()); } const QString comError = QString::number(uint(hr), 16); if (!m_errorString.toLower().contains(comError.toLower())) { diff --git a/src/3rdparty/phonon/ds9/mediaobject.h b/src/3rdparty/phonon/ds9/mediaobject.h index 34aa666..2c34ffc 100644 --- a/src/3rdparty/phonon/ds9/mediaobject.h +++ b/src/3rdparty/phonon/ds9/mediaobject.h @@ -114,7 +114,6 @@ namespace Phonon enum Task { - None, Render, Seek, ChangeState, @@ -123,7 +122,6 @@ namespace Phonon struct Work { - Work() : task(None), id(0), time(0) { } Task task; quint16 id; Graph graph; @@ -137,14 +135,16 @@ namespace Phonon }; QList decoders; //for the state change requests }; + Work dequeueWork(); void handleTask(); - Work m_currentWork; + Graph m_currentRender; + qint16 m_currentRenderId; QQueue m_queue; bool m_finished; quint16 m_currentWorkId; QWinWaitCondition m_waitCondition; - QMutex m_mutex; // mutex for the m_queue, m_finished and m_currentWorkId + QMutex m_mutex; //this is for WaitForMultipleObjects struct diff --git a/src/3rdparty/phonon/ds9/qasyncreader.cpp b/src/3rdparty/phonon/ds9/qasyncreader.cpp index a3f9cda..68ec1f8 100644 --- a/src/3rdparty/phonon/ds9/qasyncreader.cpp +++ b/src/3rdparty/phonon/ds9/qasyncreader.cpp @@ -15,6 +15,8 @@ You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . */ +#include + #include "qasyncreader.h" #include "qbasefilter.h" @@ -78,7 +80,8 @@ namespace Phonon STDMETHODIMP QAsyncReader::Request(IMediaSample *sample,DWORD_PTR user) { - QMutexLocker locker(&m_mutex); + QMutexLocker mutexLocker(&m_mutexWait); + QWriteLocker locker(&m_lock); if (m_flushing) { return VFW_E_WRONG_STATE; } @@ -90,28 +93,33 @@ namespace Phonon STDMETHODIMP QAsyncReader::WaitForNext(DWORD timeout, IMediaSample **sample, DWORD_PTR *user) { - QMutexLocker locker(&m_mutex); + QMutexLocker locker(&m_mutexWait); if (!sample ||!user) { return E_POINTER; } - //msdn says to return immediately if we're flushing but that doesn't seem to be true - //since it triggers a dead-lock somewhere inside directshow (see task 258830) - *sample = 0; *user = 0; - if (m_requestQueue.isEmpty()) { - if (m_requestWait.wait(&m_mutex, timeout) == false) { - return VFW_E_TIMEOUT; - } - if (m_requestQueue.isEmpty()) { + AsyncRequest r = getNextRequest(); + + if (r.sample == 0) { + //there is no request in the queue + if (isFlushing()) { return VFW_E_WRONG_STATE; + } else { + //First we need to lock the mutex + if (m_requestWait.wait(&m_mutexWait, timeout) == false) { + return VFW_E_TIMEOUT; + } + if (isFlushing()) { + return VFW_E_WRONG_STATE; + } + + r = getNextRequest(); } } - AsyncRequest r = m_requestQueue.dequeue(); - //at this point we're sure to have a request to proceed if (r.sample == 0) { return E_FAIL; @@ -119,12 +127,14 @@ namespace Phonon *sample = r.sample; *user = r.user; - return syncReadAlignedUnlocked(r.sample); + + return SyncReadAligned(r.sample); } STDMETHODIMP QAsyncReader::BeginFlush() { - QMutexLocker locker(&m_mutex); + QMutexLocker mutexLocker(&m_mutexWait); + QWriteLocker locker(&m_lock); m_flushing = true; m_requestWait.wakeOne(); return S_OK; @@ -132,28 +142,13 @@ namespace Phonon STDMETHODIMP QAsyncReader::EndFlush() { - QMutexLocker locker(&m_mutex); + QWriteLocker locker(&m_lock); m_flushing = false; return S_OK; } STDMETHODIMP QAsyncReader::SyncReadAligned(IMediaSample *sample) { - QMutexLocker locker(&m_mutex); - return syncReadAlignedUnlocked(sample); - } - - STDMETHODIMP QAsyncReader::SyncRead(LONGLONG pos, LONG length, BYTE *buffer) - { - QMutexLocker locker(&m_mutex); - return read(pos, length, buffer, 0); - } - - - STDMETHODIMP QAsyncReader::syncReadAlignedUnlocked(IMediaSample *sample) - { - Q_ASSERT(!m_mutex.tryLock()); - if (!sample) { return E_POINTER; } @@ -180,6 +175,23 @@ namespace Phonon return sample->SetActualDataLength(actual); } + STDMETHODIMP QAsyncReader::SyncRead(LONGLONG pos, LONG length, BYTE *buffer) + { + return read(pos, length, buffer, 0); + } + + + //addition + QAsyncReader::AsyncRequest QAsyncReader::getNextRequest() + { + QWriteLocker locker(&m_lock); + AsyncRequest ret; + if (!m_requestQueue.isEmpty()) { + ret = m_requestQueue.dequeue(); + } + + return ret; + } } } diff --git a/src/3rdparty/phonon/ds9/qasyncreader.h b/src/3rdparty/phonon/ds9/qasyncreader.h index 95872f9..cb789ee 100644 --- a/src/3rdparty/phonon/ds9/qasyncreader.h +++ b/src/3rdparty/phonon/ds9/qasyncreader.h @@ -48,12 +48,11 @@ namespace Phonon STDMETHODIMP WaitForNext(DWORD,IMediaSample **,DWORD_PTR *); STDMETHODIMP SyncReadAligned(IMediaSample *); STDMETHODIMP SyncRead(LONGLONG,LONG,BYTE *); - STDMETHODIMP Length(LONGLONG *,LONGLONG *) = 0; + virtual STDMETHODIMP Length(LONGLONG *,LONGLONG *) = 0; STDMETHODIMP BeginFlush(); STDMETHODIMP EndFlush(); protected: - STDMETHODIMP syncReadAlignedUnlocked(IMediaSample *); virtual HRESULT read(LONGLONG pos, LONG length, BYTE *buffer, LONG *actual) = 0; private: @@ -63,6 +62,9 @@ namespace Phonon IMediaSample *sample; DWORD_PTR user; }; + AsyncRequest getNextRequest(); + + QMutex m_mutexWait; QQueue m_requestQueue; QWaitCondition m_requestWait; diff --git a/src/3rdparty/phonon/ds9/qaudiocdreader.cpp b/src/3rdparty/phonon/ds9/qaudiocdreader.cpp index 6d0f335..b9f9fd6 100644 --- a/src/3rdparty/phonon/ds9/qaudiocdreader.cpp +++ b/src/3rdparty/phonon/ds9/qaudiocdreader.cpp @@ -103,8 +103,8 @@ namespace Phonon private: HANDLE m_cddrive; - CDROM_TOC m_toc; - WaveStructure m_waveHeader; + CDROM_TOC *m_toc; + WaveStructure *m_waveHeader; qint64 m_trackAddress; }; @@ -112,8 +112,19 @@ namespace Phonon #define SECTOR_SIZE 2352 #define NB_SECTORS_READ 20 - static const AM_MEDIA_TYPE audioCDMediaType = { MEDIATYPE_Stream, MEDIASUBTYPE_WAVE, TRUE, FALSE, 1, GUID_NULL, 0, 0, 0}; - + static AM_MEDIA_TYPE getAudioCDMediaType() + { + AM_MEDIA_TYPE mt; + qMemSet(&mt, 0, sizeof(AM_MEDIA_TYPE)); + mt.majortype = MEDIATYPE_Stream; + mt.subtype = MEDIASUBTYPE_WAVE; + mt.bFixedSizeSamples = TRUE; + mt.bTemporalCompression = FALSE; + mt.lSampleSize = 1; + mt.formattype = GUID_NULL; + return mt; + } + int addressToSectors(UCHAR address[4]) { return ((address[0] * 60 + address[1]) * 60 + address[2]) * 75 + address[3] - 150; @@ -130,8 +141,11 @@ namespace Phonon } - QAudioCDReader::QAudioCDReader(QBaseFilter *parent, QChar drive) : QAsyncReader(parent, QVector() << audioCDMediaType) + QAudioCDReader::QAudioCDReader(QBaseFilter *parent, QChar drive) : QAsyncReader(parent, QVector() << getAudioCDMediaType()) { + m_toc = new CDROM_TOC; + m_waveHeader = new WaveStructure; + //now open the cd-drive QString path; if (drive.isNull()) { @@ -140,30 +154,36 @@ namespace Phonon path = QString::fromLatin1("\\\\.\\%1:").arg(drive); } - m_cddrive = ::CreateFile((const wchar_t *)path.utf16(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); + m_cddrive = QT_WA_INLINE ( + ::CreateFile( (TCHAR*)path.utf16(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL ), + ::CreateFileA( path.toLocal8Bit().constData(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL ) + ); - qMemSet(&m_toc, 0, sizeof(CDROM_TOC)); + qMemSet(m_toc, 0, sizeof(CDROM_TOC)); //read the TOC DWORD bytesRead = 0; - bool tocRead = ::DeviceIoControl(m_cddrive, IOCTL_CDROM_READ_TOC, 0, 0, &m_toc, sizeof(CDROM_TOC), &bytesRead, 0); + bool tocRead = ::DeviceIoControl(m_cddrive, IOCTL_CDROM_READ_TOC, 0, 0, m_toc, sizeof(CDROM_TOC), &bytesRead, 0); if (!tocRead) { qWarning("unable to load the TOC from the CD"); return; } - m_trackAddress = addressToSectors(m_toc.TrackData[0].Address); - const qint32 nbSectorsToRead = (addressToSectors(m_toc.TrackData[m_toc.LastTrack + 1 - m_toc.FirstTrack].Address) + m_trackAddress = addressToSectors(m_toc->TrackData[0].Address); + const qint32 nbSectorsToRead = (addressToSectors(m_toc->TrackData[m_toc->LastTrack + 1 - m_toc->FirstTrack].Address) - m_trackAddress); const qint32 dataLength = nbSectorsToRead * SECTOR_SIZE; - m_waveHeader.chunksize = 4 + (8 + m_waveHeader.chunksize2) + (8 + dataLength); - m_waveHeader.dataLength = dataLength; + m_waveHeader->chunksize = 4 + (8 + m_waveHeader->chunksize2) + (8 + dataLength); + m_waveHeader->dataLength = dataLength; } QAudioCDReader::~QAudioCDReader() { ::CloseHandle(m_cddrive); + delete m_toc; + delete m_waveHeader; + } STDMETHODIMP_(ULONG) QAudioCDReader::AddRef() @@ -179,7 +199,7 @@ namespace Phonon STDMETHODIMP QAudioCDReader::Length(LONGLONG *total,LONGLONG *available) { - const LONGLONG length = sizeof(WaveStructure) + m_waveHeader.dataLength; + const LONGLONG length = sizeof(WaveStructure) + m_waveHeader->dataLength; if (total) { *total = length; } @@ -218,11 +238,11 @@ namespace Phonon if (pos < sizeof(WaveStructure)) { //we first copy the content of the structure nbRead = qMin(LONG(sizeof(WaveStructure) - pos), length); - qMemCopy(buffer, reinterpret_cast(&m_waveHeader) + pos, nbRead); + qMemCopy(buffer, reinterpret_cast(m_waveHeader) + pos, nbRead); } const LONGLONG posInTrack = pos - sizeof(WaveStructure) + nbRead; - const int bytesLeft = qMin(m_waveHeader.dataLength - posInTrack, LONGLONG(length - nbRead)); + const int bytesLeft = qMin(m_waveHeader->dataLength - posInTrack, LONGLONG(length - nbRead)); if (bytesLeft > 0) { @@ -277,8 +297,8 @@ namespace Phonon { QList ret; ret << 0; - for(int i = m_toc.FirstTrack; i <= m_toc.LastTrack ; ++i) { - const uchar *address = m_toc.TrackData[i].Address; + for(int i = m_toc->FirstTrack; i <= m_toc->LastTrack ; ++i) { + const uchar *address = m_toc->TrackData[i].Address; ret << ((address[0] * 60 + address[1]) * 60 + address[2]) * 1000 + address[3]*1000/75 - 2000; } diff --git a/src/3rdparty/phonon/ds9/qaudiocdreader.h b/src/3rdparty/phonon/ds9/qaudiocdreader.h index eff845d..9049b66 100644 --- a/src/3rdparty/phonon/ds9/qaudiocdreader.h +++ b/src/3rdparty/phonon/ds9/qaudiocdreader.h @@ -31,7 +31,7 @@ namespace Phonon { struct CDROM_TOC; struct WaveStructure; - EXTERN_C const IID IID_ITitleInterface; + extern const IID IID_ITitleInterface; //interface for the Titles struct ITitleInterface : public IUnknown diff --git a/src/3rdparty/phonon/ds9/qbasefilter.cpp b/src/3rdparty/phonon/ds9/qbasefilter.cpp index 78b8b8f..95cab92 100644 --- a/src/3rdparty/phonon/ds9/qbasefilter.cpp +++ b/src/3rdparty/phonon/ds9/qbasefilter.cpp @@ -92,8 +92,8 @@ namespace Phonon return E_POINTER; } - uint nbfetched = 0; - while (nbfetched < count && m_index < m_pins.count()) { + int nbfetched = 0; + while (nbfetched < int(count) && m_index < m_pins.count()) { IPin *current = m_pins[m_index]; current->AddRef(); ret[nbfetched] = current; @@ -166,19 +166,19 @@ namespace Phonon const QList QBaseFilter::pins() const { - QMutexLocker locker(&m_mutex); + QReadLocker locker(&m_lock); return m_pins; } void QBaseFilter::addPin(QPin *pin) { - QMutexLocker locker(&m_mutex); + QWriteLocker locker(&m_lock); m_pins.append(pin); } void QBaseFilter::removePin(QPin *pin) { - QMutexLocker locker(&m_mutex); + QWriteLocker locker(&m_lock); m_pins.removeAll(pin); } @@ -211,8 +211,7 @@ namespace Phonon } else if (iid == IID_IMediaPosition || iid == IID_IMediaSeeking) { if (inputPins().isEmpty()) { - *out = getUpStreamInterface(iid); - if (*out) { + if (*out = getUpStreamInterface(iid)) { return S_OK; //we return here to avoid adding a reference } else { hr = E_NOINTERFACE; @@ -251,35 +250,35 @@ namespace Phonon STDMETHODIMP QBaseFilter::GetClassID(CLSID *clsid) { - QMutexLocker locker(&m_mutex); + QReadLocker locker(&m_lock); *clsid = m_clsid; return S_OK; } STDMETHODIMP QBaseFilter::Stop() { - QMutexLocker locker(&m_mutex); + QWriteLocker locker(&m_lock); m_state = State_Stopped; return S_OK; } STDMETHODIMP QBaseFilter::Pause() { - QMutexLocker locker(&m_mutex); + QWriteLocker locker(&m_lock); m_state = State_Paused; return S_OK; } STDMETHODIMP QBaseFilter::Run(REFERENCE_TIME) { - QMutexLocker locker(&m_mutex); + QWriteLocker locker(&m_lock); m_state = State_Running; return S_OK; } STDMETHODIMP QBaseFilter::GetState(DWORD, FILTER_STATE *state) { - QMutexLocker locker(&m_mutex); + QReadLocker locker(&m_lock); if (!state) { return E_POINTER; } @@ -290,7 +289,7 @@ namespace Phonon STDMETHODIMP QBaseFilter::SetSyncSource(IReferenceClock *clock) { - QMutexLocker locker(&m_mutex); + QWriteLocker locker(&m_lock); if (clock) { clock->AddRef(); } @@ -303,7 +302,7 @@ namespace Phonon STDMETHODIMP QBaseFilter::GetSyncSource(IReferenceClock **clock) { - QMutexLocker locker(&m_mutex); + QReadLocker locker(&m_lock); if (!clock) { return E_POINTER; } @@ -342,7 +341,7 @@ namespace Phonon STDMETHODIMP QBaseFilter::QueryFilterInfo(FILTER_INFO *info ) { - QMutexLocker locker(&m_mutex); + QReadLocker locker(&m_lock); if (!info) { return E_POINTER; } @@ -356,9 +355,9 @@ namespace Phonon STDMETHODIMP QBaseFilter::JoinFilterGraph(IFilterGraph *graph, LPCWSTR name) { - QMutexLocker locker(&m_mutex); + QWriteLocker locker(&m_lock); m_graph = graph; - m_name = QString::fromWCharArray(name); + m_name = QString::fromUtf16((const unsigned short*)name); return S_OK; } diff --git a/src/3rdparty/phonon/ds9/qbasefilter.h b/src/3rdparty/phonon/ds9/qbasefilter.h index a72d6fe..85f1431 100644 --- a/src/3rdparty/phonon/ds9/qbasefilter.h +++ b/src/3rdparty/phonon/ds9/qbasefilter.h @@ -22,7 +22,7 @@ along with this library. If not, see . #include #include -#include +#include #include @@ -127,7 +127,7 @@ namespace Phonon IFilterGraph *m_graph; FILTER_STATE m_state; QList m_pins; - mutable QMutex m_mutex; + mutable QReadWriteLock m_lock; }; } } diff --git a/src/3rdparty/phonon/ds9/qevr9.h b/src/3rdparty/phonon/ds9/qevr9.h deleted file mode 100644 index 8599fce..0000000 --- a/src/3rdparty/phonon/ds9/qevr9.h +++ /dev/null @@ -1,143 +0,0 @@ -/* This file is part of the KDE project. - -Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). - -This library is free software: you can redistribute it and/or modify -it under the terms of the GNU Lesser General Public License as published by -the Free Software Foundation, either version 2.1 or 3 of the License. - -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public License -along with this library. If not, see . -*/ - -#include - -#define DXVA2_ProcAmp_Brightness 1 -#define DXVA2_ProcAmp_Contrast 2 -#define DXVA2_ProcAmp_Hue 4 -#define DXVA2_ProcAmp_Saturation 8 - -typedef enum { - MFVideoARMode_None = 0x00000000, - MFVideoARMode_PreservePicture = 0x00000001, - MFVideoARMode_PreservePixel = 0x00000002, - MFVideoARMode_NonLinearStretch = 0x00000004, - MFVideoARMode_Mask = 0x00000007 -} MFVideoAspectRatioMode; - -typedef struct { - float left; - float top; - float right; - float bottom; -} MFVideoNormalizedRect; - -typedef struct { - UINT DeviceCaps; - D3DPOOL InputPool; - UINT NumForwardRefSamples; - UINT NumBackwardRefSamples; - UINT Reserved; - UINT DeinterlaceTechnology; - UINT ProcAmpControlCaps; - UINT VideoProcessorOperations; - UINT NoiseFilterTechnology; - UINT DetailFilterTechnology; -} DXVA2_VideoProcessorCaps; - -typedef struct { - union { - struct { - USHORT Fraction; - SHORT Value; - }; - LONG ll; - }; -} DXVA2_Fixed32; - -typedef struct { - DXVA2_Fixed32 MinValue; - DXVA2_Fixed32 MaxValue; - DXVA2_Fixed32 DefaultValue; - DXVA2_Fixed32 StepSize; -} DXVA2_ValueRange; - -typedef struct { - DXVA2_Fixed32 Brightness; - DXVA2_Fixed32 Contrast; - DXVA2_Fixed32 Hue; - DXVA2_Fixed32 Saturation; -} DXVA2_ProcAmpValues; - -DXVA2_Fixed32 DXVA2FloatToFixed(const float _float_) -{ - DXVA2_Fixed32 _fixed_; - _fixed_.Fraction = LOWORD(_float_ * 0x10000); - _fixed_.Value = HIWORD(_float_ * 0x10000); - return _fixed_; -} - -float DXVA2FixedToFloat(const DXVA2_Fixed32 _fixed_) -{ - return (FLOAT)_fixed_.Value + (FLOAT)_fixed_.Fraction / 0x10000; -} - -#undef INTERFACE -#define INTERFACE IMFVideoDisplayControl -DECLARE_INTERFACE_(IMFVideoDisplayControl, IUnknown) -{ - STDMETHOD(GetNativeVideoSize)(THIS_ SIZE* pszVideo, SIZE* pszARVideo) PURE; - STDMETHOD(GetIdealVideoSize)(THIS_ SIZE* pszMin, SIZE* pszMax) PURE; - STDMETHOD(SetVideoPosition)(THIS_ const MFVideoNormalizedRect* pnrcSource, const LPRECT prcDest) PURE; - STDMETHOD(GetVideoPosition)(THIS_ MFVideoNormalizedRect* pnrcSource, LPRECT prcDest) PURE; - STDMETHOD(SetAspectRatioMode)(THIS_ DWORD dwAspectRatioMode) PURE; - STDMETHOD(GetAspectRatioMode)(THIS_ DWORD* pdwAspectRatioMode) PURE; - STDMETHOD(SetVideoWindow)(THIS_ HWND hwndVideo) PURE; - STDMETHOD(GetVideoWindow)(THIS_ HWND* phwndVideo) PURE; - STDMETHOD(RepaintVideo)(THIS_) PURE; - STDMETHOD(GetCurrentImage)(THIS_ BITMAPINFOHEADER* pBih, BYTE** pDib, DWORD* pcbDib, LONGLONG* pTimeStamp) PURE; - STDMETHOD(SetBorderColor)(THIS_ COLORREF Clr) PURE; - STDMETHOD(GetBorderColor)(THIS_ COLORREF* pClr) PURE; - STDMETHOD(SetRenderingPrefs)(THIS_ DWORD dwRenderFlags) PURE; - STDMETHOD(GetRenderingPrefs)(THIS_ DWORD* pdwRenderFlags) PURE; - STDMETHOD(SetFullScreen)(THIS_ BOOL fFullscreen) PURE; - STDMETHOD(GetFullScreen)(THIS_ BOOL* pfFullscreen) PURE; -}; -#undef INTERFACE -#define INTERFACE IMFVideoMixerControl -DECLARE_INTERFACE_(IMFVideoMixerControl, IUnknown) -{ - STDMETHOD(SetStreamZOrder)(THIS_ DWORD dwStreamID, DWORD dwZ) PURE; - STDMETHOD(GetStreamZOrder)(THIS_ DWORD dwStreamID, DWORD* pdwZ) PURE; - STDMETHOD(SetStreamOutputRect)(THIS_ DWORD dwStreamID, const MFVideoNormalizedRect* pnrcOutput) PURE; - STDMETHOD(GetStreamOutputRect)(THIS_ DWORD dwStreamID, MFVideoNormalizedRect* pnrcOutput) PURE; -}; -#undef INTERFACE -#define INTERFACE IMFVideoProcessor -DECLARE_INTERFACE_(IMFVideoProcessor, IUnknown) -{ - STDMETHOD(GetAvailableVideoProcessorModes)(THIS_ UINT* lpdwNumProcessingModes, GUID** ppVideoProcessingModes) PURE; - STDMETHOD(GetVideoProcessorCaps)(THIS_ LPGUID lpVideoProcessorMode, DXVA2_VideoProcessorCaps* lpVideoProcessorCaps) PURE; - STDMETHOD(GetVideoProcessorMode)(THIS_ LPGUID lpMode) PURE; - STDMETHOD(SetVideoProcessorMode)(THIS_ LPGUID lpMode) PURE; - STDMETHOD(GetProcAmpRange)(THIS_ DWORD dwProperty, DXVA2_ValueRange* pPropRange) PURE; - STDMETHOD(GetProcAmpValues)(THIS_ DWORD dwFlags, DXVA2_ProcAmpValues* Values) PURE; - STDMETHOD(SetProcAmpValues)(THIS_ DWORD dwFlags, DXVA2_ProcAmpValues* pValues) PURE; - STDMETHOD(GetFilteringRange)(THIS_ DWORD dwProperty, DXVA2_ValueRange* pPropRange) PURE; - STDMETHOD(GetFilteringValue)(THIS_ DWORD dwProperty, DXVA2_Fixed32* pValue) PURE; - STDMETHOD(SetFilteringValue)(THIS_ DWORD dwProperty, DXVA2_Fixed32* pValue) PURE; - STDMETHOD(GetBackgroundColor)(THIS_ COLORREF* lpClrBkg) PURE; - STDMETHOD(SetBackgroundColor)(THIS_ COLORREF ClrBkg) PURE; -}; -#undef INTERFACE -#define INTERFACE IMFGetService -DECLARE_INTERFACE_(IMFGetService, IUnknown) -{ - STDMETHOD(GetService)(THIS_ REFGUID guidService, REFIID riid, LPVOID* ppvObject) PURE; -}; -#undef INTERFACE diff --git a/src/3rdparty/phonon/ds9/qmeminputpin.cpp b/src/3rdparty/phonon/ds9/qmeminputpin.cpp index a21fbe7..dca99db 100644 --- a/src/3rdparty/phonon/ds9/qmeminputpin.cpp +++ b/src/3rdparty/phonon/ds9/qmeminputpin.cpp @@ -28,8 +28,8 @@ namespace Phonon namespace DS9 { - QMemInputPin::QMemInputPin(QBaseFilter *parent, const QVector &mt, bool transform, QPin *output) : - QPin(parent, PINDIR_INPUT, mt), m_shouldDuplicateSamples(true), m_transform(transform), m_output(output) + QMemInputPin::QMemInputPin(QBaseFilter *parent, const QVector &mt, bool transform) : + QPin(parent, PINDIR_INPUT, mt), m_shouldDuplicateSamples(true), m_transform(transform) { } @@ -66,9 +66,11 @@ namespace Phonon { //this allows to serialize with Receive calls QMutexLocker locker(&m_mutexReceive); - IPin *conn = m_output ? m_output->connected() : 0; - if (conn) { - conn->EndOfStream(); + for(int i = 0; i < m_outputs.count(); ++i) { + IPin *conn = m_outputs.at(i)->connected(); + if (conn) { + conn->EndOfStream(); + } } return S_OK; } @@ -76,11 +78,13 @@ namespace Phonon STDMETHODIMP QMemInputPin::BeginFlush() { //pass downstream - IPin *conn = m_output ? m_output->connected() : 0; - if (conn) { - conn->BeginFlush(); + for(int i = 0; i < m_outputs.count(); ++i) { + IPin *conn = m_outputs.at(i)->connected(); + if (conn) { + conn->BeginFlush(); + } } - QMutexLocker locker(&m_mutex); + QWriteLocker locker(&m_lock); m_flushing = true; return S_OK; } @@ -88,19 +92,22 @@ namespace Phonon STDMETHODIMP QMemInputPin::EndFlush() { //pass downstream - IPin *conn = m_output ? m_output->connected() : 0; - if (conn) { - conn->EndFlush(); + for(int i = 0; i < m_outputs.count(); ++i) { + IPin *conn = m_outputs.at(i)->connected(); + if (conn) { + conn->EndFlush(); + } } - QMutexLocker locker(&m_mutex); + QWriteLocker locker(&m_lock); m_flushing = false; return S_OK; } STDMETHODIMP QMemInputPin::NewSegment(REFERENCE_TIME start, REFERENCE_TIME stop, double rate) { - if (m_output) - m_output->NewSegment(start, stop, rate); + for(int i = 0; i < m_outputs.count(); ++i) { + m_outputs.at(i)->NewSegment(start, stop, rate); + } return S_OK; } @@ -112,9 +119,14 @@ namespace Phonon if (hr == S_OK && mt->majortype != MEDIATYPE_NULL && mt->subtype != MEDIASUBTYPE_NULL && - mt->formattype != GUID_NULL && m_output) { - //we tell the output pin that it should connect with this type - hr = m_output->setAcceptedMediaType(connectedType()); + mt->formattype != GUID_NULL) { + //we tell the output pins that they should connect with this type + for(int i = 0; i < m_outputs.count(); ++i) { + hr = m_outputs.at(i)->setAcceptedMediaType(connectedType()); + if (FAILED(hr)) { + break; + } + } } return hr; } @@ -125,8 +137,7 @@ namespace Phonon return E_POINTER; } - *alloc = memoryAllocator(true); - if (*alloc) { + if (*alloc = memoryAllocator(true)) { return S_OK; } @@ -140,15 +151,18 @@ namespace Phonon } { - QMutexLocker locker(&m_mutex); + QWriteLocker locker(&m_lock); m_shouldDuplicateSamples = m_transform && readonly; } setMemoryAllocator(alloc); - if (m_output) { - ComPointer input(m_output, IID_IMemInputPin); - input->NotifyAllocator(alloc, m_shouldDuplicateSamples); + for(int i = 0; i < m_outputs.count(); ++i) { + IPin *pin = m_outputs.at(i)->connected(); + if (pin) { + ComPointer input(pin, IID_IMemInputPin); + input->NotifyAllocator(alloc, m_shouldDuplicateSamples); + } } return S_OK; @@ -187,18 +201,22 @@ namespace Phonon } } - if (m_output) { + for (int i = 0; i < m_outputs.count(); ++i) { + QPin *current = m_outputs.at(i); IMediaSample *outSample = m_shouldDuplicateSamples ? - duplicateSampleForOutput(sample, m_output->memoryAllocator()) + duplicateSampleForOutput(sample, current->memoryAllocator()) : sample; if (m_shouldDuplicateSamples) { m_parent->processSample(outSample); } - ComPointer input(m_output->connected(), IID_IMemInputPin); - if (input) { - input->Receive(outSample); + IPin *pin = current->connected(); + if (pin) { + ComPointer input(pin, IID_IMemInputPin); + if (input) { + input->Receive(outSample); + } } if (m_shouldDuplicateSamples) { @@ -229,16 +247,39 @@ namespace Phonon STDMETHODIMP QMemInputPin::ReceiveCanBlock() { - //we test the output to see if it can block - if (m_output) { - ComPointer meminput(m_output->connected(), IID_IMemInputPin); - if (meminput && meminput->ReceiveCanBlock() != S_FALSE) { - return S_OK; + //we test the output to see if they can block + for(int i = 0; i < m_outputs.count(); ++i) { + IPin *input = m_outputs.at(i)->connected(); + if (input) { + ComPointer meminput(input, IID_IMemInputPin); + if (meminput && meminput->ReceiveCanBlock() != S_FALSE) { + return S_OK; + } } } return S_FALSE; } + //addition + //this should be used by the filter to tell its input pins to which output they should route the samples + + void QMemInputPin::addOutput(QPin *output) + { + QWriteLocker locker(&m_lock); + m_outputs += output; + } + + void QMemInputPin::removeOutput(QPin *output) + { + QWriteLocker locker(&m_lock); + m_outputs.removeOne(output); + } + + QList QMemInputPin::outputs() const + { + QReadLocker locker(&m_lock); + return m_outputs; + } ALLOCATOR_PROPERTIES QMemInputPin::getDefaultAllocatorProperties() const { @@ -253,7 +294,7 @@ namespace Phonon LONG length = sample->GetActualDataLength(); HRESULT hr = alloc->Commit(); - if (hr == HRESULT(VFW_E_SIZENOTSET)) { + if (hr == VFW_E_SIZENOTSET) { ALLOCATOR_PROPERTIES prop = getDefaultAllocatorProperties(); prop.cbBuffer = qMax(prop.cbBuffer, length); ALLOCATOR_PROPERTIES actual; @@ -283,7 +324,7 @@ namespace Phonon { LONGLONG start, end; hr = sample->GetMediaTime(&start, &end); - if (hr != HRESULT(VFW_E_MEDIA_TIME_NOT_SET)) { + if (hr != VFW_E_MEDIA_TIME_NOT_SET) { hr = out->SetMediaTime(&start, &end); Q_ASSERT(SUCCEEDED(hr)); } diff --git a/src/3rdparty/phonon/ds9/qmeminputpin.h b/src/3rdparty/phonon/ds9/qmeminputpin.h index d74c451..c449721 100644 --- a/src/3rdparty/phonon/ds9/qmeminputpin.h +++ b/src/3rdparty/phonon/ds9/qmeminputpin.h @@ -37,7 +37,7 @@ namespace Phonon class QMemInputPin : public QPin, public IMemInputPin { public: - QMemInputPin(QBaseFilter *, const QVector &, bool transform, QPin *output); + QMemInputPin(QBaseFilter *, const QVector &, bool transform); ~QMemInputPin(); //reimplementation from IUnknown @@ -60,13 +60,18 @@ namespace Phonon STDMETHODIMP ReceiveMultiple(IMediaSample **,long,long *); STDMETHODIMP ReceiveCanBlock(); + //addition + void addOutput(QPin *output); + void removeOutput(QPin *output); + QList outputs() const; + private: IMediaSample *duplicateSampleForOutput(IMediaSample *, IMemAllocator *); ALLOCATOR_PROPERTIES getDefaultAllocatorProperties() const; bool m_shouldDuplicateSamples; const bool m_transform; //defines if the pin is transforming the samples - QPin* const m_output; + QList m_outputs; QMutex m_mutexReceive; }; } diff --git a/src/3rdparty/phonon/ds9/qpin.cpp b/src/3rdparty/phonon/ds9/qpin.cpp index b4afd10..37fe48d 100644 --- a/src/3rdparty/phonon/ds9/qpin.cpp +++ b/src/3rdparty/phonon/ds9/qpin.cpp @@ -28,7 +28,20 @@ namespace Phonon namespace DS9 { - static const AM_MEDIA_TYPE defaultMediaType = { MEDIATYPE_NULL, MEDIASUBTYPE_NULL, TRUE, FALSE, 1, GUID_NULL, 0, 0, 0}; + static const AM_MEDIA_TYPE defaultMediaType() + { + AM_MEDIA_TYPE ret; + ret.majortype = MEDIATYPE_NULL; + ret.subtype = MEDIASUBTYPE_NULL; + ret.bFixedSizeSamples = TRUE; + ret.bTemporalCompression = FALSE; + ret.lSampleSize = 1; + ret.formattype = GUID_NULL; + ret.pUnk = 0; + ret.cbFormat = 0; + ret.pbFormat = 0; + return ret; + } class QEnumMediaTypes : public IEnumMediaTypes { @@ -91,8 +104,8 @@ namespace Phonon return E_INVALIDARG; } - uint nbFetched = 0; - while (nbFetched < count && m_index < m_pin->mediaTypes().count()) { + int nbFetched = 0; + while (nbFetched < int(count) && m_index < m_pin->mediaTypes().count()) { //the caller will deallocate the memory *out = static_cast(::CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE))); const AM_MEDIA_TYPE original = m_pin->mediaTypes().at(m_index); @@ -145,9 +158,9 @@ namespace Phonon QPin::QPin(QBaseFilter *parent, PIN_DIRECTION dir, const QVector &mt) : - m_parent(parent), m_flushing(false), m_refCount(1), m_connected(0), - m_direction(dir), m_mediaTypes(mt), m_connectedType(defaultMediaType), - m_memAlloc(0) + m_memAlloc(0), m_parent(parent), m_refCount(1), m_connected(0), + m_direction(dir), m_mediaTypes(mt), m_connectedType(defaultMediaType()), + m_flushing(false) { Q_ASSERT(m_parent); m_parent->addPin(this); @@ -260,7 +273,7 @@ namespace Phonon if (FAILED(hr)) { setConnected(0); - setConnectedType(defaultMediaType); + setConnectedType(defaultMediaType()); } else { ComPointer input(pin, IID_IMemInputPin); if (input) { @@ -302,8 +315,10 @@ namespace Phonon } setConnected(0); - setConnectedType(defaultMediaType); - setMemoryAllocator(0); + setConnectedType(defaultMediaType()); + if (m_direction == PINDIR_INPUT) { + setMemoryAllocator(0); + } return S_OK; } @@ -323,7 +338,7 @@ namespace Phonon STDMETHODIMP QPin::ConnectionMediaType(AM_MEDIA_TYPE *type) { - QMutexLocker locker(&m_mutex); + QReadLocker locker(&m_lock); if (!type) { return E_POINTER; } @@ -338,6 +353,7 @@ namespace Phonon STDMETHODIMP QPin::QueryPinInfo(PIN_INFO *info) { + QReadLocker locker(&m_lock); if (!info) { return E_POINTER; } @@ -345,12 +361,14 @@ namespace Phonon info->dir = m_direction; info->pFilter = m_parent; m_parent->AddRef(); - info->achName[0] = 0; + qMemCopy(info->achName, m_name.utf16(), qMin(MAX_FILTER_NAME, m_name.length()+1) *2); + return S_OK; } STDMETHODIMP QPin::QueryDirection(PIN_DIRECTION *dir) { + QReadLocker locker(&m_lock); if (!dir) { return E_POINTER; } @@ -361,18 +379,20 @@ namespace Phonon STDMETHODIMP QPin::QueryId(LPWSTR *id) { + QReadLocker locker(&m_lock); if (!id) { return E_POINTER; } - *id = static_cast(::CoTaskMemAlloc(2)); - *id[0] = 0; + int nbBytes = (m_name.length()+1)*2; + *id = static_cast(::CoTaskMemAlloc(nbBytes)); + qMemCopy(*id, m_name.utf16(), nbBytes); return S_OK; } STDMETHODIMP QPin::QueryAccept(const AM_MEDIA_TYPE *type) { - QMutexLocker locker(&m_mutex); + QReadLocker locker(&m_lock); if (!type) { return E_POINTER; } @@ -419,7 +439,7 @@ namespace Phonon STDMETHODIMP QPin::NewSegment(REFERENCE_TIME start, REFERENCE_TIME stop, double rate) { - QMutexLocker locker(&m_mutex); + QReadLocker locker(&m_lock); if (m_direction == PINDIR_OUTPUT && m_connected) { //we deliver this downstream m_connected->NewSegment(start, stop, rate); @@ -436,8 +456,8 @@ namespace Phonon HRESULT QPin::checkOutputMediaTypesConnection(IPin *pin) { - ComPointer emt; - HRESULT hr = pin->EnumMediaTypes(emt.pparam()); + IEnumMediaTypes *emt = 0; + HRESULT hr = pin->EnumMediaTypes(&emt); if (hr != S_OK) { return hr; } @@ -450,7 +470,7 @@ namespace Phonon freeMediaType(type); return S_OK; } else { - setConnectedType(defaultMediaType); + setConnectedType(defaultMediaType()); freeMediaType(type); } } @@ -500,7 +520,7 @@ namespace Phonon void QPin::setConnectedType(const AM_MEDIA_TYPE &type) { - QMutexLocker locker(&m_mutex); + QWriteLocker locker(&m_lock); //1st we free memory freeMediaType(m_connectedType); @@ -510,13 +530,13 @@ namespace Phonon const AM_MEDIA_TYPE &QPin::connectedType() const { - QMutexLocker locker(&m_mutex); + QReadLocker locker(&m_lock); return m_connectedType; } void QPin::setConnected(IPin *pin) { - QMutexLocker locker(&m_mutex); + QWriteLocker locker(&m_lock); if (pin) { pin->AddRef(); } @@ -528,7 +548,7 @@ namespace Phonon IPin *QPin::connected(bool addref) const { - QMutexLocker locker(&m_mutex); + QReadLocker locker(&m_lock); if (addref && m_connected) { m_connected->AddRef(); } @@ -537,12 +557,13 @@ namespace Phonon bool QPin::isFlushing() const { - QMutexLocker locker(&m_mutex); + QReadLocker locker(&m_lock); return m_flushing; } FILTER_STATE QPin::filterState() const { + QReadLocker locker(&m_lock); FILTER_STATE fstate = State_Stopped; m_parent->GetState(0, &fstate); return fstate; @@ -550,7 +571,7 @@ namespace Phonon QVector QPin::mediaTypes() const { - QMutexLocker locker(&m_mutex); + QReadLocker locker(&m_lock); return m_mediaTypes; } @@ -586,7 +607,7 @@ namespace Phonon void QPin::setMemoryAllocator(IMemAllocator *alloc) { - QMutexLocker locker(&m_mutex); + QWriteLocker locker(&m_lock); if (alloc) { alloc->AddRef(); } @@ -598,7 +619,7 @@ namespace Phonon IMemAllocator *QPin::memoryAllocator(bool addref) const { - QMutexLocker locker(&m_mutex); + QReadLocker locker(&m_lock); if (addref && m_memAlloc) { m_memAlloc->AddRef(); } diff --git a/src/3rdparty/phonon/ds9/qpin.h b/src/3rdparty/phonon/ds9/qpin.h index 280ad61..a3287c4 100644 --- a/src/3rdparty/phonon/ds9/qpin.h +++ b/src/3rdparty/phonon/ds9/qpin.h @@ -22,7 +22,7 @@ along with this library. If not, see . #include #include -#include +#include #include @@ -85,8 +85,8 @@ namespace Phonon protected: //this can be used by sub-classes - mutable QMutex m_mutex; - QBaseFilter * const m_parent; + mutable QReadWriteLock m_lock; + QBaseFilter *m_parent; bool m_flushing; private: @@ -98,6 +98,7 @@ namespace Phonon const PIN_DIRECTION m_direction; QVector m_mediaTypes; //accepted media types AM_MEDIA_TYPE m_connectedType; + QString m_name; IMemAllocator *m_memAlloc; }; diff --git a/src/3rdparty/phonon/ds9/videorenderer_default.cpp b/src/3rdparty/phonon/ds9/videorenderer_default.cpp deleted file mode 100644 index 0045a49..0000000 --- a/src/3rdparty/phonon/ds9/videorenderer_default.cpp +++ /dev/null @@ -1,153 +0,0 @@ -/* This file is part of the KDE project. - -Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). - -This library is free software: you can redistribute it and/or modify -it under the terms of the GNU Lesser General Public License as published by -the Free Software Foundation, either version 2.1 or 3 of the License. - -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public License -along with this library. If not, see . -*/ - - -#include "videorenderer_default.h" - -#ifndef QT_NO_PHONON_VIDEO - -#include -#include - -#include - -QT_BEGIN_NAMESPACE - - -namespace Phonon -{ - namespace DS9 - { - VideoRendererDefault::~VideoRendererDefault() - { - } - - bool VideoRendererDefault::isNative() const - { - return true; - } - - - VideoRendererDefault::VideoRendererDefault(QWidget *target) : m_target(target) - { - m_target->setAttribute(Qt::WA_PaintOnScreen, true); - m_filter = Filter(CLSID_VideoRenderer, IID_IBaseFilter); - } - - QSize VideoRendererDefault::videoSize() const - { - LONG w = 0, - h = 0; - ComPointer basic(m_filter, IID_IBasicVideo); - if (basic) { - basic->GetVideoSize( &w, &h); - } - return QSize(w, h); - } - - void VideoRendererDefault::repaintCurrentFrame(QWidget * /*target*/, const QRect & /*rect*/) - { - //nothing to do here: the renderer paints everything - } - - void VideoRendererDefault::notifyResize(const QSize &size, Phonon::VideoWidget::AspectRatio aspectRatio, - Phonon::VideoWidget::ScaleMode scaleMode) - { - if (!isActive()) { - ComPointer basic(m_filter, IID_IBasicVideo); - if (basic) { - basic->SetDestinationPosition(0, 0, 0, 0); - } - return; - } - - ComPointer video(m_filter, IID_IVideoWindow); - - OAHWND owner; - HRESULT hr = video->get_Owner(&owner); - if (FAILED(hr)) { - return; - } - - const OAHWND newOwner = reinterpret_cast(m_target->winId()); - if (owner != newOwner) { - video->put_Owner(newOwner); - video->put_MessageDrain(newOwner); - video->put_WindowStyle(WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS); - } - - //make sure the widget takes the whole size of the parent - video->SetWindowPosition(0, 0, size.width(), size.height()); - - const QSize vsize = videoSize(); - internalNotifyResize(size, vsize, aspectRatio, scaleMode); - - ComPointer basic(m_filter, IID_IBasicVideo); - if (basic) { - basic->SetDestinationPosition(m_dstX, m_dstY, m_dstWidth, m_dstHeight); - } - } - - void VideoRendererDefault::applyMixerSettings(qreal /*brightness*/, qreal /*contrast*/, qreal /*m_hue*/, qreal /*saturation*/) - { - //this can't be supported for the default renderer - } - - QImage VideoRendererDefault::snapshot() const - { - ComPointer basic(m_filter, IID_IBasicVideo); - if (basic) { - LONG bufferSize = 0; - //1st we get the buffer size - basic->GetCurrentImage(&bufferSize, 0); - - QByteArray buffer; - buffer.resize(bufferSize); - HRESULT hr = basic->GetCurrentImage(&bufferSize, reinterpret_cast(buffer.data())); - - if (SUCCEEDED(hr)) { - - const BITMAPINFOHEADER *bmi = reinterpret_cast(buffer.constData()); - - const int w = qAbs(bmi->biWidth), - h = qAbs(bmi->biHeight); - - // Create image and copy data into image. - QImage ret(w, h, QImage::Format_RGB32); - - if (!ret.isNull()) { - const char *data = buffer.constData() + bmi->biSize; - const int bytes_per_line = w * sizeof(QRgb); - for (int y = h - 1; y >= 0; --y) { - qMemCopy(ret.scanLine(y), //destination - data, //source - bytes_per_line); - data += bytes_per_line; - } - } - return ret; - } - } - return QImage(); - } - - } -} - -QT_END_NAMESPACE - -#endif //QT_NO_PHONON_VIDEO diff --git a/src/3rdparty/phonon/ds9/videorenderer_default.h b/src/3rdparty/phonon/ds9/videorenderer_default.h deleted file mode 100644 index 43768d9..0000000 --- a/src/3rdparty/phonon/ds9/videorenderer_default.h +++ /dev/null @@ -1,55 +0,0 @@ -/* This file is part of the KDE project. - -Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). - -This library is free software: you can redistribute it and/or modify -it under the terms of the GNU Lesser General Public License as published by -the Free Software Foundation, either version 2.1 or 3 of the License. - -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public License -along with this library. If not, see . -*/ - -#ifndef PHONON_VIDEORENDERER_DEFAULT_H -#define PHONON_VIDEORENDERER_DEFAULT_H - -#include "abstractvideorenderer.h" - -QT_BEGIN_NAMESPACE - -#ifndef QT_NO_PHONON_VIDEO - -namespace Phonon -{ - namespace DS9 - { - class VideoRendererDefault : public AbstractVideoRenderer - { - public: - VideoRendererDefault(QWidget *target); - ~VideoRendererDefault(); - - //Implementation from AbstractVideoRenderer - void repaintCurrentFrame(QWidget *target, const QRect &rect); - void notifyResize(const QSize&, Phonon::VideoWidget::AspectRatio, Phonon::VideoWidget::ScaleMode); - QSize videoSize() const; - QImage snapshot() const; - void applyMixerSettings(qreal brightness, qreal contrast, qreal m_hue, qreal saturation); - bool isNative() const; - private: - QWidget *m_target; - }; - } -} - -#endif //QT_NO_PHONON_VIDEO - -QT_END_NAMESPACE - -#endif - diff --git a/src/3rdparty/phonon/ds9/videorenderer_evr.cpp b/src/3rdparty/phonon/ds9/videorenderer_evr.cpp deleted file mode 100644 index d23d9ce..0000000 --- a/src/3rdparty/phonon/ds9/videorenderer_evr.cpp +++ /dev/null @@ -1,215 +0,0 @@ -/* This file is part of the KDE project. - -Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). - -This library is free software: you can redistribute it and/or modify -it under the terms of the GNU Lesser General Public License as published by -the Free Software Foundation, either version 2.1 or 3 of the License. - -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public License -along with this library. If not, see . -*/ - - -#include "videorenderer_evr.h" -#include "qevr9.h" - -#ifndef QT_NO_PHONON_VIDEO - -#include -#include - -QT_BEGIN_NAMESPACE - -namespace Phonon -{ - namespace DS9 - { - //we have to define them here because not all compilers/sdk have them - static const GUID MR_VIDEO_RENDER_SERVICE = {0x1092a86c, 0xab1a, 0x459a, {0xa3, 0x36, 0x83, 0x1f, 0xbc, 0x4d, 0x11, 0xff} }; - static const GUID MR_VIDEO_MIXER_SERVICE = { 0x73cd2fc, 0x6cf4, 0x40b7, {0x88, 0x59, 0xe8, 0x95, 0x52, 0xc8, 0x41, 0xf8} }; - static const IID IID_IMFVideoDisplayControl = {0xa490b1e4, 0xab84, 0x4d31, {0xa1, 0xb2, 0x18, 0x1e, 0x03, 0xb1, 0x07, 0x7a} }; - static const IID IID_IMFVideoMixerControl = {0xA5C6C53F, 0xC202, 0x4aa5, {0x96, 0x95, 0x17, 0x5B, 0xA8, 0xC5, 0x08, 0xA5} }; - static const IID IID_IMFVideoProcessor = {0x6AB0000C, 0xFECE, 0x4d1f, {0xA2, 0xAC, 0xA9, 0x57, 0x35, 0x30, 0x65, 0x6E} }; - static const IID IID_IMFGetService = {0xFA993888, 0x4383, 0x415A, {0xA9, 0x30, 0xDD, 0x47, 0x2A, 0x8C, 0xF6, 0xF7} }; - static const GUID CLSID_EnhancedVideoRenderer = {0xfa10746c, 0x9b63, 0x4b6c, {0xbc, 0x49, 0xfc, 0x30, 0xe, 0xa5, 0xf2, 0x56} }; - - template ComPointer getService(const Filter &filter, REFGUID guidService, REFIID riid) - { - //normally we should use IID_IMFGetService but this introduces another dependency - //so here we simply define our own IId with the same value - ComPointer getService(filter, IID_IMFGetService); - Q_ASSERT(getService); - T *ptr = 0; - HRESULT hr = getService->GetService(guidService, riid, reinterpret_cast(&ptr)); - if (!SUCCEEDED(hr) || ptr == 0) - Q_ASSERT(!SUCCEEDED(hr) && ptr != 0); - ComPointer service(ptr); - return service; - } - - VideoRendererEVR::~VideoRendererEVR() - { - } - - bool VideoRendererEVR::isNative() const - { - return true; - } - - VideoRendererEVR::VideoRendererEVR(QWidget *target) : m_target(target) - { - m_filter = Filter(CLSID_EnhancedVideoRenderer, IID_IBaseFilter); - if (!m_filter) { - return; - } - - ComPointer filterControl = getService(m_filter, MR_VIDEO_RENDER_SERVICE, IID_IMFVideoDisplayControl); - - filterControl->SetVideoWindow(reinterpret_cast(target->winId())); - filterControl->SetAspectRatioMode(MFVideoARMode_None); // We're in control of the size - } - - QImage VideoRendererEVR::snapshot() const - { - // This will always capture black areas where no video is drawn, if any are present. - // Due to the hack in notifyResize() - ComPointer filterControl = getService(m_filter, MR_VIDEO_RENDER_SERVICE, IID_IMFVideoDisplayControl); - if (filterControl) { - BITMAPINFOHEADER bmi; - BYTE *buffer = 0; - DWORD bufferSize; - LONGLONG timeStamp; - - bmi.biSize = sizeof(BITMAPINFOHEADER); - - HRESULT hr = filterControl->GetCurrentImage(&bmi, &buffer, &bufferSize, &timeStamp); - if (SUCCEEDED(hr)) { - - const int w = qAbs(bmi.biWidth), - h = qAbs(bmi.biHeight); - - // Create image and copy data into image. - QImage ret(w, h, QImage::Format_RGB32); - - if (!ret.isNull()) { - uchar *data = buffer; - const int bytes_per_line = w * sizeof(QRgb); - for (int y = h - 1; y >= 0; --y) { - qMemCopy(ret.scanLine(y), //destination - data, //source - bytes_per_line); - data += bytes_per_line; - } - } - ::CoTaskMemFree(buffer); - return ret; - } - } - return QImage(); - } - - QSize VideoRendererEVR::videoSize() const - { - SIZE nativeSize; - SIZE aspectRatioSize; - - ComPointer filterControl = getService(m_filter, MR_VIDEO_RENDER_SERVICE, IID_IMFVideoDisplayControl); - - filterControl->GetNativeVideoSize(&nativeSize, &aspectRatioSize); - - return QSize(nativeSize.cx, nativeSize.cy); - } - - void VideoRendererEVR::repaintCurrentFrame(QWidget *target, const QRect &rect) - { - // repaint the video - ComPointer filterControl = getService(m_filter, MR_VIDEO_RENDER_SERVICE, IID_IMFVideoDisplayControl); - // All failed results can be safely ignored - filterControl->RepaintVideo(); - } - - void VideoRendererEVR::notifyResize(const QSize &size, Phonon::VideoWidget::AspectRatio aspectRatio, - Phonon::VideoWidget::ScaleMode scaleMode) - { - if (!isActive()) { - RECT dummyRect = { 0, 0, 0, 0}; - ComPointer filterControl = getService(m_filter, MR_VIDEO_RENDER_SERVICE, IID_IMFVideoDisplayControl); - filterControl->SetVideoPosition(0, &dummyRect); - return; - } - - const QSize vsize = videoSize(); - internalNotifyResize(size, vsize, aspectRatio, scaleMode); - - RECT dstRectWin = { 0, 0, size.width(), size.height()}; - - // Resize the Stream output rect instead of the destination rect. - // Hacky workaround for flicker in the areas outside of the destination rect - // This way these areas don't exist - MFVideoNormalizedRect streamOutputRect = { float(m_dstX) / float(size.width()), float(m_dstY) / float(size.height()), - float(m_dstWidth + m_dstX) / float(size.width()), float(m_dstHeight + m_dstY) / float(size.height())}; - - ComPointer filterMixer = getService(m_filter, MR_VIDEO_MIXER_SERVICE, IID_IMFVideoMixerControl); - ComPointer filterControl = getService(m_filter, MR_VIDEO_RENDER_SERVICE, IID_IMFVideoDisplayControl); - - filterMixer->SetStreamOutputRect(0, &streamOutputRect); - filterControl->SetVideoPosition(0, &dstRectWin); - } - - void VideoRendererEVR::applyMixerSettings(qreal brightness, qreal contrast, qreal hue, qreal saturation) - { - InputPin sink = BackendNode::pins(m_filter, PINDIR_INPUT).first(); - OutputPin source; - if (FAILED(sink->ConnectedTo(source.pparam()))) { - return; //it must be connected to work - } - - // Get the "Video Processor" (used for brightness/contrast/saturation/hue) - ComPointer processor = getService(m_filter, MR_VIDEO_MIXER_SERVICE, IID_IMFVideoProcessor); - Q_ASSERT(processor); - - DXVA2_ValueRange contrastRange; - DXVA2_ValueRange brightnessRange; - DXVA2_ValueRange saturationRange; - DXVA2_ValueRange hueRange; - - if (FAILED(processor->GetProcAmpRange(DXVA2_ProcAmp_Contrast, &contrastRange))) - return; - if (FAILED(processor->GetProcAmpRange(DXVA2_ProcAmp_Brightness, &brightnessRange))) - return; - if (FAILED(processor->GetProcAmpRange(DXVA2_ProcAmp_Saturation, &saturationRange))) - return; - if (FAILED(processor->GetProcAmpRange(DXVA2_ProcAmp_Hue, &hueRange))) - return; - - DXVA2_ProcAmpValues values; - - values.Contrast = DXVA2FloatToFixed(((contrast < 0 - ? DXVA2FixedToFloat(contrastRange.MinValue) : DXVA2FixedToFloat(contrastRange.MaxValue)) - - DXVA2FixedToFloat(contrastRange.DefaultValue)) * qAbs(contrast) + DXVA2FixedToFloat(contrastRange.DefaultValue)); - values.Brightness = DXVA2FloatToFixed(((brightness < 0 - ? DXVA2FixedToFloat(brightnessRange.MinValue) : DXVA2FixedToFloat(brightnessRange.MaxValue)) - - DXVA2FixedToFloat(brightnessRange.DefaultValue)) * qAbs(brightness) + DXVA2FixedToFloat(brightnessRange.DefaultValue)); - values.Saturation = DXVA2FloatToFixed(((saturation < 0 - ? DXVA2FixedToFloat(saturationRange.MinValue) : DXVA2FixedToFloat(saturationRange.MaxValue)) - - DXVA2FixedToFloat(saturationRange.DefaultValue)) * qAbs(saturation) + DXVA2FixedToFloat(saturationRange.DefaultValue)); - values.Hue = DXVA2FloatToFixed(((hue < 0 - ? DXVA2FixedToFloat(hueRange.MinValue) : DXVA2FixedToFloat(hueRange.MaxValue)) - - DXVA2FixedToFloat(hueRange.DefaultValue)) * qAbs(hue) + DXVA2FixedToFloat(hueRange.DefaultValue)); - - //finally set the settings - processor->SetProcAmpValues(DXVA2_ProcAmp_Contrast | DXVA2_ProcAmp_Brightness | DXVA2_ProcAmp_Saturation | DXVA2_ProcAmp_Hue, &values); - - } - } -} - -QT_END_NAMESPACE - -#endif //QT_NO_PHONON_VIDEO diff --git a/src/3rdparty/phonon/ds9/videorenderer_evr.h b/src/3rdparty/phonon/ds9/videorenderer_evr.h deleted file mode 100644 index 229c36d..0000000 --- a/src/3rdparty/phonon/ds9/videorenderer_evr.h +++ /dev/null @@ -1,56 +0,0 @@ -/* This file is part of the KDE project. - -Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). - -This library is free software: you can redistribute it and/or modify -it under the terms of the GNU Lesser General Public License as published by -the Free Software Foundation, either version 2.1 or 3 of the License. - -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public License -along with this library. If not, see . -*/ - -#ifndef PHONON_VIDEORENDERER_EVR_H -#define PHONON_VIDEORENDERER_EVR_H - -#include "abstractvideorenderer.h" -#include "compointer.h" - -QT_BEGIN_NAMESPACE - -#ifndef QT_NO_PHONON_VIDEO - -namespace Phonon -{ - namespace DS9 - { - class VideoRendererEVR : public AbstractVideoRenderer - { - public: - VideoRendererEVR(QWidget *target); - ~VideoRendererEVR(); - - //Implementation from AbstractVideoRenderer - void repaintCurrentFrame(QWidget *target, const QRect &rect); - void notifyResize(const QSize&, Phonon::VideoWidget::AspectRatio, Phonon::VideoWidget::ScaleMode); - QSize videoSize() const; - QImage snapshot() const; - void applyMixerSettings(qreal brightness, qreal contrast, qreal m_hue, qreal saturation); - bool isNative() const; - private: - QWidget *m_target; - }; - } -} - -#endif //QT_NO_PHONON_VIDEO - -QT_END_NAMESPACE - -#endif - diff --git a/src/3rdparty/phonon/ds9/videorenderer_soft.cpp b/src/3rdparty/phonon/ds9/videorenderer_soft.cpp index 9c7993c..491d1bd 100644 --- a/src/3rdparty/phonon/ds9/videorenderer_soft.cpp +++ b/src/3rdparty/phonon/ds9/videorenderer_soft.cpp @@ -194,8 +194,8 @@ namespace Phonon m_sampleBuffer = ComPointer(); #ifndef QT_NO_OPENGL freeGLResources(); - m_textureUploaded = false; #endif // QT_NO_OPENGL + m_textureUploaded = false; } void endOfStream() @@ -314,6 +314,7 @@ namespace Phonon REFERENCE_TIME m_start; HANDLE m_renderEvent, m_receiveCanWait; // Signals sample to render QSize m_size; + bool m_textureUploaded; //mixer settings qreal m_brightness, @@ -355,7 +356,6 @@ namespace Phonon bool m_checkedPrograms; bool m_usingOpenGL; - bool m_textureUploaded; GLuint m_program[2]; GLuint m_texture[3]; #endif @@ -365,7 +365,7 @@ namespace Phonon { public: VideoRendererSoftPin(VideoRendererSoftFilter *parent) : - QMemInputPin(parent, videoMediaTypes(), false /*no transformation of the samples*/, 0), + QMemInputPin(parent, videoMediaTypes(), false /*no transformation of the samples*/), m_renderer(parent) { } @@ -436,7 +436,7 @@ namespace Phonon QBaseFilter(CLSID_NULL), m_inputPin(new VideoRendererSoftPin(this)), m_renderer(renderer), m_start(0) #ifndef QT_NO_OPENGL - , m_checkedPrograms(false), m_usingOpenGL(false), m_textureUploaded(false) + ,m_usingOpenGL(false), m_checkedPrograms(false), m_textureUploaded(false) #endif { m_renderEvent = ::CreateEvent(0, 0, 0, 0); @@ -661,10 +661,7 @@ namespace Phonon #ifndef QT_NO_OPENGL - if (painter.paintEngine() && - (painter.paintEngine()->type() == QPaintEngine::OpenGL || painter.paintEngine()->type() == QPaintEngine::OpenGL2) - && checkGLPrograms()) { - + if (painter.paintEngine() && painter.paintEngine()->type() == QPaintEngine::OpenGL && checkGLPrograms()) { //for now we only support YUV (both YV12 and YUY2) updateTexture(); @@ -676,7 +673,6 @@ namespace Phonon } //let's draw the texture - painter.beginNativePainting(); //Let's pass the other arguments const Program prog = (m_inputPin->connectedType().subtype == MEDIASUBTYPE_YV12) ? YV12toRGB : YUY2toRGB; @@ -726,7 +722,6 @@ namespace Phonon glDisableClientState(GL_VERTEX_ARRAY); glDisable(GL_FRAGMENT_PROGRAM_ARB); - painter.endNativePainting(); return; } else #endif diff --git a/src/3rdparty/phonon/ds9/videorenderer_vmr9.cpp b/src/3rdparty/phonon/ds9/videorenderer_vmr9.cpp index 545b31e..298e9fa 100644 --- a/src/3rdparty/phonon/ds9/videorenderer_vmr9.cpp +++ b/src/3rdparty/phonon/ds9/videorenderer_vmr9.cpp @@ -22,9 +22,14 @@ along with this library. If not, see . #include #include +#include +#ifndef Q_OS_WINCE #include #include +#else +#include +#endif QT_BEGIN_NAMESPACE @@ -43,10 +48,116 @@ namespace Phonon } +#ifdef Q_OS_WINCE + VideoRendererVMR9::VideoRendererVMR9(QWidget *target) : m_target(target) + { + m_target->setAttribute(Qt::WA_PaintOnScreen, true); + m_filter = Filter(CLSID_VideoRenderer, IID_IBaseFilter); + } + + QSize VideoRendererVMR9::videoSize() const + { + LONG w = 0, + h = 0; + ComPointer basic(m_filter, IID_IBasicVideo); + if (basic) { + basic->GetVideoSize( &w, &h); + } + return QSize(w, h); + } + + void VideoRendererVMR9::repaintCurrentFrame(QWidget * /*target*/, const QRect & /*rect*/) + { + //nothing to do here: the renderer paints everything + } + + void VideoRendererVMR9::notifyResize(const QSize &size, Phonon::VideoWidget::AspectRatio aspectRatio, + Phonon::VideoWidget::ScaleMode scaleMode) + { + if (!isActive()) { + ComPointer basic(m_filter, IID_IBasicVideo); + if (basic) { + basic->SetDestinationPosition(0, 0, 0, 0); + } + return; + } + + ComPointer video(m_filter, IID_IVideoWindow); + + OAHWND owner; + HRESULT hr = video->get_Owner(&owner); + if (FAILED(hr)) { + return; + } + + const OAHWND newOwner = reinterpret_cast(m_target->winId()); + if (owner != newOwner) { + video->put_Owner(newOwner); + video->put_MessageDrain(newOwner); + video->put_WindowStyle(WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS); + } + + //make sure the widget takes the whole size of the parent + video->SetWindowPosition(0, 0, size.width(), size.height()); + + const QSize vsize = videoSize(); + internalNotifyResize(size, vsize, aspectRatio, scaleMode); + + ComPointer basic(m_filter, IID_IBasicVideo); + if (basic) { + basic->SetDestinationPosition(m_dstX, m_dstY, m_dstWidth, m_dstHeight); + } + } + + void VideoRendererVMR9::applyMixerSettings(qreal /*brightness*/, qreal /*contrast*/, qreal /*m_hue*/, qreal /*saturation*/) + { + //this can't be supported for WinCE + } + + QImage VideoRendererVMR9::snapshot() const + { + ComPointer basic(m_filter, IID_IBasicVideo); + if (basic) { + LONG bufferSize = 0; + //1st we get the buffer size + basic->GetCurrentImage(&bufferSize, 0); + + QByteArray buffer; + buffer.resize(bufferSize); + HRESULT hr = basic->GetCurrentImage(&bufferSize, reinterpret_cast(buffer.data())); + + if (SUCCEEDED(hr)) { + + const BITMAPINFOHEADER *bmi = reinterpret_cast(buffer.constData()); + + const int w = qAbs(bmi->biWidth), + h = qAbs(bmi->biHeight); + + // Create image and copy data into image. + QImage ret(w, h, QImage::Format_RGB32); + + if (!ret.isNull()) { + const char *data = buffer.constData() + bmi->biSize; + const int bytes_per_line = w * sizeof(QRgb); + for (int y = h - 1; y >= 0; --y) { + qMemCopy(ret.scanLine(y), //destination + data, //source + bytes_per_line); + data += bytes_per_line; + } + } + return ret; + } + } + return QImage(); + } + +#else VideoRendererVMR9::VideoRendererVMR9(QWidget *target) : m_target(target) { m_filter = Filter(CLSID_VideoMixingRenderer9, IID_IBaseFilter); if (!m_filter) { + qWarning("the video widget could not be initialized correctly"); return; } @@ -58,7 +169,6 @@ namespace Phonon Q_ASSERT(SUCCEEDED(hr)); ComPointer windowlessControl(m_filter, IID_IVMRWindowlessControl9); windowlessControl->SetVideoClippingWindow(reinterpret_cast(target->winId())); - windowlessControl->SetAspectRatioMode(VMR9ARMode_None); //we're in control of the size } QImage VideoRendererVMR9::snapshot() const @@ -214,6 +324,7 @@ namespace Phonon //finally set the settings mixer->SetProcAmpControl(0, &ctrl); } +#endif } } diff --git a/src/3rdparty/phonon/ds9/videorenderer_vmr9.h b/src/3rdparty/phonon/ds9/videorenderer_vmr9.h index 516d79d..4eb237e 100644 --- a/src/3rdparty/phonon/ds9/videorenderer_vmr9.h +++ b/src/3rdparty/phonon/ds9/videorenderer_vmr9.h @@ -19,6 +19,7 @@ along with this library. If not, see . #define PHONON_VIDEORENDERER_VMR9_H #include "abstractvideorenderer.h" +#include "compointer.h" QT_BEGIN_NAMESPACE diff --git a/src/3rdparty/phonon/ds9/videowidget.cpp b/src/3rdparty/phonon/ds9/videowidget.cpp index 09d42a4..de7ce5f 100644 --- a/src/3rdparty/phonon/ds9/videowidget.cpp +++ b/src/3rdparty/phonon/ds9/videowidget.cpp @@ -24,12 +24,7 @@ along with this library. If not, see . #include "mediaobject.h" -#ifndef Q_OS_WINCE -#include "videorenderer_evr.h" #include "videorenderer_vmr9.h" -#else -#include "videorenderer_default.h" -#endif #include "videorenderer_soft.h" QT_BEGIN_NAMESPACE @@ -89,19 +84,7 @@ namespace Phonon void setCurrentRenderer(AbstractVideoRenderer *renderer) { m_currentRenderer = renderer; - //we disallow repaint on that widget for just a fraction of second - //this allows better transition between videos - setUpdatesEnabled(false); - m_flickerFreeTimer.start(20, this); - } - - void timerEvent(QTimerEvent *e) - { - if (e->timerId() == m_flickerFreeTimer.timerId()) { - m_flickerFreeTimer.stop(); - setUpdatesEnabled(true); - } - QWidget::timerEvent(e); + update(); } QSize sizeHint() const @@ -123,8 +106,6 @@ namespace Phonon void paintEvent(QPaintEvent *e) { - if (!updatesEnabled()) - return; //this avoids repaint from native events checkCurrentRenderingMode(); m_currentRenderer->repaintCurrentFrame(this, e->rect()); } @@ -172,14 +153,13 @@ namespace Phonon } } else if (!isEmbedded()) { m_currentRenderer = m_node->switchRendering(m_currentRenderer); - setAttribute(Qt::WA_PaintOnScreen, false); + setAttribute(Qt::WA_PaintOnScreen, true); } } VideoWidget *m_node; AbstractVideoRenderer *m_currentRenderer; QVariant m_restoreScreenSaverActive; - QBasicTimer m_flickerFreeTimer; }; VideoWidget::VideoWidget(QWidget *parent) @@ -223,9 +203,6 @@ namespace Phonon if (toNative && m_noNativeRendererSupported) return current; //no switch here - if (!mediaObject()) - return current; - //firt we delete the renderer //initialization of the widgets for(int i = 0; i < FILTER_COUNT; ++i) { @@ -284,7 +261,6 @@ namespace Phonon { m_aspectRatio = aspectRatio; updateVideoSize(); - m_widget->update(); } Phonon::VideoWidget::ScaleMode VideoWidget::scaleMode() const @@ -303,7 +279,6 @@ namespace Phonon { m_scaleMode = scaleMode; updateVideoSize(); - m_widget->update(); } void VideoWidget::setBrightness(qreal b) @@ -357,29 +332,14 @@ namespace Phonon int index = graphIndex * 2 + type; if (m_renderers[index] == 0 && autoCreate) { AbstractVideoRenderer *renderer = 0; - if (type == Native) { -#ifndef Q_OS_WINCE - renderer = new VideoRendererEVR(m_widget); - if (renderer->getFilter() == 0) { - delete renderer; - //EVR not present, let's try VMR - renderer = new VideoRendererVMR9(m_widget); - if (renderer->getFilter() == 0) { - //instanciating the renderer might fail - m_noNativeRendererSupported = true; - delete renderer; - renderer = 0; - } - } -#else - renderer = new VideoRendererDefault(m_widget); + if (type == Native) { + renderer = new VideoRendererVMR9(m_widget); if (renderer->getFilter() == 0) { - //instanciating the renderer might fail + //instanciating the renderer might fail with error VFW_E_DDRAW_CAPS_NOT_SUITABLE (0x80040273) m_noNativeRendererSupported = true; delete renderer; renderer = 0; } -#endif } if (renderer == 0) { diff --git a/src/3rdparty/phonon/ds9/volumeeffect.cpp b/src/3rdparty/phonon/ds9/volumeeffect.cpp index a93b074..b9a5fce 100644 --- a/src/3rdparty/phonon/ds9/volumeeffect.cpp +++ b/src/3rdparty/phonon/ds9/volumeeffect.cpp @@ -76,7 +76,7 @@ namespace Phonon class VolumeMemInputPin : public QMemInputPin { public: - VolumeMemInputPin(QBaseFilter *parent, const QVector &mt, QPin *output) : QMemInputPin(parent, mt, true /*transform*/, output) + VolumeMemInputPin(QBaseFilter *parent, const QVector &mt) : QMemInputPin(parent, mt, true /*transform*/) { } @@ -139,7 +139,8 @@ namespace Phonon //then creating the input mt << audioMediaType(); - m_input = new VolumeMemInputPin(this, mt, m_output); + m_input = new VolumeMemInputPin(this, mt); + m_input->addOutput(m_output); //make the connection here } void VolumeEffectFilter::treatOneSamplePerChannel(BYTE **buffer, int sampleSize, int channelCount, int frequency) diff --git a/src/3rdparty/phonon/ds9/volumeeffect.h b/src/3rdparty/phonon/ds9/volumeeffect.h index d1b0186..39b20d0 100644 --- a/src/3rdparty/phonon/ds9/volumeeffect.h +++ b/src/3rdparty/phonon/ds9/volumeeffect.h @@ -47,7 +47,7 @@ namespace Phonon private: float m_volume; - //paramaters used to fade + //parameters used to fade Phonon::VolumeFaderEffect::FadeCurve m_fadeCurve; bool m_fading; //determines if we should be fading. -- cgit v0.12 From b7add13a0c363c9ca435256d879b398b15cb8dca Mon Sep 17 00:00:00 2001 From: Justin McPherson Date: Thu, 25 Mar 2010 14:28:49 +1000 Subject: Update Phonon qt7 backend to 4.4.0. --- src/3rdparty/phonon/qt7/audionode.h | 2 +- src/3rdparty/phonon/qt7/audionode.mm | 16 +- src/3rdparty/phonon/qt7/backendinfo.mm | 1 - src/3rdparty/phonon/qt7/mediaobject.h | 40 +--- src/3rdparty/phonon/qt7/mediaobject.mm | 286 +++++++----------------- src/3rdparty/phonon/qt7/quicktimemetadata.h | 8 +- src/3rdparty/phonon/qt7/quicktimemetadata.mm | 41 ++-- src/3rdparty/phonon/qt7/quicktimevideoplayer.h | 28 +-- src/3rdparty/phonon/qt7/quicktimevideoplayer.mm | 265 +++------------------- src/3rdparty/phonon/qt7/videoframe.mm | 24 +- 10 files changed, 137 insertions(+), 574 deletions(-) diff --git a/src/3rdparty/phonon/qt7/audionode.h b/src/3rdparty/phonon/qt7/audionode.h index 2498e49..dfec817f 100644 --- a/src/3rdparty/phonon/qt7/audionode.h +++ b/src/3rdparty/phonon/qt7/audionode.h @@ -72,7 +72,7 @@ namespace QT7 AudioUnit m_audioUnit; // Only the following methods needs to - // be overidden by only_one-audio-unit nodes: + // be overridden by only_one-audio-unit nodes: virtual ComponentDescription getAudioNodeDescription() const; virtual void initializeAudioUnit(); diff --git a/src/3rdparty/phonon/qt7/audionode.mm b/src/3rdparty/phonon/qt7/audionode.mm index 961230c..cb9e82f 100644 --- a/src/3rdparty/phonon/qt7/audionode.mm +++ b/src/3rdparty/phonon/qt7/audionode.mm @@ -68,15 +68,13 @@ void AudioNode::createAndConnectAUNodes() << QString(!FindNextComponent(0, &description) ? "ERROR: COMPONENT NOT FOUND!" : "OK!")) OSStatus err = noErr; - - // The proper function to call here is AUGraphAddNode() but the type has - // changed between 10.5 and 10.6. it's still OK to call this function, but - // if we want to use the proper thing we need to move over to - // AudioComponentDescription everywhere, which is very similar to the - // ComponentDescription, but a different size. however, - // AudioComponentDescription only exists on 10.6+. More fun than we need to - // deal with at the moment, so we'll take the "deprecated" warning instead. - err = AUGraphNewNode(m_audioGraph->audioGraphRef(), &description, 0, 0, &m_auNode); +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 + if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_5) + err = AUGraphAddNode(m_audioGraph->audioGraphRef(), &description, &m_auNode); + else +#endif + err = AUGraphNewNode(m_audioGraph->audioGraphRef(), &description, 0, 0, &m_auNode); + BACKEND_ASSERT2(err != kAUGraphErr_OutputNodeErr, "A MediaObject can only be connected to one audio output device.", FATAL_ERROR) BACKEND_ASSERT2(err == noErr, "Could not create new AUNode.", FATAL_ERROR) } diff --git a/src/3rdparty/phonon/qt7/backendinfo.mm b/src/3rdparty/phonon/qt7/backendinfo.mm index 0d51db0..e173f05 100644 --- a/src/3rdparty/phonon/qt7/backendinfo.mm +++ b/src/3rdparty/phonon/qt7/backendinfo.mm @@ -22,7 +22,6 @@ #include #include -#include #import #ifdef QUICKTIME_C_API_AVAILABLE diff --git a/src/3rdparty/phonon/qt7/mediaobject.h b/src/3rdparty/phonon/qt7/mediaobject.h index c93eddc..27949ec 100644 --- a/src/3rdparty/phonon/qt7/mediaobject.h +++ b/src/3rdparty/phonon/qt7/mediaobject.h @@ -25,10 +25,6 @@ #include "medianode.h" -#if QT_ALLOW_QUICKTIME - #include -#endif - QT_BEGIN_NAMESPACE namespace Phonon @@ -42,10 +38,7 @@ namespace QT7 class MediaObjectAudioNode; class MediaObject : public MediaNode, - public Phonon::MediaObjectInterface -#ifndef QT_NO_PHONON_MEDIACONTROLLER - , public Phonon::AddonInterface -#endif + public Phonon::MediaObjectInterface, public Phonon::AddonInterface { Q_OBJECT Q_INTERFACES(Phonon::MediaObjectInterface Phonon::AddonInterface) @@ -99,10 +92,6 @@ namespace QT7 int videoOutputCount(); -#if QT_ALLOW_QUICKTIME - void displayLinkEvent(); -#endif - signals: void stateChanged(Phonon::State,Phonon::State); void tick(qint64); @@ -116,16 +105,6 @@ namespace QT7 void metaDataChanged(QMultiMap); void currentSourceChanged(const MediaSource &newSource); - // Add-on interface: - void availableSubtitlesChanged(); - void availableAudioChannelsChanged(); - void titleChanged(int); - void availableTitlesChanged(int); - void chapterChanged(int); - void availableChaptersChanged(int); - void angleChanged(int); - void availableAnglesChanged(int); - protected: void mediaNodeEvent(const MediaNodeEvent *event); bool event(QEvent *event); @@ -139,14 +118,7 @@ namespace QT7 QuickTimeVideoPlayer *m_nextVideoPlayer; QuickTimeAudioPlayer *m_nextAudioPlayer; MediaObjectAudioNode *m_mediaObjectAudioNode; - -#if QT_ALLOW_QUICKTIME - CVDisplayLinkRef m_displayLink; - QMutex m_displayLinkMutex; - bool m_pendingDisplayLinkEvent; - void startDisplayLink(); - void stopDisplayLink(); -#endif + QuickTimeMetaData *m_metaData; qint32 m_tickInterval; qint32 m_transitionTime; @@ -155,14 +127,12 @@ namespace QT7 float m_percentageLoaded; int m_tickTimer; - int m_videoTimer; - int m_audioTimer; + int m_bufferTimer; int m_rapidTimer; bool m_waitNextSwap; int m_swapTimeLeft; QTime m_swapTime; - bool m_autoplayTitles; void synchAudioVideo(); void updateCurrentTime(); @@ -171,7 +141,8 @@ namespace QT7 void pause_internal(); void play_internal(); void setupAudioSystem(); - void restartAudioVideoTimers(); + void updateTimer(int &timer, int interval); + void bufferAudioVideo(); void updateRapidly(); void updateCrossFade(); void updateAudioBuffers(); @@ -183,7 +154,6 @@ namespace QT7 void inspectVideoGraphRecursive(MediaNode *node, int &effectCount, int &outputCount); void inspectGraph(); bool isCrossFading(); - void setCurrentTrack(int track); QString m_errorString; Phonon::ErrorType m_errorType; diff --git a/src/3rdparty/phonon/qt7/mediaobject.mm b/src/3rdparty/phonon/qt7/mediaobject.mm index 677640c..f8d635a 100644 --- a/src/3rdparty/phonon/qt7/mediaobject.mm +++ b/src/3rdparty/phonon/qt7/mediaobject.mm @@ -46,6 +46,7 @@ MediaObject::MediaObject(QObject *parent) : MediaNode(AudioSource | VideoSource, m_mediaObjectAudioNode = new MediaObjectAudioNode(m_audioPlayer, m_nextAudioPlayer); setAudioNode(m_mediaObjectAudioNode); + m_metaData = new QuickTimeMetaData(); m_audioGraph = new AudioGraph(this); m_tickInterval = 0; @@ -54,7 +55,6 @@ MediaObject::MediaObject(QObject *parent) : MediaNode(AudioSource | VideoSource, m_transitionTime = 0; m_percentageLoaded = 0; m_waitNextSwap = false; - m_autoplayTitles = true; m_audioEffectCount = 0; m_audioOutputCount = 0; m_videoEffectCount = 0; @@ -63,28 +63,20 @@ MediaObject::MediaObject(QObject *parent) : MediaNode(AudioSource | VideoSource, m_errorType = Phonon::NoError; m_tickTimer = 0; - m_videoTimer = 0; - m_audioTimer = 0; + m_bufferTimer = 0; m_rapidTimer = 0; -#if QT_ALLOW_QUICKTIME - m_displayLink = 0; - m_pendingDisplayLinkEvent = false; -#endif - checkForError(); } MediaObject::~MediaObject() -{ - // m_mediaObjectAudioNode is owned by super class. -#if QT_ALLOW_QUICKTIME - stopDisplayLink(); -#endif +{ + // m_mediaObjectAudioNode is owned by super class. m_audioPlayer->unsetVideoPlayer(); m_nextAudioPlayer->unsetVideoPlayer(); delete m_videoPlayer; delete m_nextVideoPlayer; + delete m_metaData; checkForError(); } @@ -222,28 +214,28 @@ void MediaObject::setSource(const MediaSource &source) IMPLEMENTED; PhononAutoReleasePool pool; setState(Phonon::LoadingState); - + // Save current state for event/signal handling below: bool prevHasVideo = m_videoPlayer->hasVideo(); qint64 prevTotalTime = totalTime(); - int prevTrackCount = m_videoPlayer->trackCount(); m_waitNextSwap = false; - + // Cancel cross-fade if any: m_nextVideoPlayer->pause(); m_nextAudioPlayer->pause(); m_mediaObjectAudioNode->cancelCrossFade(); - + // Set new source: m_audioPlayer->unsetVideoPlayer(); m_videoPlayer->setMediaSource(source); m_audioPlayer->setVideoPlayer(m_videoPlayer); + m_metaData->setVideo(m_videoPlayer); - m_audioGraph->updateStreamSpecifications(); + m_audioGraph->updateStreamSpecifications(); m_nextAudioPlayer->unsetVideoPlayer(); - m_nextVideoPlayer->unsetCurrentMediaSource(); + m_nextVideoPlayer->unsetVideo(); m_currentTime = 0; - + // Emit/notify information about the new source: QRect videoRect = m_videoPlayer->videoRect(); MediaNodeEvent e1(MediaNodeEvent::VideoFrameSizeChanged, &videoRect); @@ -254,14 +246,12 @@ void MediaObject::setSource(const MediaSource &source) updateVideo(emptyFrame); emit currentSourceChanged(source); - emit metaDataChanged(m_videoPlayer->metaData()); + emit metaDataChanged(m_metaData->metaData()); if (prevHasVideo != m_videoPlayer->hasVideo()) - emit hasVideoChanged(m_videoPlayer->hasVideo()); + emit hasVideoChanged(m_videoPlayer->hasVideo()); if (prevTotalTime != totalTime()) - emit totalTimeChanged(totalTime()); - if (prevTrackCount != m_videoPlayer->trackCount()) - emit availableTitlesChanged(m_videoPlayer->trackCount()); + emit totalTimeChanged(totalTime()); if (checkForError()) return; if (!m_videoPlayer->isDrmAuthorized()) @@ -297,30 +287,28 @@ void MediaObject::swapCurrentWithNext(qint32 transitionTime) // Save current state for event/signal handling below: bool prevHasVideo = m_videoPlayer->hasVideo(); qint64 prevTotalTime = totalTime(); - int prevTrackCount = m_videoPlayer->trackCount(); qSwap(m_audioPlayer, m_nextAudioPlayer); qSwap(m_videoPlayer, m_nextVideoPlayer); m_mediaObjectAudioNode->startCrossFade(transitionTime); m_audioGraph->updateStreamSpecifications(); + m_metaData->setVideo(m_videoPlayer); m_waitNextSwap = false; m_currentTime = 0; - + // Emit/notify information about the new source: QRect videoRect = m_videoPlayer->videoRect(); MediaNodeEvent e1(MediaNodeEvent::VideoFrameSizeChanged, &videoRect); notify(&e1); emit currentSourceChanged(m_videoPlayer->mediaSource()); - emit metaDataChanged(m_videoPlayer->metaData()); + emit metaDataChanged(m_metaData->metaData()); if (prevHasVideo != m_videoPlayer->hasVideo()) - emit hasVideoChanged(m_videoPlayer->hasVideo()); + emit hasVideoChanged(m_videoPlayer->hasVideo()); if (prevTotalTime != totalTime()) emit totalTimeChanged(totalTime()); - if (prevTrackCount != m_videoPlayer->trackCount()) - emit availableTitlesChanged(m_videoPlayer->trackCount()); if (checkForError()) return; if (!m_videoPlayer->isDrmAuthorized()) @@ -339,107 +327,28 @@ void MediaObject::swapCurrentWithNext(qint32 transitionTime) } } -#if QT_ALLOW_QUICKTIME -static CVReturn displayLinkCallback(CVDisplayLinkRef /*displayLink*/, - const CVTimeStamp */*inNow*/, - const CVTimeStamp */*inOutputTime*/, - CVOptionFlags /*flagsIn*/, - CVOptionFlags */*flagsOut*/, - void *userData) +void MediaObject::updateTimer(int &timer, int interval) { - MediaObject *mediaObject = static_cast(userData); - mediaObject->displayLinkEvent(); - return kCVReturnSuccess; -} - -void MediaObject::displayLinkEvent() -{ - // This function is called from a - // thread != gui thread. So we post the event. - // But we need to make sure that we don't post faster - // than the event loop can eat: - m_displayLinkMutex.lock(); - bool pending = m_pendingDisplayLinkEvent; - m_pendingDisplayLinkEvent = true; - m_displayLinkMutex.unlock(); - - if (!pending) - qApp->postEvent(this, new QEvent(QEvent::User), Qt::HighEventPriority); -} - -void MediaObject::startDisplayLink() -{ - if (m_displayLink) - return; - OSStatus err = CVDisplayLinkCreateWithCGDisplay(kCGDirectMainDisplay, &m_displayLink); - if (err != noErr) - goto fail; - err = CVDisplayLinkSetCurrentCGDisplay(m_displayLink, kCGDirectMainDisplay); - if (err != noErr) - goto fail; - err = CVDisplayLinkSetOutputCallback(m_displayLink, displayLinkCallback, this); - if (err != noErr) - goto fail; - err = CVDisplayLinkStart(m_displayLink); - if (err != noErr) - goto fail; - return; -fail: - stopDisplayLink(); -} - -void MediaObject::stopDisplayLink() -{ - if (!m_displayLink) - return; - CVDisplayLinkStop(m_displayLink); - CFRelease(m_displayLink); - m_displayLink = 0; -} -#endif - -void MediaObject::restartAudioVideoTimers() -{ - if (m_videoTimer) - killTimer(m_videoTimer); - if (m_audioTimer) - killTimer(m_audioTimer); - -#if QT_ALLOW_QUICKTIME - // We prefer to use a display link as timer if available, since - // it is more steady, and results in better and smoother frame drawing: - startDisplayLink(); - if (!m_displayLink){ - float fps = m_videoPlayer->staticFps(); - long videoUpdateFrequency = fps ? long(1000.0f / fps) : 0.001; - m_videoTimer = startTimer(videoUpdateFrequency); - } -#else - float fps = m_videoPlayer->staticFps(); - long videoUpdateFrequency = fps ? long(1000.0f / fps) : 0.001; - m_videoTimer = startTimer(videoUpdateFrequency); -#endif - - long audioUpdateFrequency = m_audioPlayer->regularTaskFrequency(); - m_audioTimer = startTimer(audioUpdateFrequency); - updateVideoFrames(); - updateAudioBuffers(); + if (timer) + killTimer(timer); + timer = 0; + if (interval >= 0) + timer = startTimer(interval); } void MediaObject::play_internal() { // Play main audio/video: m_videoPlayer->play(); - m_audioPlayer->play(); + m_audioPlayer->play(); updateLipSynch(0); // Play old audio/video to finish cross-fade: if (m_nextVideoPlayer->currentTime() > 0){ m_nextVideoPlayer->play(); m_nextAudioPlayer->play(); } - restartAudioVideoTimers(); - if (!m_rapidTimer) - m_rapidTimer = startTimer(100); + bufferAudioVideo(); + updateTimer(m_rapidTimer, 100); } void MediaObject::pause_internal() @@ -449,15 +358,9 @@ void MediaObject::pause_internal() m_nextAudioPlayer->pause(); m_videoPlayer->pause(); m_nextVideoPlayer->pause(); - killTimer(m_rapidTimer); - killTimer(m_videoTimer); - killTimer(m_audioTimer); - m_rapidTimer = 0; - m_videoTimer = 0; - m_audioTimer = 0; -#if QT_ALLOW_QUICKTIME - stopDisplayLink(); -#endif + updateTimer(m_rapidTimer, -1); + updateTimer(m_bufferTimer, -1); + if (m_waitNextSwap) m_swapTimeLeft = m_swapTime.msecsTo(QTime::currentTime()); } @@ -520,7 +423,7 @@ void MediaObject::stop() if (!setState(Phonon::StoppedState)) return; m_waitNextSwap = false; - m_nextVideoPlayer->unsetCurrentMediaSource(); + m_nextVideoPlayer->unsetVideo(); m_nextAudioPlayer->unsetVideoPlayer(); pause_internal(); seek(0); @@ -532,9 +435,9 @@ void MediaObject::seek(qint64 milliseconds) IMPLEMENTED; if (m_state == Phonon::ErrorState) return; - + // Stop cross-fade if any: - m_nextVideoPlayer->unsetCurrentMediaSource(); + m_nextVideoPlayer->unsetVideo(); m_nextAudioPlayer->unsetVideoPlayer(); m_mediaObjectAudioNode->cancelCrossFade(); @@ -664,24 +567,19 @@ void MediaObject::updateCurrentTime() m_currentTime = (m_audioSystem == AS_Graph) ? m_audioPlayer->currentTime() : m_videoPlayer->currentTime(); quint64 total = m_videoPlayer->duration(); - if (m_videoPlayer->currentTrack() < m_videoPlayer->trackCount() - 1){ - // There are still more tracks to play after the current track. - if (m_autoplayTitles) { - if (lastUpdateTime < m_currentTime && m_currentTime == total) - setCurrentTrack(m_videoPlayer->currentTrack() + 1); - } - } else if (m_nextVideoPlayer->state() == QuickTimeVideoPlayer::NoMedia){ - // There is no more sources or tracks to play after the current source. - // Check if it's time to emit aboutToFinish: - quint32 mark = qMax(quint64(0), qMin(total, total + m_transitionTime - 2000)); - if (lastUpdateTime < mark && mark <= m_currentTime) - emit aboutToFinish(); - - // Check if it's time to emit prefinishMarkReached: - mark = qMax(quint64(0), total - m_prefinishMark); - if (lastUpdateTime < mark && mark <= m_currentTime) - emit prefinishMarkReached(total - m_currentTime); + // Check if it's time to emit aboutToFinish: + quint32 mark = qMax(quint64(0), qMin(total, total + m_transitionTime - 2000)); + if (lastUpdateTime < mark && mark <= m_currentTime) + emit aboutToFinish(); + + // Check if it's time to emit prefinishMarkReached: + mark = qMax(quint64(0), total - m_prefinishMark); + if (lastUpdateTime < mark && mark <= m_currentTime) + emit prefinishMarkReached(total - m_currentTime); + if (m_nextVideoPlayer->state() == QuickTimeVideoPlayer::NoMedia){ + // There is no next source in que. + // Check if it's time to emit finished: if (lastUpdateTime < m_currentTime && m_currentTime == total){ emit finished(); m_currentTime = (m_audioSystem == AS_Graph) ? m_audioPlayer->currentTime() : m_videoPlayer->currentTime(); @@ -691,7 +589,7 @@ void MediaObject::updateCurrentTime() } else { // We have a next source. // Check if it's time to swap to next source: - quint32 mark = qMax(quint64(0), total + m_transitionTime); + mark = qMax(quint64(0), total + m_transitionTime); if (m_waitNextSwap && m_state == Phonon::PlayingState && m_transitionTime < m_swapTime.msecsTo(QTime::currentTime())){ swapCurrentWithNext(0); @@ -794,14 +692,14 @@ bool MediaObject::setAudioDeviceOnMovie(int id) void MediaObject::updateCrossFade() { - m_mediaObjectAudioNode->updateCrossFade(m_currentTime); + m_mediaObjectAudioNode->updateCrossFade(m_currentTime); // Clean-up previous movie if done fading: if (m_mediaObjectAudioNode->m_fadeDuration == 0){ if (m_nextVideoPlayer->isPlaying() || m_nextAudioPlayer->isPlaying()){ - m_nextVideoPlayer->unsetCurrentMediaSource(); + m_nextVideoPlayer->unsetVideo(); m_nextAudioPlayer->unsetVideoPlayer(); } - } + } } void MediaObject::updateBufferStatus() @@ -830,7 +728,7 @@ void MediaObject::updateVideoFrames() // Draw next frame if awailable: if (m_videoPlayer->videoFrameChanged()){ updateLipSynch(50); - VideoFrame frame(m_videoPlayer); + VideoFrame frame(m_videoPlayer); if (m_nextVideoPlayer->isPlaying() && m_nextVideoPlayer->hasVideo() && isCrossFading()){ @@ -838,9 +736,9 @@ void MediaObject::updateVideoFrames() frame.setBackgroundFrame(bgFrame); frame.setBaseOpacity(m_mediaObjectAudioNode->m_volume1); } - + // Send the frame through the graph: - updateVideo(frame); + updateVideo(frame); checkForError(); } } @@ -851,7 +749,7 @@ void MediaObject::updateLipSynch(int allowedOffset) return; if (m_videoSinkList.isEmpty() || m_audioSinkList.isEmpty()) return; - + if (m_videoPlayer->hasVideo()){ qint64 diff = m_audioPlayer->currentTime() - m_videoPlayer->currentTime(); if (-allowedOffset > diff || diff > allowedOffset) @@ -865,6 +763,16 @@ void MediaObject::updateLipSynch(int allowedOffset) } } +void MediaObject::bufferAudioVideo() +{ + long nextVideoUpdate = m_videoPlayer->hasVideo() ? 30 : INT_MAX; + long nextAudioUpdate = m_audioPlayer->regularTaskFrequency(); + updateAudioBuffers(); + updateVideoFrames(); + if (m_state == Phonon::PlayingState) + updateTimer(m_bufferTimer, qMin(nextVideoUpdate, nextAudioUpdate)); +} + void MediaObject::updateRapidly() { updateCurrentTime(); @@ -889,8 +797,8 @@ void MediaObject::mediaNodeEvent(const MediaNodeEvent *event) synchAudioVideo(); checkForError(); m_mediaObjectAudioNode->setMute(false); - if (m_state == Phonon::PlayingState) - restartAudioVideoTimers(); + if (m_state == Phonon::PlayingState) + bufferAudioVideo(); break; case MediaNodeEvent::AudioGraphCannotPlay: case MediaNodeEvent::AudioGraphInitialized: @@ -901,7 +809,7 @@ void MediaObject::mediaNodeEvent(const MediaNodeEvent *event) checkForError(); m_mediaObjectAudioNode->setMute(false); } - break; + break; default: break; } @@ -910,67 +818,29 @@ void MediaObject::mediaNodeEvent(const MediaNodeEvent *event) bool MediaObject::event(QEvent *event) { switch (event->type()){ -#if QT_ALLOW_QUICKTIME - case QEvent::User:{ - m_displayLinkMutex.lock(); - m_pendingDisplayLinkEvent = false; - m_displayLinkMutex.unlock(); - updateVideoFrames(); - break; } -#endif - case QEvent::Timer:{ - int timerId = static_cast(event)->timerId(); - if (timerId == m_rapidTimer) + case QEvent::Timer: { + QTimerEvent *timerEvent = static_cast(event); + if (timerEvent->timerId() == m_rapidTimer) updateRapidly(); - else if (timerId == m_tickTimer) + else if (timerEvent->timerId() == m_tickTimer) emit tick(currentTime()); - else if (timerId == m_videoTimer) - updateVideoFrames(); - else if (timerId == m_audioTimer) - updateAudioBuffers(); - break; } + else if (timerEvent->timerId() == m_bufferTimer) + bufferAudioVideo(); + } + break; default: break; } return QObject::event(event); } -void MediaObject::setCurrentTrack(int track) -{ - if (track == m_videoPlayer->currentTrack() || track < 0 || track >= m_videoPlayer->trackCount()) - return; - - m_videoPlayer->setCurrentTrack(track); - emit titleChanged(track); - emit metaDataChanged(m_videoPlayer->metaData()); -} - -bool MediaObject::hasInterface(Interface iface) const +bool MediaObject::hasInterface(Interface /*interface*/) const { - return iface == AddonInterface::TitleInterface; + return false; } -QVariant MediaObject::interfaceCall(Interface iface, int command, const QList ¶ms) +QVariant MediaObject::interfaceCall(Interface /*interface*/, int /*command*/, const QList &/*arguments*/) { - switch (iface) { - case TitleInterface: - switch (command) { - case availableTitles: - return m_videoPlayer->trackCount(); - case title: - return m_videoPlayer->currentTrack(); - case setTitle: - setCurrentTrack(params.first().toInt()); - break; - case autoplayTitles: - return m_autoplayTitles; - case setAutoplayTitles: - m_autoplayTitles = params.first().toBool(); - break; - } - default: - break; - } return QVariant(); } diff --git a/src/3rdparty/phonon/qt7/quicktimemetadata.h b/src/3rdparty/phonon/qt7/quicktimemetadata.h index c589535..d524183 100644 --- a/src/3rdparty/phonon/qt7/quicktimemetadata.h +++ b/src/3rdparty/phonon/qt7/quicktimemetadata.h @@ -38,8 +38,10 @@ namespace QT7 class QuickTimeMetaData { public: - QuickTimeMetaData(QuickTimeVideoPlayer *videoPlayer); - void update(); + QuickTimeMetaData(); + virtual ~QuickTimeMetaData(); + + void setVideo(QuickTimeVideoPlayer *videoPlayer); QMultiMap metaData(); private: @@ -47,8 +49,6 @@ namespace QT7 bool m_movieChanged; QuickTimeVideoPlayer *m_videoPlayer; void readMetaData(); - void guessMetaDataForCD(); - void readMetaDataFromMovie(); #ifdef QUICKTIME_C_API_AVAILABLE QString stripCopyRightSymbol(const QString &key); diff --git a/src/3rdparty/phonon/qt7/quicktimemetadata.mm b/src/3rdparty/phonon/qt7/quicktimemetadata.mm index 2dcc152..851e707 100644 --- a/src/3rdparty/phonon/qt7/quicktimemetadata.mm +++ b/src/3rdparty/phonon/qt7/quicktimemetadata.mm @@ -15,7 +15,6 @@ along with this library. If not, see . */ -#include #include "quicktimemetadata.h" #include "quicktimevideoplayer.h" @@ -26,14 +25,19 @@ namespace Phonon namespace QT7 { -QuickTimeMetaData::QuickTimeMetaData(QuickTimeVideoPlayer *videoPlayer) +QuickTimeMetaData::QuickTimeMetaData() { - m_videoPlayer = videoPlayer; + m_videoPlayer = 0; m_movieChanged = false; } -void QuickTimeMetaData::update() +QuickTimeMetaData::~QuickTimeMetaData() { +} + +void QuickTimeMetaData::setVideo(QuickTimeVideoPlayer *videoPlayer) +{ + m_videoPlayer = videoPlayer; m_movieChanged = true; m_metaData.clear(); } @@ -141,22 +145,14 @@ void QuickTimeMetaData::readFormattedData(QTMetaDataRef metaDataRef, OSType form #endif // QUICKTIME_C_API_AVAILABLE -void QuickTimeMetaData::guessMetaDataForCD() -{ - QString album = QFileInfo(m_videoPlayer->movieCompactDiscPath()).fileName(); - QString title = QFileInfo(m_videoPlayer->currentTrackPath()).fileName(); - title = title.left(title.lastIndexOf('.')); - m_metaData.insert(QLatin1String("ALBUM"), album); - m_metaData.insert(QLatin1String("TITLE"), title); - m_metaData.insert(QLatin1String("TRACKNUMBER"), QString::number(m_videoPlayer->currentTrack())); -} - -void QuickTimeMetaData::readMetaDataFromMovie() +void QuickTimeMetaData::readMetaData() { + if (!m_videoPlayer) + return; QMultiMap metaMap; - + #ifdef QUICKTIME_C_API_AVAILABLE - QTMetaDataRef metaDataRef; + QTMetaDataRef metaDataRef; OSStatus err = QTCopyMovieMetaData([m_videoPlayer->qtMovie() quickTimeMovie], &metaDataRef); BACKEND_ASSERT2(err == noErr, "Could not read QuickTime meta data", NORMAL_ERROR) @@ -177,17 +173,6 @@ void QuickTimeMetaData::readMetaDataFromMovie() m_metaData.insert(QLatin1String("DESCRIPTION"), metaMap.value(QLatin1String("des"))); } -void QuickTimeMetaData::readMetaData() -{ - if (!m_videoPlayer) - return; - - if (m_videoPlayer->mediaSource().type() == Phonon::MediaSource::Disc) - guessMetaDataForCD(); - else - readMetaDataFromMovie(); -} - QMultiMap QuickTimeMetaData::metaData() { if (m_videoPlayer && m_videoPlayer->hasMovie() && m_movieChanged) diff --git a/src/3rdparty/phonon/qt7/quicktimevideoplayer.h b/src/3rdparty/phonon/qt7/quicktimevideoplayer.h index 98eacb5..0b3aec2 100644 --- a/src/3rdparty/phonon/qt7/quicktimevideoplayer.h +++ b/src/3rdparty/phonon/qt7/quicktimevideoplayer.h @@ -20,7 +20,6 @@ #include "backendheader.h" -#include #import #import @@ -39,7 +38,6 @@ namespace Phonon namespace QT7 { class QuickTimeStreamReader; - class QuickTimeMetaData; class VideoRenderWidgetQTMovieView; class QuickTimeVideoPlayer : QObject @@ -57,7 +55,7 @@ namespace QT7 void setMediaSource(const MediaSource &source); MediaSource mediaSource() const; - void unsetCurrentMediaSource(); + void unsetVideo(); void play(); void pause(); @@ -68,13 +66,11 @@ namespace QT7 GLuint currentFrameAsGLTexture(); void *currentFrameAsCIImage(); QImage currentFrameAsQImage(); - void releaseImageCache(); QRect videoRect() const; quint64 duration() const; quint64 currentTime() const; long timeScale() const; - float staticFps(); QString currentTimeString(); void setColors(qreal brightness = 0, qreal contrast = 1, qreal hue = 0, qreal saturation = 1); @@ -87,7 +83,6 @@ namespace QT7 bool setAudioDevice(int id); void setPlaybackRate(float rate); QTMovie *qtMovie() const; - QMultiMap metaData(); float playbackRate() const; float prefferedPlaybackRate() const; @@ -107,12 +102,6 @@ namespace QT7 float percentageLoaded(); quint64 timeLoaded(); - int trackCount() const; - int currentTrack() const; - void setCurrentTrack(int track); - QString movieCompactDiscPath() const; - QString currentTrackPath() const; - static QString timeToString(quint64 ms); // Help functions when drawing to more that one widget in cocoa 64: @@ -126,10 +115,6 @@ namespace QT7 QTMovie *m_QTMovie; State m_state; QGLPixelBuffer *m_QImagePixelBuffer; - QuickTimeMetaData *m_metaData; - - CVOpenGLTextureRef m_cachedCVTextureRef; - QImage m_cachedQImage; bool m_playbackRateSat; bool m_isDrmProtected; @@ -140,18 +125,13 @@ namespace QT7 float m_masterVolume; float m_relativeVolume; float m_playbackRate; - float m_staticFps; quint64 m_currentTime; MediaSource m_mediaSource; - void *m_primaryRenderingCIImage; qreal m_brightness; qreal m_contrast; qreal m_hue; qreal m_saturation; - NSArray *m_folderTracks; - int m_currentTrack; - QString m_movieCompactDiscPath; #ifdef QUICKTIME_C_API_AVAILABLE QTVisualContextRef m_visualContext; @@ -159,26 +139,20 @@ namespace QT7 VideoFrame m_currentFrame; QuickTimeStreamReader *m_streamReader; - void prepareCurrentMovieForPlayback(); void createVisualContext(); void openMovieFromCurrentMediaSource(); void openMovieFromDataRef(QTDataReference *dataRef); void openMovieFromFile(); void openMovieFromUrl(); void openMovieFromStream(); - void openMovieFromCompactDisc(); void openMovieFromData(QByteArray *data, char *fileType); void openMovieFromDataGuessType(QByteArray *data); QString mediaSourcePath(); bool codecExistsAccordingToSuffix(const QString &fileName); - NSString* pathToCompactDisc(); - bool isCompactDisc(NSString *path); - NSArray* scanFolder(NSString *path); void setError(NSError *error); bool errorOccured(); void readProtection(); - void calculateStaticFps(); void checkIfVideoAwailable(); bool movieNotLoaded(); void waitStatePlayable(); diff --git a/src/3rdparty/phonon/qt7/quicktimevideoplayer.mm b/src/3rdparty/phonon/qt7/quicktimevideoplayer.mm index 23c76e3..3f76132 100644 --- a/src/3rdparty/phonon/qt7/quicktimevideoplayer.mm +++ b/src/3rdparty/phonon/qt7/quicktimevideoplayer.mm @@ -20,7 +20,6 @@ #include "videowidget.h" #include "audiodevice.h" #include "quicktimestreamreader.h" -#include "quicktimemetadata.h" #include #include @@ -53,7 +52,6 @@ QuickTimeVideoPlayer::QuickTimeVideoPlayer() : QObject(0) { m_state = NoMedia; m_mediaSource = MediaSource(); - m_metaData = new QuickTimeMetaData(this); m_QTMovie = 0; m_streamReader = 0; m_playbackRate = 1.0f; @@ -63,16 +61,12 @@ QuickTimeVideoPlayer::QuickTimeVideoPlayer() : QObject(0) m_mute = false; m_audioEnabled = false; m_hasVideo = false; - m_staticFps = 0; m_playbackRateSat = false; m_isDrmProtected = false; m_isDrmAuthorized = true; m_primaryRenderingTarget = 0; m_primaryRenderingCIImage = 0; m_QImagePixelBuffer = 0; - m_cachedCVTextureRef = 0; - m_folderTracks = 0; - m_currentTrack = 0; #ifdef QUICKTIME_C_API_AVAILABLE OSStatus err = EnterMovies(); @@ -83,9 +77,7 @@ QuickTimeVideoPlayer::QuickTimeVideoPlayer() : QObject(0) QuickTimeVideoPlayer::~QuickTimeVideoPlayer() { - PhononAutoReleasePool pool; - unsetCurrentMediaSource(); - delete m_metaData; + unsetVideo(); [(NSObject*)m_primaryRenderingTarget release]; m_primaryRenderingTarget = 0; #ifdef QUICKTIME_C_API_AVAILABLE @@ -94,15 +86,6 @@ QuickTimeVideoPlayer::~QuickTimeVideoPlayer() #endif } -void QuickTimeVideoPlayer::releaseImageCache() -{ - if (m_cachedCVTextureRef){ - CVOpenGLTextureRelease(m_cachedCVTextureRef); - m_cachedCVTextureRef = 0; - } - m_cachedQImage = QImage(); -} - void QuickTimeVideoPlayer::createVisualContext() { #ifdef QUICKTIME_C_API_AVAILABLE @@ -142,10 +125,7 @@ bool QuickTimeVideoPlayer::videoFrameChanged() return false; QTVisualContextTask(m_visualContext); - bool changed = QTVisualContextIsNewImageAvailable(m_visualContext, 0); - if (changed) - releaseImageCache(); - return changed; + return QTVisualContextIsNewImageAvailable(m_visualContext, 0); #elif defined(QT_MAC_USE_COCOA) return true; @@ -160,11 +140,10 @@ CVOpenGLTextureRef QuickTimeVideoPlayer::currentFrameAsCVTexture() #ifdef QUICKTIME_C_API_AVAILABLE if (!m_visualContext) return 0; - if (!m_cachedCVTextureRef){ - OSStatus err = QTVisualContextCopyImageForTime(m_visualContext, 0, 0, &m_cachedCVTextureRef); - BACKEND_ASSERT3(err == noErr, "Could not copy image for time in QuickTime player", FATAL_ERROR, 0) - } - return m_cachedCVTextureRef; + CVOpenGLTextureRef texture = 0; + OSStatus err = QTVisualContextCopyImageForTime(m_visualContext, 0, 0, &texture); + BACKEND_ASSERT3(err == noErr, "Could not copy image for time in QuickTime player", FATAL_ERROR, 0) + return texture; #else return 0; @@ -173,9 +152,6 @@ CVOpenGLTextureRef QuickTimeVideoPlayer::currentFrameAsCVTexture() QImage QuickTimeVideoPlayer::currentFrameAsQImage() { - if (!m_cachedQImage.isNull()) - return m_cachedQImage; - #ifdef QUICKTIME_C_API_AVAILABLE QGLContext *prevContext = const_cast(QGLContext::currentContext()); CVOpenGLTextureRef texture = currentFrameAsCVTexture(); @@ -205,11 +181,12 @@ QImage QuickTimeVideoPlayer::currentFrameAsQImage() glVertex2i(-1, -1); glEnd(); - m_cachedQImage = m_QImagePixelBuffer->toImage(); + QImage image = m_QImagePixelBuffer->toImage(); + CVOpenGLTextureRelease(texture); // Because of QuickTime, m_QImagePixelBuffer->doneCurrent() will fail. // So we store, and restore, the context our selves: prevContext->makeCurrent(); - return m_cachedQImage; + return image; #else CIImage *img = (CIImage *)currentFrameAsCIImage(); if (!img) @@ -218,10 +195,10 @@ QImage QuickTimeVideoPlayer::currentFrameAsQImage() NSBitmapImageRep* bitmap = [[NSBitmapImageRep alloc] initWithCIImage:img]; CGRect bounds = [img extent]; QImage qImg([bitmap bitmapData], bounds.size.width, bounds.size.height, QImage::Format_ARGB32); - m_cachedQImage = qImg.rgbSwapped(); + QImage swapped = qImg.rgbSwapped(); [bitmap release]; [img release]; - return m_cachedQImage; + return swapped; #endif } @@ -273,7 +250,8 @@ void *QuickTimeVideoPlayer::currentFrameAsCIImage() #ifdef QUICKTIME_C_API_AVAILABLE CVOpenGLTextureRef cvImg = currentFrameAsCVTexture(); CIImage *img = [[CIImage alloc] initWithCVImageBuffer:cvImg]; - return img; + CVOpenGLTextureRelease(cvImg); + return img; #else return 0; #endif @@ -295,7 +273,7 @@ GLuint QuickTimeVideoPlayer::currentFrameAsGLTexture() int samplesPerPixel = [bitmap samplesPerPixel]; if (![bitmap isPlanar] && (samplesPerPixel == 3 || samplesPerPixel == 4)){ - glTexImage2D(GL_TEXTURE_RECTANGLE_EXT, 0, + glTexImage2D(GL_TEXTURE_RECTANGLE_EXT, 0, samplesPerPixel == 4 ? GL_RGBA8 : GL_RGB8, [bitmap pixelsWide], [bitmap pixelsHigh], 0, samplesPerPixel == 4 ? GL_RGBA : GL_RGB, @@ -324,7 +302,7 @@ void QuickTimeVideoPlayer::setVolume(float masterVolume, float relativeVolume) m_masterVolume = masterVolume; m_relativeVolume = relativeVolume; if (!m_QTMovie || !m_audioEnabled || m_mute) - return; + return; [m_QTMovie setVolume:(m_masterVolume * m_relativeVolume)]; } @@ -335,7 +313,7 @@ void QuickTimeVideoPlayer::setMute(bool mute) return; // Work-around bug that happends if you set/unset mute - // before movie is playing, and audio is not played + // before movie is playing, and audio is not played // through graph. Then audio is delayed. [m_QTMovie setMuted:mute]; [m_QTMovie setVolume:(mute ? 0 : m_masterVolume * m_relativeVolume)]; @@ -348,7 +326,7 @@ void QuickTimeVideoPlayer::enableAudio(bool enable) return; // Work-around bug that happends if you set/unset mute - // before movie is playing, and audio is not played + // before movie is playing, and audio is not played // through graph. Then audio is delayed. [m_QTMovie setMuted:(!enable || m_mute)]; [m_QTMovie setVolume:((!enable || m_mute) ? 0 : m_masterVolume * m_relativeVolume)]; @@ -367,7 +345,7 @@ bool QuickTimeVideoPlayer::setAudioDevice(int id) #ifdef QUICKTIME_C_API_AVAILABLE // The following code will not work for some media codecs that // typically mingle audio/video frames (e.g mpeg). - CFStringRef idString = PhononCFString::toCFStringRef(AudioDevice::deviceUID(id)); + CFStringRef idString = PhononCFString::toCFStringRef(AudioDevice::deviceUID(id)); QTAudioContextRef context; QTAudioContextCreateForAudioDevice(kCFAllocatorDefault, idString, 0, &context); OSStatus err = SetMovieAudioContext([m_QTMovie quickTimeMovie], context); @@ -391,16 +369,11 @@ void QuickTimeVideoPlayer::setColors(qreal brightness, qreal contrast, qreal hue contrast += 1; saturation += 1; - if (m_brightness == brightness - && m_contrast == contrast - && m_hue == hue - && m_saturation == saturation) - return; - m_brightness = brightness; m_contrast = contrast; m_hue = hue; m_saturation = saturation; + #ifdef QUICKTIME_C_API_AVAILABLE Float32 value; value = brightness; @@ -412,7 +385,6 @@ void QuickTimeVideoPlayer::setColors(qreal brightness, qreal contrast, qreal hue value = saturation; SetMovieVisualSaturation([m_QTMovie quickTimeMovie], value, 0); #endif - releaseImageCache(); } QRect QuickTimeVideoPlayer::videoRect() const @@ -425,7 +397,7 @@ QRect QuickTimeVideoPlayer::videoRect() const return QRect(0, 0, size.width, size.height); } -void QuickTimeVideoPlayer::unsetCurrentMediaSource() +void QuickTimeVideoPlayer::unsetVideo() { if (!m_QTMovie) return; @@ -438,17 +410,11 @@ void QuickTimeVideoPlayer::unsetCurrentMediaSource() m_state = NoMedia; m_isDrmProtected = false; m_isDrmAuthorized = true; - m_hasVideo = false; - m_staticFps = 0; m_mediaSource = MediaSource(); - m_movieCompactDiscPath.clear(); [(CIImage *)m_primaryRenderingCIImage release]; m_primaryRenderingCIImage = 0; delete m_QImagePixelBuffer; m_QImagePixelBuffer = 0; - releaseImageCache(); - [m_folderTracks release]; - m_folderTracks = 0; } QuickTimeVideoPlayer::State QuickTimeVideoPlayer::state() const @@ -558,25 +524,18 @@ bool QuickTimeVideoPlayer::codecExistsAccordingToSuffix(const QString &fileName) void QuickTimeVideoPlayer::setMediaSource(const MediaSource &mediaSource) { PhononAutoReleasePool pool; - unsetCurrentMediaSource(); - + unsetVideo(); m_mediaSource = mediaSource; if (mediaSource.type() == MediaSource::Empty || mediaSource.type() == MediaSource::Invalid){ m_state = NoMedia; return; } - openMovieFromCurrentMediaSource(); if (errorOccured()){ - unsetCurrentMediaSource(); + unsetVideo(); return; } - prepareCurrentMovieForPlayback(); -} - -void QuickTimeVideoPlayer::prepareCurrentMovieForPlayback() -{ #ifdef QUICKTIME_C_API_AVAILABLE if (m_visualContext) SetMovieVisualContext([m_QTMovie quickTimeMovie], m_visualContext); @@ -584,25 +543,23 @@ void QuickTimeVideoPlayer::prepareCurrentMovieForPlayback() waitStatePlayable(); if (errorOccured()){ - unsetCurrentMediaSource(); + unsetVideo(); return; } readProtection(); preRollMovie(); if (errorOccured()){ - unsetCurrentMediaSource(); + unsetVideo(); return; } if (!m_playbackRateSat) m_playbackRate = prefferedPlaybackRate(); checkIfVideoAwailable(); - calculateStaticFps(); enableAudio(m_audioEnabled); setMute(m_mute); setVolume(m_masterVolume, m_relativeVolume); - m_metaData->update(); pause(); } @@ -616,7 +573,7 @@ void QuickTimeVideoPlayer::openMovieFromCurrentMediaSource() openMovieFromUrl(); break; case MediaSource::Disc: - openMovieFromCompactDisc(); + CASE_UNSUPPORTED("Could not open media source.", FATAL_ERROR) break; case MediaSource::Stream: openMovieFromStream(); @@ -678,7 +635,7 @@ void QuickTimeVideoPlayer::openMovieFromDataGuessType(QByteArray *data) // than using e.g [QTMovie movieFileTypes:QTIncludeCommonTypes]. Some // codecs *think* they can decode the stream, and crash... #define TryOpenMovieWithCodec(type) gClearError(); \ - openMovieFromData(data, (char *)"."type); \ + openMovieFromData(data, "."type); \ if (m_QTMovie) return; TryOpenMovieWithCodec("avi"); @@ -718,50 +675,6 @@ void QuickTimeVideoPlayer::openMovieFromStream() openMovieFromDataGuessType(m_streamReader->pointerToData()); } -typedef void (*qt_sighandler_t)(int); -static void sigtest(int) { - qApp->exit(0); -} - -void QuickTimeVideoPlayer::openMovieFromCompactDisc() -{ - // Interrupting the application while the device is open - // causes the application to hang. So we need to handle - // this in a more graceful way: - qt_sighandler_t hndl = signal(SIGINT, sigtest); - if (hndl) - signal(SIGINT, hndl); - - PhononAutoReleasePool pool; - NSString *cd = 0; - QString devName = m_mediaSource.deviceName(); - if (devName.isEmpty()) { - cd = pathToCompactDisc(); - if (!cd) { - SET_ERROR("Could not open media source.", NORMAL_ERROR) - return; - } - m_movieCompactDiscPath = PhononCFString::toQString(reinterpret_cast(cd)); - } else { - if (!QFileInfo(devName).isAbsolute()) - devName = QLatin1String("/Volumes/") + devName; - cd = [reinterpret_cast(PhononCFString::toCFStringRef(devName)) autorelease]; - if (!isCompactDisc(cd)) { - SET_ERROR("Could not open media source.", NORMAL_ERROR) - return; - } - m_movieCompactDiscPath = devName; - } - - m_folderTracks = [scanFolder(cd) retain]; - setCurrentTrack(0); -} - -QString QuickTimeVideoPlayer::movieCompactDiscPath() const -{ - return m_movieCompactDiscPath; -} - MediaSource QuickTimeVideoPlayer::mediaSource() const { return m_mediaSource; @@ -807,44 +720,6 @@ long QuickTimeVideoPlayer::timeScale() const return [[m_QTMovie attributeForKey:@"QTMovieTimeScaleAttribute"] longValue]; } -float QuickTimeVideoPlayer::staticFps() -{ - return m_staticFps; -} - -void QuickTimeVideoPlayer::calculateStaticFps() -{ - if (!m_hasVideo){ - m_staticFps = 0; - return; - } - -#ifdef QT_ALLOW_QUICKTIME - Boolean isMpeg = false; - Track videoTrack = GetMovieIndTrackType([m_QTMovie quickTimeMovie], 1, - FOUR_CHAR_CODE('vfrr'), // 'vfrr' means: has frame rate - movieTrackCharacteristic | movieTrackEnabledOnly); - Media media = GetTrackMedia(videoTrack); - MediaHandler mediaH = GetMediaHandler(media); - MediaHasCharacteristic(mediaH, FOUR_CHAR_CODE('mpeg'), &isMpeg); - - if (isMpeg){ - MHInfoEncodedFrameRateRecord frameRate; - Size frameRateSize = sizeof(frameRate); - MediaGetPublicInfo(mediaH, kMHInfoEncodedFrameRate, &frameRate, &frameRateSize); - m_staticFps = float(Fix2X(frameRate.encodedFrameRate)); - } else { - Media media = GetTrackMedia(videoTrack); - long sampleCount = GetMediaSampleCount(media); - TimeValue64 duration = GetMediaDisplayDuration(media); - TimeValue64 timeScale = GetMediaTimeScale(media); - m_staticFps = float((double)sampleCount * (double)timeScale / (double)duration); - } -#else - m_staticFps = 30.0f; -#endif -} - QString QuickTimeVideoPlayer::timeToString(quint64 ms) { int sec = ms/1000; @@ -1075,94 +950,6 @@ void QuickTimeVideoPlayer::readProtection() } } -QMultiMap QuickTimeVideoPlayer::metaData() -{ - return m_metaData->metaData(); -} - -int QuickTimeVideoPlayer::trackCount() const -{ - if (!m_folderTracks) - return 0; - return [m_folderTracks count]; -} - -int QuickTimeVideoPlayer::currentTrack() const -{ - return m_currentTrack; -} - -QString QuickTimeVideoPlayer::currentTrackPath() const -{ - if (!m_folderTracks) - return QString(); - - PhononAutoReleasePool pool; - NSString *trackPath = [m_folderTracks objectAtIndex:m_currentTrack]; - return PhononCFString::toQString(reinterpret_cast(trackPath)); -} - -NSString* QuickTimeVideoPlayer::pathToCompactDisc() -{ - PhononAutoReleasePool pool; - NSArray *devices = [[NSWorkspace sharedWorkspace] mountedRemovableMedia]; - for (unsigned int i=0; i<[devices count]; ++i) { - NSString *dev = [devices objectAtIndex:i]; - if (isCompactDisc(dev)) - return [dev retain]; - } - return 0; -} - -bool QuickTimeVideoPlayer::isCompactDisc(NSString *path) -{ - PhononAutoReleasePool pool; - NSString *type = [NSString string]; - [[NSWorkspace sharedWorkspace] getFileSystemInfoForPath:path - isRemovable:0 - isWritable:0 - isUnmountable:0 - description:0 - type:&type]; - return [type hasPrefix:@"cdd"]; -} - -NSArray* QuickTimeVideoPlayer::scanFolder(NSString *path) -{ - NSMutableArray *tracks = [NSMutableArray arrayWithCapacity:20]; - if (!path) - return tracks; - - NSDirectoryEnumerator *enumerator = [[NSFileManager defaultManager] enumeratorAtPath:path]; - while (NSString *track = [enumerator nextObject]) { - if (![track hasPrefix:@"."]) - [tracks addObject:[path stringByAppendingPathComponent:track]]; - } - return tracks; -} - -void QuickTimeVideoPlayer::setCurrentTrack(int track) -{ - PhononAutoReleasePool pool; - [m_QTMovie release]; - m_QTMovie = 0; - m_currentTime = 0; - m_currentTrack = track; - - if (!m_folderTracks) - return; - if (track < 0 || track >= (int)[m_folderTracks count]) - return; - - NSString *trackPath = [m_folderTracks objectAtIndex:track]; - QTDataReference *dataRef = [QTDataReference dataReferenceWithReferenceToFile:trackPath]; - State currentState = m_state; - openMovieFromDataRef(dataRef); - prepareCurrentMovieForPlayback(); - if (currentState == Playing) - play(); -} - }} QT_END_NAMESPACE diff --git a/src/3rdparty/phonon/qt7/videoframe.mm b/src/3rdparty/phonon/qt7/videoframe.mm index 7b67b5e..92a3cd5 100644 --- a/src/3rdparty/phonon/qt7/videoframe.mm +++ b/src/3rdparty/phonon/qt7/videoframe.mm @@ -20,8 +20,6 @@ #import #import -//#define CACHE_CV_TEXTURE - QT_BEGIN_NAMESPACE namespace Phonon @@ -72,9 +70,7 @@ namespace QT7 void VideoFrame::copyMembers(const VideoFrame& frame) { -#ifdef CACHE_CV_TEXTURE m_cachedCVTextureRef = frame.m_cachedCVTextureRef; -#endif m_cachedCIImage = frame.m_cachedCIImage; m_cachedQImage = frame.m_cachedQImage; m_cachedNSBitmap = frame.m_cachedNSBitmap; @@ -109,20 +105,11 @@ namespace QT7 CVOpenGLTextureRef VideoFrame::cachedCVTexture() const { -#ifdef CACHE_CV_TEXTURE if (!m_cachedCVTextureRef && m_videoPlayer){ m_videoPlayer->setColors(m_brightness, m_contrast, m_hue, m_saturation); (const_cast(this))->m_cachedCVTextureRef = m_videoPlayer->currentFrameAsCVTexture(); - CVOpenGLTextureRetain((const_cast(this))->m_cachedCVTextureRef); } return m_cachedCVTextureRef; -#else - if (m_videoPlayer){ - m_videoPlayer->setColors(m_brightness, m_contrast, m_hue, m_saturation); - return m_videoPlayer->currentFrameAsCVTexture(); - } - return 0; -#endif } void *VideoFrame::cachedCIImage() const @@ -342,12 +329,10 @@ namespace QT7 void VideoFrame::invalidateImage() const { -#ifdef CACHE_CV_TEXTURE if (m_cachedCVTextureRef){ CVOpenGLTextureRelease(m_cachedCVTextureRef); (const_cast(this))->m_cachedCVTextureRef = 0; } -#endif if (m_cachedCIImage){ [(CIImage *) m_cachedCIImage release]; (const_cast(this))->m_cachedCIImage = 0; @@ -361,10 +346,8 @@ namespace QT7 void VideoFrame::retain() const { -#ifdef CACHE_CV_TEXTURE if (m_cachedCVTextureRef) CVOpenGLTextureRetain(m_cachedCVTextureRef); -#endif if (m_cachedCIImage) [(CIImage *) m_cachedCIImage retain]; if (m_backgroundFrame) @@ -375,12 +358,8 @@ namespace QT7 void VideoFrame::release() const { -#ifdef CACHE_CV_TEXTURE - if (m_cachedCVTextureRef){ + if (m_cachedCVTextureRef) CVOpenGLTextureRelease(m_cachedCVTextureRef); - (const_cast(this))->m_cachedCVTextureRef = 0; - } -#endif if (m_cachedCIImage) [(CIImage *) m_cachedCIImage release]; if (m_backgroundFrame) @@ -389,6 +368,7 @@ namespace QT7 [m_cachedNSBitmap release]; (const_cast(this))->m_backgroundFrame = 0; + (const_cast(this))->m_cachedCVTextureRef = 0; (const_cast(this))->m_cachedCIImage = 0; (const_cast(this))->m_cachedNSBitmap = 0; } -- cgit v0.12 From 4931e0657af3f22478df8cb26faf178a9886e2d2 Mon Sep 17 00:00:00 2001 From: Justin McPherson Date: Thu, 25 Mar 2010 14:30:17 +1000 Subject: Update Phonon CMakeLists.txt. --- src/3rdparty/phonon/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/3rdparty/phonon/CMakeLists.txt b/src/3rdparty/phonon/CMakeLists.txt index a25ec5d..ff89edb 100644 --- a/src/3rdparty/phonon/CMakeLists.txt +++ b/src/3rdparty/phonon/CMakeLists.txt @@ -149,7 +149,7 @@ set(CMAKE_COLOR_MAKEFILE ON) set(PHONON_LIB_MAJOR_VERSION "4") set(PHONON_LIB_MINOR_VERSION "3") -set(PHONON_LIB_PATCH_VERSION "50") +set(PHONON_LIB_PATCH_VERSION "80") set(PHONON_LIB_VERSION "${PHONON_LIB_MAJOR_VERSION}.4.0") set(PHONON_LIB_SOVERSION ${PHONON_LIB_MAJOR_VERSION}) -- cgit v0.12 From 9d324a07c9c87f972b165a43956424f5c92f80ad Mon Sep 17 00:00:00 2001 From: Justin McPherson Date: Thu, 25 Mar 2010 16:58:42 +1000 Subject: Phonon; complete integration. --- src/3rdparty/phonon/CMakeLists.txt | 4 + src/3rdparty/phonon/gstreamer/backend.cpp | 27 +- src/3rdparty/phonon/phonon/audiodataoutput.cpp | 68 ++ src/3rdparty/phonon/phonon/audiodataoutput.h | 129 +++ src/3rdparty/phonon/phonon/audiodataoutput_p.h | 48 + .../phonon/phonon/audiodataoutputinterface.h | 44 + src/3rdparty/phonon/phonon/globalconfig.h | 71 ++ src/3rdparty/phonon/phonon/pulsesupport.cpp | 1040 ++++++++++++++++++++ src/3rdparty/phonon/phonon/pulsesupport.h | 78 ++ src/3rdparty/phonon/phonon/swiftslider.cpp | 103 ++ src/3rdparty/phonon/phonon/swiftslider_p.h | 68 ++ src/3rdparty/phonon/qt7/mediaobject.mm | 20 +- 12 files changed, 1678 insertions(+), 22 deletions(-) create mode 100644 src/3rdparty/phonon/phonon/audiodataoutput.cpp create mode 100644 src/3rdparty/phonon/phonon/audiodataoutput.h create mode 100644 src/3rdparty/phonon/phonon/audiodataoutput_p.h create mode 100644 src/3rdparty/phonon/phonon/audiodataoutputinterface.h create mode 100644 src/3rdparty/phonon/phonon/globalconfig.h create mode 100644 src/3rdparty/phonon/phonon/pulsesupport.cpp create mode 100644 src/3rdparty/phonon/phonon/pulsesupport.h create mode 100644 src/3rdparty/phonon/phonon/swiftslider.cpp create mode 100644 src/3rdparty/phonon/phonon/swiftslider_p.h diff --git a/src/3rdparty/phonon/CMakeLists.txt b/src/3rdparty/phonon/CMakeLists.txt index ff89edb..ef7d6f5 100644 --- a/src/3rdparty/phonon/CMakeLists.txt +++ b/src/3rdparty/phonon/CMakeLists.txt @@ -70,6 +70,10 @@ if (CMAKE_COMPILER_IS_GNUCXX) add_definitions(-DQT_NO_DEBUG) endif (MINGW) + if (QT_USE_FRAMEWORKS) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -F${QT_LIBRARY_DIR}") + endif (QT_USE_FRAMEWORKS) + check_cxx_compiler_flag(-fPIE HAVE_FPIE_SUPPORT) if(KDE4_ENABLE_FPIE) if(HAVE_FPIE_SUPPORT) diff --git a/src/3rdparty/phonon/gstreamer/backend.cpp b/src/3rdparty/phonon/gstreamer/backend.cpp index 8c2b42f..729a1d3 100644 --- a/src/3rdparty/phonon/gstreamer/backend.cpp +++ b/src/3rdparty/phonon/gstreamer/backend.cpp @@ -220,14 +220,14 @@ QStringList Backend::availableMimeTypes() const GstPluginFeature *feature = GST_PLUGIN_FEATURE(iter->data); QString klass = gst_element_factory_get_klass(GST_ELEMENT_FACTORY(feature)); - if (klass == QLatin1String("Codec/Decoder") || - klass == QLatin1String("Codec/Decoder/Audio") || - klass == QLatin1String("Codec/Decoder/Video") || - klass == QLatin1String("Codec/Demuxer") || - klass == QLatin1String("Codec/Demuxer/Audio") || - klass == QLatin1String("Codec/Demuxer/Video") || - klass == QLatin1String("Codec/Parser") || - klass == QLatin1String("Codec/Parser/Audio") || + if (klass == QLatin1String("Codec/Decoder") || + klass == QLatin1String("Codec/Decoder/Audio") || + klass == QLatin1String("Codec/Decoder/Video") || + klass == QLatin1String("Codec/Demuxer") || + klass == QLatin1String("Codec/Demuxer/Audio") || + klass == QLatin1String("Codec/Demuxer/Video") || + klass == QLatin1String("Codec/Parser") || + klass == QLatin1String("Codec/Parser/Audio") || klass == QLatin1String("Codec/Parser/Video")) { const GList *static_templates; @@ -240,10 +240,13 @@ QStringList Backend::availableMimeTypes() const GstCaps *caps = gst_static_pad_template_get_caps (padTemplate); if (caps) { - const GstStructure* capsStruct = gst_caps_get_structure (caps, 0); - QString mime = QString::fromUtf8(gst_structure_get_name (capsStruct)); - if (!availableMimeTypes.contains(mime)) - availableMimeTypes.append(mime); + for (unsigned int struct_idx = 0; struct_idx < gst_caps_get_size (caps); struct_idx++) { + + const GstStructure* capsStruct = gst_caps_get_structure (caps, struct_idx); + QString mime = QString::fromUtf8(gst_structure_get_name (capsStruct)); + if (!availableMimeTypes.contains(mime)) + availableMimeTypes.append(mime); + } } } } diff --git a/src/3rdparty/phonon/phonon/audiodataoutput.cpp b/src/3rdparty/phonon/phonon/audiodataoutput.cpp new file mode 100644 index 0000000..6c737c2 --- /dev/null +++ b/src/3rdparty/phonon/phonon/audiodataoutput.cpp @@ -0,0 +1,68 @@ +/* This file is part of the KDE project + Copyright (C) 2005 Matthias Kretz + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) version 3, or any + later version accepted by the membership of KDE e.V. (or its + successor approved by the membership of KDE e.V.), Nokia Corporation + (or its successors, if any) and the KDE Free Qt Foundation, which shall + act as a proxy defined in Section 6 of version 3 of the license. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. If not, see . + +*/ + +#include "audiodataoutput.h" +#include "audiodataoutput_p.h" +#include "factory_p.h" + +#define PHONON_CLASSNAME AudioDataOutput + +namespace Phonon +{ + +PHONON_HEIR_IMPL(AbstractAudioOutput) + +PHONON_GETTER(int, dataSize, d->dataSize) +PHONON_GETTER(int, sampleRate, -1) +PHONON_SETTER(setDataSize, dataSize, int) + +bool AudioDataOutputPrivate::aboutToDeleteBackendObject() +{ + Q_ASSERT(m_backendObject); + pBACKEND_GET(int, dataSize, "dataSize"); + + return AbstractAudioOutputPrivate::aboutToDeleteBackendObject(); +} + +void AudioDataOutputPrivate::setupBackendObject() +{ + Q_Q(AudioDataOutput); + Q_ASSERT(m_backendObject); + AbstractAudioOutputPrivate::setupBackendObject(); + + // set up attributes + pBACKEND_CALL1("setDataSize", int, dataSize); + + qRegisterMetaType > >("QMap >"); + + QObject::connect(m_backendObject, + SIGNAL(dataReady(const QMap > &)), + q, SIGNAL(dataReady(const QMap > &))); + QObject::connect(m_backendObject, SIGNAL(endOfMedia(int)), q, SIGNAL(endOfMedia(int))); +} + +} // namespace Phonon + +#include "audiodataoutput.moc" + +#undef PHONON_CLASSNAME +// vim: sw=4 ts=4 tw=80 diff --git a/src/3rdparty/phonon/phonon/audiodataoutput.h b/src/3rdparty/phonon/phonon/audiodataoutput.h new file mode 100644 index 0000000..8e8f8e0 --- /dev/null +++ b/src/3rdparty/phonon/phonon/audiodataoutput.h @@ -0,0 +1,129 @@ +/* This file is part of the KDE project + Copyright (C) 2005-2006 Matthias Kretz + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) version 3, or any + later version accepted by the membership of KDE e.V. (or its + successor approved by the membership of KDE e.V.), Nokia Corporation + (or its successors, if any) and the KDE Free Qt Foundation, which shall + act as a proxy defined in Section 6 of version 3 of the license. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. If not, see . + +*/ +#ifndef Phonon_AUDIODATAOUTPUT_H +#define Phonon_AUDIODATAOUTPUT_H + +#include "phonon_export.h" +#include "abstractaudiooutput.h" +#include "phonondefs.h" + +#ifndef DOXYGEN_SHOULD_SKIP_THIS +template class QVector; +template class QMap; +#endif + +namespace Phonon +{ + class AudioDataOutputPrivate; + + /** + * \short This class gives you the audio data (for visualizations). + * + * This class implements a special AbstractAudioOutput that gives your + * application the audio data. Don't expect realtime performance. But + * the latencies should be low enough to use the audio data for + * visualizations. You can also use the audio data for further processing + * (e.g. encoding and saving to a file). + * + * \author Matthias Kretz + */ + class PHONON_EXPORT AudioDataOutput : public AbstractAudioOutput + { + Q_OBJECT + K_DECLARE_PRIVATE(AudioDataOutput) + Q_ENUMS(Channel) + Q_PROPERTY(int dataSize READ dataSize WRITE setDataSize) + PHONON_HEIR(AudioDataOutput) + public: + /** + * Specifies the channel the audio data belongs to. + */ + enum Channel + { + LeftChannel, + RightChannel, + CenterChannel, + LeftSurroundChannel, + RightSurroundChannel, + SubwooferChannel + }; + + /** + * Returns the currently used number of samples passed through + * the signal. + * + * \see setDataSize + */ + int dataSize() const; + + /** + * Returns the sample rate in Hz. Common sample rates are 44100 Hz + * and 48000 Hz. AudioDataOutput will not do any sample rate + * conversion for you. If you need to convert the sample rate you + * might want to take a look at libsamplerate. For visualizations it + * is often enough to do simple interpolation or even drop/duplicate + * samples. + * + * \return The sample rate as reported by the backend. If the + * backend is unavailable -1 is returned. + */ + int sampleRate() const; + + public Q_SLOTS: + /** + * Sets the number of samples to be passed in one signal emission. + * + * Defaults to 512 samples per emitted signal. + * + * \param size the number of samples + */ + void setDataSize(int size); + + Q_SIGNALS: + /** + * Emitted whenever another dataSize number of samples are ready. + * + * \param data A mapping of Channel to a vector holding the audio data. + */ + void dataReady(const QMap > &data); + + + /** + * This signal is emitted before the last dataReady signal of a + * media is emitted. + * + * If, for example, the playback of a media file has finished and the + * last audio data of that file is going to be passed with the next + * dataReady signal, and only the 28 first samples of the data + * vector are from that media file endOfMedia will be emitted right + * before dataReady with \p remainingSamples = 28. + * + * \param remainingSamples The number of samples in the next + * dataReady vector that belong to the media that was playing to + * this point. + */ + void endOfMedia(int remainingSamples); + }; +} // namespace Phonon + +// vim: sw=4 ts=4 tw=80 +#endif // Phonon_AUDIODATAOUTPUT_H diff --git a/src/3rdparty/phonon/phonon/audiodataoutput_p.h b/src/3rdparty/phonon/phonon/audiodataoutput_p.h new file mode 100644 index 0000000..91103a9 --- /dev/null +++ b/src/3rdparty/phonon/phonon/audiodataoutput_p.h @@ -0,0 +1,48 @@ +/* This file is part of the KDE project + Copyright (C) 2006 Matthias Kretz + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) version 3, or any + later version accepted by the membership of KDE e.V. (or its + successor approved by the membership of KDE e.V.), Nokia Corporation + (or its successors, if any) and the KDE Free Qt Foundation, which shall + act as a proxy defined in Section 6 of version 3 of the license. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. If not, see . + +*/ + +#ifndef AUDIODATAOUTPUT_P_H +#define AUDIODATAOUTPUT_P_H + +#include "audiodataoutput.h" +#include "abstractaudiooutput_p.h" + +namespace Phonon +{ + +class AudioDataOutputPrivate : public AbstractAudioOutputPrivate +{ + Q_DECLARE_PUBLIC(AudioDataOutput) + PHONON_PRIVATECLASS + protected: + AudioDataOutputPrivate() + : dataSize(512) + { + } + + int dataSize; +}; + +} // namespace Phonon + +#endif // AUDIODATAOUTPUT_P_H +// vim: sw=4 ts=4 tw=80 diff --git a/src/3rdparty/phonon/phonon/audiodataoutputinterface.h b/src/3rdparty/phonon/phonon/audiodataoutputinterface.h new file mode 100644 index 0000000..bc1aad0 --- /dev/null +++ b/src/3rdparty/phonon/phonon/audiodataoutputinterface.h @@ -0,0 +1,44 @@ +/* This file is part of the KDE project + Copyright (C) 2008 Matthias Kretz + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) version 3, or any + later version accepted by the membership of KDE e.V. (or its + successor approved by the membership of KDE e.V.), Nokia Corporation + (or its successors, if any) and the KDE Free Qt Foundation, which shall + act as a proxy defined in Section 6 of version 3 of the license. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. If not, see . + +*/ + +#ifndef PHONON_AUDIODATAOUTPUTINTERFACE_H +#define PHONON_AUDIODATAOUTPUTINTERFACE_H + +namespace Phonon +{ + +class AudioDataOutput; + +class AudioDataOutputInterface +{ + public: + virtual ~AudioDataOutputInterface() {} + + virtual AudioDataOutput *frontendObject() const = 0; + virtual void setFrontendObject(AudioDataOutput *) = 0; +}; + +} // namespace Phonon + +Q_DECLARE_INTERFACE(Phonon::AudioDataOutputInterface, "0AudioDataOutputInterface.phonon.kde.org") + +#endif // PHONON_AUDIODATAOUTPUTINTERFACE_H diff --git a/src/3rdparty/phonon/phonon/globalconfig.h b/src/3rdparty/phonon/phonon/globalconfig.h new file mode 100644 index 0000000..5233c7b --- /dev/null +++ b/src/3rdparty/phonon/phonon/globalconfig.h @@ -0,0 +1,71 @@ +/* This file is part of the KDE project +Copyright (C) 2006-2008 Matthias Kretz + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) version 3, or any + later version accepted by the membership of KDE e.V. (or its + successor approved by the membership of KDE e.V.), Nokia Corporation + (or its successors, if any) and the KDE Free Qt Foundation, which shall + act as a proxy defined in Section 6 of version 3 of the license. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. If not, see . + +*/ + +#ifndef PHONON_GLOBALCONFIG_H +#define PHONON_GLOBALCONFIG_H + +#include "phonon_export.h" +#include "phononnamespace.h" +#include "phonondefs.h" + +QT_BEGIN_HEADER +QT_BEGIN_NAMESPACE + +namespace Phonon +{ + class GlobalConfigPrivate; + + class PHONON_EXPORT GlobalConfig + { + K_DECLARE_PRIVATE(GlobalConfig) + public: + GlobalConfig(); + virtual ~GlobalConfig(); + + enum DevicesToHideFlag { + ShowUnavailableDevices = 0, + ShowAdvancedDevices = 0, + HideAdvancedDevices = 1, + AdvancedDevicesFromSettings = 2, + HideUnavailableDevices = 4 + }; + bool hideAdvancedDevices() const; + void setHideAdvancedDevices(bool hide = true); + void setAudioOutputDeviceListFor(Phonon::Category category, QList order); + QList audioOutputDeviceListFor(Phonon::Category category, int override = AdvancedDevicesFromSettings) const; + int audioOutputDeviceFor(Phonon::Category category, int override = AdvancedDevicesFromSettings) const; + +#ifndef QT_NO_PHONON_AUDIOCAPTURE + void setAudioCaptureDeviceListFor(Phonon::Category category, QList order); + QList audioCaptureDeviceListFor(Phonon::Category category, int override = AdvancedDevicesFromSettings) const; + int audioCaptureDeviceFor(Phonon::Category category, int override = AdvancedDevicesFromSettings) const; +#endif //QT_NO_PHONON_AUDIOCAPTURE + + protected: + GlobalConfigPrivate *const k_ptr; + }; +} // namespace Phonon + +QT_END_NAMESPACE +QT_END_HEADER + +#endif // PHONON_GLOBALCONFIG_H diff --git a/src/3rdparty/phonon/phonon/pulsesupport.cpp b/src/3rdparty/phonon/phonon/pulsesupport.cpp new file mode 100644 index 0000000..642843f --- /dev/null +++ b/src/3rdparty/phonon/phonon/pulsesupport.cpp @@ -0,0 +1,1040 @@ +/* This file is part of the KDE project + Copyright (C) 2009 Colin Guthrie + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) version 3, or any + later version accepted by the membership of KDE e.V. (or its + successor approved by the membership of KDE e.V.), Nokia Corporation + (or its successors, if any) and the KDE Free Qt Foundation, which shall + act as a proxy defined in Section 6 of version 3 of the license. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. If not, see . + +*/ + +#include +#include +#include +#include + +#ifdef HAVE_PULSEAUDIO +#include +#include +#include +#include +#ifdef HAVE_PULSEAUDIO_DEVICE_MANAGER +# include +#endif +#endif // HAVE_PULSEAUDIO + +#include "pulsesupport.h" + +QT_BEGIN_NAMESPACE + +namespace Phonon +{ + +static PulseSupport* s_instance = NULL; + +#ifdef HAVE_PULSEAUDIO +/*** +* Prints a conditional debug message based on the current debug level +* If obj is provided, classname and objectname will be printed as well +* +* see debugLevel() +*/ + +static int debugLevel() { + static int level = -1; + if (level < 1) { + level = 0; + QString pulseenv = qgetenv("PHONON_PULSEAUDIO_DEBUG"); + int l = pulseenv.toInt(); + if (l > 0) + level = (l > 2 ? 2 : l); + } + return level; +} + +static void logMessage(const QString &message, int priority = 2, QObject *obj=0); +static void logMessage(const QString &message, int priority, QObject *obj) +{ + if (debugLevel() > 0) { + QString output; + if (obj) { + // Strip away namespace from className + QString className(obj->metaObject()->className()); + int nameLength = className.length() - className.lastIndexOf(':') - 1; + className = className.right(nameLength); + output.sprintf("%s %s (%s %p)", message.toLatin1().constData(), + obj->objectName().toLatin1().constData(), + className.toLatin1().constData(), obj); + } + else { + output = message; + } + if (priority <= debugLevel()) { + qDebug() << QString("PulseSupport(%1): %2").arg(priority).arg(output); + } + } +} + + +class AudioDevice +{ + public: + inline + AudioDevice(QString name, QString desc, QString icon, uint32_t index) + : pulseName(name), pulseIndex(index) + { + properties["name"] = desc; + properties["description"] = ""; // We don't have descriptions (well we do, but we use them as the name!) + properties["icon"] = icon; + properties["available"] = (index != PA_INVALID_INDEX); + properties["isAdvanced"] = false; // Nothing is advanced! + } + + // Needed for QMap + inline AudioDevice() {} + + QString pulseName; + uint32_t pulseIndex; + QHash properties; +}; +bool operator!=(const AudioDevice &a, const AudioDevice &b) +{ + return !(a.pulseName == b.pulseName && a.properties == b.properties); +} + +class PulseUserData +{ + public: + inline + PulseUserData() + { + } + + QMap newOutputDevices; + QMap > newOutputDevicePriorities; // prio, device + + QMap newCaptureDevices; + QMap > newCaptureDevicePriorities; // prio, device +}; + +static QMap s_roleCategoryMap; + +static bool s_pulseActive = false; + +static pa_glib_mainloop *s_mainloop = NULL; +static pa_context *s_context = NULL; + + + +static int s_deviceIndexCounter = 0; + +static QMap s_outputDeviceIndexes; +static QMap s_outputDevices; +static QMap > s_outputDevicePriorities; // prio, device +static QMap s_outputStreamIndexMap; + +static QMap s_captureDeviceIndexes; +static QMap s_captureDevices; +static QMap > s_captureDevicePriorities; // prio, device +static QMap s_captureStreamIndexMap; + +static void createGenericDevices() +{ + // OK so we don't have the device manager extension, but we can show a single device and fake it. + int index; + s_outputDeviceIndexes.clear(); + s_outputDevices.clear(); + s_outputDevicePriorities.clear(); + index = s_deviceIndexCounter++; + s_outputDeviceIndexes.insert("sink:default", index); + s_outputDevices.insert(index, AudioDevice("sink:default", QObject::tr("PulseAudio Sound Server").toUtf8(), "audio-backend-pulseaudio", 0)); + for (int i = Phonon::NoCategory; i <= Phonon::LastCategory; ++i) { + Phonon::Category cat = static_cast(i); + s_outputDevicePriorities[cat].insert(0, index); + } + + s_captureDeviceIndexes.clear(); + s_captureDevices.clear(); + s_captureDevicePriorities.clear(); + index = s_deviceIndexCounter++; + s_captureDeviceIndexes.insert("source:default", index); + s_captureDevices.insert(index, AudioDevice("source:default", QObject::tr("PulseAudio Sound Server").toUtf8(), "audio-backend-pulseaudio", 0)); + for (int i = Phonon::NoCategory; i <= Phonon::LastCategory; ++i) { + Phonon::Category cat = static_cast(i); + s_captureDevicePriorities[cat].insert(0, index); + } +} + +#ifdef HAVE_PULSEAUDIO_DEVICE_MANAGER +static void ext_device_manager_read_cb(pa_context *c, const pa_ext_device_manager_info *info, int eol, void *userdata) { + Q_ASSERT(c); + Q_ASSERT(userdata); + + PulseUserData *u = reinterpret_cast(userdata); + + if (eol < 0) { + logMessage(QString("Failed to initialize device manager extension: %1").arg(pa_strerror(pa_context_errno(c)))); + logMessage("Falling back to single device mode"); + createGenericDevices(); + delete u; + + // If this is our probe phase, exit now + if (s_context != c) + pa_context_disconnect(c); + + return; + } + + if (eol) { + // We're done reading the data, so order it by priority and copy it into the + // static variables where it can then be accessed by those classes that need it. + + QMap::iterator newdev_it; + + // Check for new output devices or things changing about known output devices. + bool output_changed = false; + for (newdev_it = u->newOutputDevices.begin(); newdev_it != u->newOutputDevices.end(); ++newdev_it) { + QString name = newdev_it.key(); + + // The name + index map is always written when a new device is added. + Q_ASSERT(s_outputDeviceIndexes.contains(name)); + + int index = s_outputDeviceIndexes[name]; + if (!s_outputDevices.contains(index)) { + // This is a totally new device + output_changed = true; + logMessage(QString("Brand New Output Device Found.")); + s_outputDevices.insert(index, *newdev_it); + } else if (s_outputDevices[index] != *newdev_it) { + // We have this device already, but is it different? + output_changed = true; + logMessage(QString("Change to Existing Output Device (may be Added/Removed or something else)")); + s_outputDevices.remove(index); + s_outputDevices.insert(index, *newdev_it); + } + } + // Go through the output devices we know about and see if any are no longer mentioned in the list. + QMutableMapIterator output_existing_it(s_outputDeviceIndexes); + while (output_existing_it.hasNext()) { + output_existing_it.next(); + if (!u->newOutputDevices.contains(output_existing_it.key())) { + output_changed = true; + logMessage(QString("Output Device Completely Removed")); + s_outputDevices.remove(output_existing_it.value()); + output_existing_it.remove(); + } + } + + // Check for new capture devices or things changing about known capture devices. + bool capture_changed = false; + for (newdev_it = u->newCaptureDevices.begin(); newdev_it != u->newCaptureDevices.end(); ++newdev_it) { + QString name = newdev_it.key(); + + // The name + index map is always written when a new device is added. + Q_ASSERT(s_captureDeviceIndexes.contains(name)); + + int index = s_captureDeviceIndexes[name]; + if (!s_captureDevices.contains(index)) { + // This is a totally new device + capture_changed = true; + logMessage(QString("Brand New Capture Device Found.")); + s_captureDevices.insert(index, *newdev_it); + } else if (s_captureDevices[index] != *newdev_it) { + // We have this device already, but is it different? + capture_changed = true; + logMessage(QString("Change to Existing Capture Device (may be Added/Removed or something else)")); + s_captureDevices.remove(index); + s_captureDevices.insert(index, *newdev_it); + } + } + // Go through the capture devices we know about and see if any are no longer mentioned in the list. + QMutableMapIterator capture_existing_it(s_captureDeviceIndexes); + while (capture_existing_it.hasNext()) { + capture_existing_it.next(); + if (!u->newCaptureDevices.contains(capture_existing_it.key())) { + capture_changed = true; + logMessage(QString("Capture Device Completely Removed")); + s_captureDevices.remove(capture_existing_it.value()); + capture_existing_it.remove(); + } + } + + // Just copy accross the new priority lists as we know they are valid + if (s_outputDevicePriorities != u->newOutputDevicePriorities) { + output_changed = true; + s_outputDevicePriorities = u->newOutputDevicePriorities; + } + if (s_captureDevicePriorities != u->newCaptureDevicePriorities) { + capture_changed = true; + s_captureDevicePriorities = u->newCaptureDevicePriorities; + } + + if (s_instance) { + // This wont be emitted durring the connection probe phase + // which is intensional + if (output_changed) + s_instance->emitObjectDescriptionChanged(AudioOutputDeviceType); + if (capture_changed) + s_instance->emitObjectDescriptionChanged(AudioCaptureDeviceType); + } + + // We can free the user data as we will not be called again. + delete u; + + // Some debug + logMessage(QString("Output Device Priority List:")); + for (int i = Phonon::NoCategory; i <= Phonon::LastCategory; ++i) { + Phonon::Category cat = static_cast(i); + if (s_outputDevicePriorities.contains(cat)) { + logMessage(QString(" Phonon Category %1").arg(cat)); + int count = 0; + foreach (int j, s_outputDevicePriorities[cat]) { + QHash &props = s_outputDevices[j].properties; + logMessage(QString(" %1. %2 (Available: %3)").arg(++count).arg(props["name"].toString()).arg(props["available"].toBool())); + } + } + } + logMessage(QString("Capture Device Priority List:")); + for (int i = Phonon::NoCategory; i <= Phonon::LastCategory; ++i) { + Phonon::Category cat = static_cast(i); + if (s_captureDevicePriorities.contains(cat)) { + logMessage(QString(" Phonon Category %1").arg(cat)); + int count = 0; + foreach (int j, s_captureDevicePriorities[cat]) { + QHash &props = s_captureDevices[j].properties; + logMessage(QString(" %1. %2 (Available: %3)").arg(++count).arg(props["name"].toString()).arg(props["available"].toBool())); + } + } + } + + // If this is our probe phase, exit now as we're finished reading + // our device info and can exit and reconnect + if (s_context != c) + pa_context_disconnect(c); + } + + if (!info) + return; + + Q_ASSERT(info->name); + Q_ASSERT(info->description); + Q_ASSERT(info->icon); + + // QString wrapper + QString name(info->name); + int index; + QMap > *new_prio_map_cats; // prio, device + QMap *new_devices; + + if (name.startsWith("sink:")) { + new_devices = &u->newOutputDevices; + new_prio_map_cats = &u->newOutputDevicePriorities; + + if (s_outputDeviceIndexes.contains(name)) + index = s_outputDeviceIndexes[name]; + else + index = s_outputDeviceIndexes[name] = s_deviceIndexCounter++; + } else if (name.startsWith("source:")) { + new_devices = &u->newCaptureDevices; + new_prio_map_cats = &u->newCaptureDevicePriorities; + + if (s_captureDeviceIndexes.contains(name)) + index = s_captureDeviceIndexes[name]; + else + index = s_captureDeviceIndexes[name] = s_deviceIndexCounter++; + } else { + // This indicates a bug in pulseaudio. + return; + } + + // Add the new device itself. + new_devices->insert(name, AudioDevice(name, info->description, info->icon, info->index)); + + // For each role in the priority, map it to a phonon category and store the order. + for (uint32_t i = 0; i < info->n_role_priorities; ++i) { + pa_ext_device_manager_role_priority_info* role_prio = &info->role_priorities[i]; + Q_ASSERT(role_prio->role); + + if (s_roleCategoryMap.contains(role_prio->role)) { + Phonon::Category cat = s_roleCategoryMap[role_prio->role]; + + (*new_prio_map_cats)[cat].insert(role_prio->priority, index); + } + } +} + +static void ext_device_manager_subscribe_cb(pa_context *c, void *) { + Q_ASSERT(c); + + pa_operation *o; + PulseUserData *u = new PulseUserData; + if (!(o = pa_ext_device_manager_read(c, ext_device_manager_read_cb, u))) { + logMessage(QString("pa_ext_device_manager_read() failed.")); + delete u; + return; + } + pa_operation_unref(o); +} +#endif + +void sink_input_cb(pa_context *c, const pa_sink_input_info *i, int eol, void *userdata) { + Q_UNUSED(userdata); + Q_ASSERT(c); + + if (eol < 0) { + if (pa_context_errno(c) == PA_ERR_NOENTITY) + return; + + logMessage(QString("Sink input callback failure")); + return; + } + + if (eol > 0) + return; + + Q_ASSERT(i); + + // loop through (*i) and extract phonon->streamindex... + const char *t; + if ((t = pa_proplist_gets(i->proplist, "phonon.streamid"))) { + logMessage(QString("Found PulseAudio stream index %1 for Phonon Output Stream %2").arg(i->index).arg(t)); + s_outputStreamIndexMap[QString(t)] = i->index; + + // Find the sink's phonon index and notify whoever cares... + if (PA_INVALID_INDEX != i->sink) { + bool found = false; + int device; + QMap::iterator it; + for (it = s_outputDevices.begin(); it != s_outputDevices.end(); ++it) { + if ((*it).pulseIndex == i->sink) { + found = true; + device = it.key(); + break; + } + } + if (found) { + // OK so we just emit our signal + logMessage(QString("Letting the rest of phonon know about this")); + s_instance->emitUsingDevice(QString(t), device); + } + } + } +} + +void source_output_cb(pa_context *c, const pa_source_output_info *i, int eol, void *userdata) { + Q_UNUSED(userdata); + Q_ASSERT(c); + + if (eol < 0) { + if (pa_context_errno(c) == PA_ERR_NOENTITY) + return; + + logMessage(QString("Source output callback failure")); + return; + } + + if (eol > 0) + return; + + Q_ASSERT(i); + + // loop through (*i) and extract phonon->streamindex... + const char *t; + if ((t = pa_proplist_gets(i->proplist, "phonon.streamid"))) { + logMessage(QString("Found PulseAudio stream index %1 for Phonon Capture Stream %2").arg(i->index).arg(t)); + s_captureStreamIndexMap[QString(t)] = i->index; + + // Find the source's phonon index and notify whoever cares... + if (PA_INVALID_INDEX != i->source) { + bool found = false; + int device; + QMap::iterator it; + for (it = s_captureDevices.begin(); it != s_captureDevices.end(); ++it) { + if ((*it).pulseIndex == i->source) { + found = true; + device = it.key(); + break; + } + } + if (found) { + // OK so we just emit our signal + logMessage(QString("Letting the rest of phonon know about this")); + s_instance->emitUsingDevice(QString(t), device); + } + } + } +} + +static void subscribe_cb(pa_context *c, pa_subscription_event_type_t t, uint32_t index, void *userdata) { + Q_UNUSED(userdata); + + switch (t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) { + case PA_SUBSCRIPTION_EVENT_SINK_INPUT: + if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) { + QString phononid = s_outputStreamIndexMap.key(index); + if (!phononid.isEmpty()) { + if (s_outputStreamIndexMap.contains(phononid)) { + logMessage(QString("Phonon Output Stream %1 is gone at the PA end. Marking it as invalid in our cache as we may reuse it.").arg(phononid)); + s_outputStreamIndexMap[phononid] = PA_INVALID_INDEX; + } else { + logMessage(QString("Removing Phonon Output Stream %1 (it's gone!)").arg(phononid)); + s_outputStreamIndexMap.remove(phononid); + } + } + } else { + pa_operation *o; + if (!(o = pa_context_get_sink_input_info(c, index, sink_input_cb, NULL))) { + logMessage(QString("pa_context_get_sink_input_info() failed")); + return; + } + pa_operation_unref(o); + } + break; + + case PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT: + if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) { + QString phononid = s_captureStreamIndexMap.key(index); + if (!phononid.isEmpty()) { + if (s_captureStreamIndexMap.contains(phononid)) { + logMessage(QString("Phonon Capture Stream %1 is gone at the PA end. Marking it as invalid in our cache as we may reuse it.").arg(phononid)); + s_captureStreamIndexMap[phononid] = PA_INVALID_INDEX; + } else { + logMessage(QString("Removing Phonon Capture Stream %1 (it's gone!)").arg(phononid)); + s_captureStreamIndexMap.remove(phononid); + } + } + } else { + pa_operation *o; + if (!(o = pa_context_get_source_output_info(c, index, source_output_cb, NULL))) { + logMessage(QString("pa_context_get_sink_input_info() failed")); + return; + } + pa_operation_unref(o); + } + break; + } +} + + +static const char* statename(pa_context_state_t state) +{ + switch (state) + { + case PA_CONTEXT_UNCONNECTED: return "Unconnected"; + case PA_CONTEXT_CONNECTING: return "Connecting"; + case PA_CONTEXT_AUTHORIZING: return "Authorizing"; + case PA_CONTEXT_SETTING_NAME: return "Setting Name"; + case PA_CONTEXT_READY: return "Ready"; + case PA_CONTEXT_FAILED: return "Failed"; + case PA_CONTEXT_TERMINATED: return "Terminated"; + } + + static QString unknown; + unknown = QString("Unknown state: %0").arg(state); + return unknown.toAscii().constData(); +} + +static void context_state_callback(pa_context *c, void *) +{ + Q_ASSERT(c); + + logMessage(QString("context_state_callback %1").arg(statename(pa_context_get_state(c)))); + pa_context_state_t state = pa_context_get_state(c); + if (state == PA_CONTEXT_READY) { + // We've connected to PA, so it is active + s_pulseActive = true; + + // Attempt to load things up + pa_operation *o; + + // 1. Register for the stream changes (except during probe) + if (s_context == c) { + pa_context_set_subscribe_callback(c, subscribe_cb, NULL); + + if (!(o = pa_context_subscribe(c, (pa_subscription_mask_t) + (PA_SUBSCRIPTION_MASK_SINK_INPUT| + PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT), NULL, NULL))) { + logMessage(QString("pa_context_subscribe() failed")); + return; + } + pa_operation_unref(o); + } + +#ifdef HAVE_PULSEAUDIO_DEVICE_MANAGER + // 2a. Attempt to initialise Device Manager info (except during probe) + if (s_context == c) { + pa_ext_device_manager_set_subscribe_cb(c, ext_device_manager_subscribe_cb, NULL); + if (!(o = pa_ext_device_manager_subscribe(c, 1, NULL, NULL))) { + logMessage(QString("pa_ext_device_manager_subscribe() failed")); + return; + } + pa_operation_unref(o); + } + + // 3. Attempt to read info from Device Manager + PulseUserData *u = new PulseUserData; + if (!(o = pa_ext_device_manager_read(c, ext_device_manager_read_cb, u))) { + logMessage(QString("pa_ext_device_manager_read() failed. Attempting to continue without device manager support")); + createGenericDevices(); + delete u; + + // If this is our probe phase, exit immediately + if (s_context != c) + pa_context_disconnect(c); + + return; + } + pa_operation_unref(o); + +#else + // If we know do not have Device Manager support, we just create our dummy devices now + createGenericDevices(); + + // If this is our probe phase, exit immediately + if (s_context != c) + pa_context_disconnect(c); +#endif + } else if (!PA_CONTEXT_IS_GOOD(state)) { + /// @todo Deal with reconnection... + //logMessage("Connection to PulseAudio lost"); + + // If this is our probe phase, exit our context immediately + if (s_context != c) + pa_context_disconnect(c); + } +} +#endif // HAVE_PULSEAUDIO + + +PulseSupport* PulseSupport::getInstance() +{ + if (NULL == s_instance) { + s_instance = new PulseSupport(); + } + return s_instance; +} + +void PulseSupport::shutdown() +{ + if (NULL != s_instance) { + delete s_instance; + s_instance = NULL; + } +} + +PulseSupport::PulseSupport() + : QObject(), mEnabled(false) +{ +#ifdef HAVE_PULSEAUDIO + // Initialise our map (is there a better way to do this?) + s_roleCategoryMap["none"] = Phonon::NoCategory; + s_roleCategoryMap["video"] = Phonon::VideoCategory; + s_roleCategoryMap["music"] = Phonon::MusicCategory; + s_roleCategoryMap["game"] = Phonon::GameCategory; + s_roleCategoryMap["event"] = Phonon::NotificationCategory; + s_roleCategoryMap["phone"] = Phonon::CommunicationCategory; + //s_roleCategoryMap["animation"]; // No Mapping + //s_roleCategoryMap["production"]; // No Mapping + s_roleCategoryMap["a11y"] = Phonon::AccessibilityCategory; + + // To allow for easy debugging, give an easy way to disable this pulseaudio check + QString pulseenv = qgetenv("PHONON_PULSEAUDIO_DISABLE"); + if (pulseenv.toInt()) { + logMessage("PulseAudio support disabled: PHONON_PULSEAUDIO_DISABLE is set"); + return; + } + + // We require a glib event loop + if (QLatin1String(QAbstractEventDispatcher::instance()->metaObject()->className()) + != "QGuiEventDispatcherGlib") { + logMessage("Disabling PulseAudio integration for lack of GLib event loop."); + return; + } + + // First of all conenct to PA via simple/blocking means and if that succeeds, + // use a fully async integrated mainloop method to connect and get proper support. + pa_mainloop *p_test_mainloop; + if (!(p_test_mainloop = pa_mainloop_new())) { + logMessage("PulseAudio support disabled: Unable to create mainloop"); + return; + } + + pa_context *p_test_context; + if (!(p_test_context = pa_context_new(pa_mainloop_get_api(p_test_mainloop), "libphonon-probe"))) { + logMessage("PulseAudio support disabled: Unable to create context"); + pa_mainloop_free(p_test_mainloop); + return; + } + + logMessage("Probing for PulseAudio..."); + // (cg) Convert to PA_CONTEXT_NOFLAGS when PulseAudio 0.9.19 is required + if (pa_context_connect(p_test_context, NULL, static_cast(0), NULL) < 0) { + logMessage(QString("PulseAudio support disabled: %1").arg(pa_strerror(pa_context_errno(p_test_context)))); + pa_context_disconnect(p_test_context); + pa_context_unref(p_test_context); + pa_mainloop_free(p_test_mainloop); + return; + } + + pa_context_set_state_callback(p_test_context, &context_state_callback, NULL); + for (;;) { + pa_mainloop_iterate(p_test_mainloop, 1, NULL); + + if (!PA_CONTEXT_IS_GOOD(pa_context_get_state(p_test_context))) { + logMessage("PulseAudio probe complete."); + break; + } + } + pa_context_disconnect(p_test_context); + pa_context_unref(p_test_context); + pa_mainloop_free(p_test_mainloop); + + if (!s_pulseActive) { + logMessage("PulseAudio support is not available."); + return; + } + + // If we're still here, PA is available. + logMessage("PulseAudio support enabled"); + + // Now we connect for real using a proper main loop that we can forget + // all about processing. + s_mainloop = pa_glib_mainloop_new(NULL); + Q_ASSERT(s_mainloop); + pa_mainloop_api *api = pa_glib_mainloop_get_api(s_mainloop); + + s_context = pa_context_new(api, "libphonon"); + // (cg) Convert to PA_CONTEXT_NOFLAGS when PulseAudio 0.9.19 is required + if (pa_context_connect(s_context, NULL, static_cast(0), 0) >= 0) + pa_context_set_state_callback(s_context, &context_state_callback, NULL); +#endif +} + +PulseSupport::~PulseSupport() +{ +#ifdef HAVE_PULSEAUDIO + if (s_context) { + pa_context_disconnect(s_context); + s_context = NULL; + } + + if (s_mainloop) { + pa_glib_mainloop_free(s_mainloop); + s_mainloop = NULL; + } +#endif +} + +bool PulseSupport::isActive() +{ +#ifdef HAVE_PULSEAUDIO + return mEnabled && s_pulseActive; +#else + return false; +#endif +} + +void PulseSupport::enable(bool enabled) +{ + mEnabled = enabled; +} + +QList PulseSupport::objectDescriptionIndexes(ObjectDescriptionType type) const +{ + QList list; + + if (type != AudioOutputDeviceType && type != AudioCaptureDeviceType) + return list; + +#ifdef HAVE_PULSEAUDIO + if (s_pulseActive) { + switch (type) { + + case AudioOutputDeviceType: { + QMap::iterator it; + for (it = s_outputDeviceIndexes.begin(); it != s_outputDeviceIndexes.end(); ++it) { + list.append(*it); + } + break; + } + case AudioCaptureDeviceType: { + QMap::iterator it; + for (it = s_captureDeviceIndexes.begin(); it != s_captureDeviceIndexes.end(); ++it) { + list.append(*it); + } + break; + } + default: + break; + } + } +#endif + + return list; +} + +QHash PulseSupport::objectDescriptionProperties(ObjectDescriptionType type, int index) const +{ + QHash ret; + + if (type != AudioOutputDeviceType && type != AudioCaptureDeviceType) + return ret; + +#ifndef HAVE_PULSEAUDIO + Q_UNUSED(index); +#else + if (s_pulseActive) { + switch (type) { + + case AudioOutputDeviceType: + Q_ASSERT(s_outputDevices.contains(index)); + ret = s_outputDevices[index].properties; + break; + + case AudioCaptureDeviceType: + Q_ASSERT(s_captureDevices.contains(index)); + ret = s_captureDevices[index].properties; + break; + + default: + break; + } + } +#endif + + return ret; +} + +QList PulseSupport::objectIndexesByCategory(ObjectDescriptionType type, Category category) const +{ + QList ret; + + if (type != AudioOutputDeviceType && type != AudioCaptureDeviceType) + return ret; + +#ifndef HAVE_PULSEAUDIO + Q_UNUSED(category); +#else + if (s_pulseActive) { + switch (type) { + + case AudioOutputDeviceType: + if (s_outputDevicePriorities.contains(category)) + ret = s_outputDevicePriorities[category].values(); + break; + + case AudioCaptureDeviceType: + if (s_captureDevicePriorities.contains(category)) + ret = s_captureDevicePriorities[category].values(); + break; + + default: + break; + } + } +#endif + + return ret; +} + +#ifdef HAVE_PULSEAUDIO +static void setDevicePriority(Category category, QStringList list) +{ + QString role = s_roleCategoryMap.key(category); + if (role.isEmpty()) + return; + + logMessage(QString("Reindexing %1: %2").arg(role).arg(list.join(", "))); + + char **devices; + devices = pa_xnew(char *, list.size()+1); + int i = 0; + foreach (QString str, list) { + devices[i++] = pa_xstrdup(str.toUtf8().constData()); + } + devices[list.size()] = NULL; + +#ifdef HAVE_PULSEAUDIO_DEVICE_MANAGER + pa_operation *o; + if (!(o = pa_ext_device_manager_reorder_devices_for_role(s_context, role.toUtf8().constData(), (const char**)devices, NULL, NULL))) + logMessage(QString("pa_ext_device_manager_reorder_devices_for_role() failed")); + else + pa_operation_unref(o); +#endif + + for (i = 0; i < list.size(); ++i) + pa_xfree(devices[i]); + pa_xfree(devices); +} +#endif + +void PulseSupport::setOutputDevicePriorityForCategory(Category category, QList order) +{ +#ifndef HAVE_PULSEAUDIO + Q_UNUSED(category); + Q_UNUSED(order); +#else + QStringList list; + QList::iterator it; + + for (it = order.begin(); it != order.end(); ++it) { + if (s_outputDevices.contains(*it)) { + list << s_outputDeviceIndexes.key(*it); + } + } + setDevicePriority(category, list); +#endif +} + +void PulseSupport::setCaptureDevicePriorityForCategory(Category category, QList order) +{ +#ifndef HAVE_PULSEAUDIO + Q_UNUSED(category); + Q_UNUSED(order); +#else + QStringList list; + QList::iterator it; + + for (it = order.begin(); it != order.end(); ++it) { + if (s_captureDevices.contains(*it)) { + list << s_captureDeviceIndexes.key(*it); + } + } + setDevicePriority(category, list); +#endif +} + +void PulseSupport::setStreamPropList(Category category, QString streamUuid) +{ +#ifndef HAVE_PULSEAUDIO + Q_UNUSED(category); + Q_UNUSED(streamUuid); +#else + QString role = s_roleCategoryMap.key(category); + if (role.isEmpty()) + return; + + logMessage(QString("Setting role to %1 for streamindex %2").arg(role).arg(streamUuid)); + setenv("PULSE_PROP_media.role", role.toLatin1().constData(), 1); + setenv("PULSE_PROP_phonon.streamid", streamUuid.toLatin1().constData(), 1); +#endif +} + +void PulseSupport::emitObjectDescriptionChanged(ObjectDescriptionType type) +{ + emit objectDescriptionChanged(type); +} + +void PulseSupport::emitUsingDevice(QString streamUuid, int device) +{ + emit usingDevice(streamUuid, device); +} + +bool PulseSupport::setOutputDevice(QString streamUuid, int device) { +#ifndef HAVE_PULSEAUDIO + Q_UNUSED(streamUuid); + Q_UNUSED(device); + return false; +#else + if (s_outputDevices.size() < 2) + return true; + + if (!s_outputDevices.contains(device)) { + logMessage(QString("Attempting to set Output Device for invalid device id %1.").arg(device)); + return false; + } + const QVariant var = s_outputDevices[device].properties["name"]; + logMessage(QString("Attempting to set Output Device to '%1' for Output Stream %2").arg(var.toString()).arg(streamUuid)); + + // Attempt to look up the pulse stream index. + if (s_outputStreamIndexMap.contains(streamUuid) && s_outputStreamIndexMap[streamUuid] != PA_INVALID_INDEX) { + logMessage(QString("... Found in map. Moving now")); + + uint32_t pulse_device_index = s_outputDevices[device].pulseIndex; + uint32_t pulse_stream_index = s_outputStreamIndexMap[streamUuid]; + + logMessage(QString("Moving Pulse Sink Input %1 to '%2' (Pulse Sink %3)").arg(pulse_stream_index).arg(var.toString()).arg(pulse_device_index)); + + /// @todo Find a way to move the stream without saving it... We don't want to pollute the stream restore db. + pa_operation* o; + if (!(o = pa_context_move_sink_input_by_index(s_context, pulse_stream_index, pulse_device_index, NULL, NULL))) { + logMessage(QString("pa_context_move_sink_input_by_index() failed")); + return false; + } + pa_operation_unref(o); + } else { + logMessage(QString("... Not found in map. We will be notified of the device when the stream appears and we can process any moves needed then")); + } + return true; +#endif +} + +bool PulseSupport::setCaptureDevice(QString streamUuid, int device) { +#ifndef HAVE_PULSEAUDIO + Q_UNUSED(streamUuid); + Q_UNUSED(device); + return false; +#else + if (s_captureDevices.size() < 2) + return true; + + if (!s_captureDevices.contains(device)) { + logMessage(QString("Attempting to set Capture Device for invalid device id %1.").arg(device)); + return false; + } + const QVariant var = s_captureDevices[device].properties["name"]; + logMessage(QString("Attempting to set Capture Device to '%1' for Capture Stream %2").arg(var.toString()).arg(streamUuid)); + + // Attempt to look up the pulse stream index. + if (s_captureStreamIndexMap.contains(streamUuid) && s_captureStreamIndexMap[streamUuid] == PA_INVALID_INDEX) { + logMessage(QString("... Found in map. Moving now")); + + uint32_t pulse_device_index = s_captureDevices[device].pulseIndex; + uint32_t pulse_stream_index = s_captureStreamIndexMap[streamUuid]; + + logMessage(QString("Moving Pulse Source Output %1 to '%2' (Pulse Sink %3)").arg(pulse_stream_index).arg(var.toString()).arg(pulse_device_index)); + + /// @todo Find a way to move the stream without saving it... We don't want to pollute the stream restore db. + pa_operation* o; + if (!(o = pa_context_move_source_output_by_index(s_context, pulse_stream_index, pulse_device_index, NULL, NULL))) { + logMessage(QString("pa_context_move_source_output_by_index() failed")); + return false; + } + pa_operation_unref(o); + } else { + logMessage(QString("... Not found in map. We will be notified of the device when the stream appears and we can process any moves needed then")); + } + return true; +#endif +} + +void PulseSupport::clearStreamCache(QString streamUuid) { +#ifndef HAVE_PULSEAUDIO + Q_UNUSED(streamUuid); + return; +#else + logMessage(QString("Clearing stream cache for stream %1").arg(streamUuid)); + s_outputStreamIndexMap.remove(streamUuid); + s_captureStreamIndexMap.remove(streamUuid); +#endif +} + +} // namespace Phonon + +QT_END_NAMESPACE + +#include "moc_pulsesupport.cpp" + +// vim: sw=4 ts=4 diff --git a/src/3rdparty/phonon/phonon/pulsesupport.h b/src/3rdparty/phonon/phonon/pulsesupport.h new file mode 100644 index 0000000..c38bece --- /dev/null +++ b/src/3rdparty/phonon/phonon/pulsesupport.h @@ -0,0 +1,78 @@ +/* This file is part of the KDE project + Copyright (C) 2009 Colin Guthrie + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) version 3, or any + later version accepted by the membership of KDE e.V. (or its + successor approved by the membership of KDE e.V.), Nokia Corporation + (or its successors, if any) and the KDE Free Qt Foundation, which shall + act as a proxy defined in Section 6 of version 3 of the license. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. If not, see . + +*/ + +#ifndef PHONON_PULSESUPPORT_H +#define PHONON_PULSESUPPORT_H + +#include "phonon_export.h" +#include "phononnamespace.h" +#include "objectdescription.h" + +#include +#include + +QT_BEGIN_HEADER +QT_BEGIN_NAMESPACE + +namespace Phonon +{ + class PHONON_EXPORT PulseSupport : public QObject + { + Q_OBJECT + public: + static PulseSupport* getInstance(); + static void shutdown(); + + bool isActive(); + void enable(bool enabled = true); + + QList objectDescriptionIndexes(ObjectDescriptionType type) const; + QHash objectDescriptionProperties(ObjectDescriptionType type, int index) const; + QList objectIndexesByCategory(ObjectDescriptionType type, Category category) const; + + void setOutputDevicePriorityForCategory(Category category, QList order); + void setCaptureDevicePriorityForCategory(Category category, QList order); + + void setStreamPropList(Category category, QString streamUuid); + void emitObjectDescriptionChanged(ObjectDescriptionType); + void emitUsingDevice(QString streamUuid, int device); + + bool setOutputDevice(QString streamUuid, int device); + bool setCaptureDevice(QString streamUuid, int device); + void clearStreamCache(QString streamUuid); + + signals: + void objectDescriptionChanged(ObjectDescriptionType); + void usingDevice(QString streamUuid, int device); + + private: + PulseSupport(); + ~PulseSupport(); + + bool mEnabled; + }; +} // namespace Phonon + +QT_END_NAMESPACE +QT_END_HEADER + +#endif // PHONON_PULSESUPPORT_H diff --git a/src/3rdparty/phonon/phonon/swiftslider.cpp b/src/3rdparty/phonon/phonon/swiftslider.cpp new file mode 100644 index 0000000..1e274aa --- /dev/null +++ b/src/3rdparty/phonon/phonon/swiftslider.cpp @@ -0,0 +1,103 @@ +/* This file is part of the KDE project + Copyright (C) 2006-2008 Ricardo Villalba + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) version 3, or any + later version accepted by the membership of KDE e.V. (or its + successor approved by the membership of KDE e.V.), Nokia Corporation + (or its successors, if any) and the KDE Free Qt Foundation, which shall + act as a proxy defined in Section 6 of version 3 of the license. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. If not, see . + +*/ + +#include "swiftslider_p.h" + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +#if !defined(QT_NO_PHONON_SEEKSLIDER) && !defined(QT_NO_PHONON_VOLUMESLIDER) + +namespace Phonon +{ + +SwiftSlider::SwiftSlider(Qt::Orientation orientation, QWidget * parent) + : QSlider(orientation, parent) +{ +} + +SwiftSlider::~SwiftSlider() +{ +} + +// Function copied from qslider.cpp +inline int SwiftSlider::pick(const QPoint &pt) const +{ + return orientation() == Qt::Horizontal ? pt.x() : pt.y(); +} + +// Function copied from qslider.cpp and modified to make it compile +int SwiftSlider::pixelPosToRangeValue(int pos) const +{ + QStyleOptionSlider opt; + initStyleOption(&opt); + QRect gr = style()->subControlRect(QStyle::CC_Slider, &opt, QStyle::SC_SliderGroove, this); + QRect sr = style()->subControlRect(QStyle::CC_Slider, &opt, QStyle::SC_SliderHandle, this); + int sliderMin, sliderMax, sliderLength; + + if (orientation() == Qt::Horizontal) { + sliderLength = sr.width(); + sliderMin = gr.x(); + sliderMax = gr.right() - sliderLength + 1; + } else { + sliderLength = sr.height(); + sliderMin = gr.y(); + sliderMax = gr.bottom() - sliderLength + 1; + } + return QStyle::sliderValueFromPosition(minimum(), maximum(), pos - sliderMin, + sliderMax - sliderMin, opt.upsideDown); +} + +// Based on code from qslider.cpp +void SwiftSlider::mousePressEvent(QMouseEvent *event) +{ + if (event->button() == Qt::LeftButton) { + QStyleOptionSlider opt; + initStyleOption(&opt); + const QRect sliderRect = style()->subControlRect(QStyle::CC_Slider, &opt, QStyle::SC_SliderHandle, this); + const QPoint center = sliderRect.center() - sliderRect.topLeft(); + // to take half of the slider off for the setSliderPosition call we use the center - topLeft + + if (!sliderRect.contains(event->pos())) { + event->accept(); + + setSliderPosition(pixelPosToRangeValue(pick(event->pos() - center))); + triggerAction(SliderMove); + setRepeatAction(SliderNoAction); + } else { + QSlider::mousePressEvent(event); + } + } else { + QSlider::mousePressEvent(event); + } +} + +} // namespace Phonon + +#endif //QT_NO_PHONON_VOLUMESLIDER && QT_NO_PHONON_VOLUMESLIDER + +QT_END_NAMESPACE + +#include "moc_swiftslider_p.cpp" diff --git a/src/3rdparty/phonon/phonon/swiftslider_p.h b/src/3rdparty/phonon/phonon/swiftslider_p.h new file mode 100644 index 0000000..b063b47 --- /dev/null +++ b/src/3rdparty/phonon/phonon/swiftslider_p.h @@ -0,0 +1,68 @@ +/* This file is part of the KDE project + Copyright (C) 2006-2008 Ricardo Villalba + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) version 3, or any + later version accepted by the membership of KDE e.V. (or its + successor approved by the membership of KDE e.V.), Nokia Corporation + (or its successors, if any) and the KDE Free Qt Foundation, which shall + act as a proxy defined in Section 6 of version 3 of the license. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. If not, see . + +*/ + +#ifndef SWIFTSLIDER_H +#define SWIFTSLIDER_H + +#include + +QT_BEGIN_NAMESPACE + +#if !defined(QT_NO_PHONON_SEEKSLIDER) && !defined(QT_NO_PHONON_VOLUMESLIDER) + +namespace Phonon +{ + +/** \class SwiftSlider swiftslider_p.h phonon/SwiftSlider + * \short Modified QSlider that allows sudden/quick moves instead of stepped moves ("Click'n'Go" QSlider) + * + * This is an internal class used by SeekSlider and VolumeSlider. + * + * Ricardo Villalba, the original author of MySlider.cpp (from the SMPlayer project) + * gave his permission for the inclusion of this code inside Phonon by + * switching MySlider.cpp to the LGPLv2.1+ license. + * See http://smplayer.svn.sourceforge.net/viewvc/smplayer/smplayer/trunk/src/myslider.cpp?revision=2406&view=markup + * + * The original discussion about a "Click'n'Go QSlider": http://lists.trolltech.com/qt-interest/2006-11/msg00363.html + * + * \ingroup PhononWidgets + */ +class SwiftSlider : public QSlider +{ + Q_OBJECT +public: + SwiftSlider(Qt::Orientation orientation, QWidget * parent); + ~SwiftSlider(); + +private: + void mousePressEvent(QMouseEvent *event); + inline int pick(const QPoint &pt) const; + int pixelPosToRangeValue(int pos) const; +}; + +} // namespace Phonon + +#endif //QT_NO_PHONON_VOLUMESLIDER && QT_NO_PHONON_VOLUMESLIDER + +QT_END_NAMESPACE + +#endif //SWIFTSLIDER_H diff --git a/src/3rdparty/phonon/qt7/mediaobject.mm b/src/3rdparty/phonon/qt7/mediaobject.mm index f8d635a..002c337 100644 --- a/src/3rdparty/phonon/qt7/mediaobject.mm +++ b/src/3rdparty/phonon/qt7/mediaobject.mm @@ -88,7 +88,7 @@ bool MediaObject::setState(Phonon::State state) emit stateChanged(m_state, prevState); if (m_state != state){ // End-application did something - // upon receiving the signal. + // upon receiving the signal. return false; } } @@ -122,7 +122,7 @@ void MediaObject::inspectGraph() // Inspect the graph to check wether there are any // effects or outputs connected. This will have // influence on the audio system and video system that ends up beeing used: - int prevVideoOutputCount = m_videoOutputCount; + int prevVideoOutputCount = m_videoOutputCount; m_audioEffectCount = 0; m_audioOutputCount = 0; m_videoEffectCount = 0; @@ -134,7 +134,7 @@ void MediaObject::inspectGraph() if (m_videoOutputCount != prevVideoOutputCount){ MediaNodeEvent e1(MediaNodeEvent::VideoOutputCountChanged, &m_videoOutputCount); notify(&e1); - } + } } void MediaObject::setupAudioSystem() @@ -167,14 +167,14 @@ void MediaObject::setupAudioSystem() if (newAudioSystem == m_audioSystem) return; - + // Enable selected audio system: - m_audioSystem = newAudioSystem; + m_audioSystem = newAudioSystem; switch (newAudioSystem){ case AS_Silent: m_audioGraph->stop(); m_videoPlayer->enableAudio(false); - m_nextVideoPlayer->enableAudio(false); + m_nextVideoPlayer->enableAudio(false); m_audioPlayer->enableAudio(false); m_nextAudioPlayer->enableAudio(false); break; @@ -260,7 +260,7 @@ void MediaObject::setSource(const MediaSource &source) return; if (!m_videoPlayer->canPlayMedia()) SET_ERROR("Cannot play media.", FATAL_ERROR) - + // The state might have changed from LoadingState // as a response to an error state change. So we // need to check it before stopping: @@ -382,7 +382,7 @@ void MediaObject::play() if (!m_videoPlayer->canPlayMedia()) return; if (!setState(Phonon::PlayingState)) - return; + return; if (m_audioSystem == AS_Graph){ m_audioGraph->start(); m_mediaObjectAudioNode->setMute(true); @@ -446,7 +446,7 @@ void MediaObject::seek(qint64 milliseconds) m_videoPlayer->seek(milliseconds); m_audioPlayer->seek(m_videoPlayer->currentTime()); m_mediaObjectAudioNode->setMute(false); - + // Update time and cancel pending swap: if (m_currentTime < m_videoPlayer->duration()) m_waitNextSwap = false; @@ -557,7 +557,7 @@ bool MediaObject::isSeekable() const qint64 MediaObject::currentTime() const { IMPLEMENTED_SILENT; - const_cast(this)->updateCurrentTime(); + const_cast(this)->updateCurrentTime(); return m_currentTime; } -- cgit v0.12 From 7e60531cc1b70c660dd5635b5d105894a49954f2 Mon Sep 17 00:00:00 2001 From: Justin McPherson Date: Fri, 26 Mar 2010 13:43:10 +1000 Subject: Phonon qt7; Compile fixes after merge. --- src/3rdparty/phonon/qt7/audionode.mm | 15 +++++++++------ src/3rdparty/phonon/qt7/backendinfo.mm | 12 ++++++------ src/3rdparty/phonon/qt7/mediaobjectaudionode.mm | 2 ++ src/3rdparty/phonon/qt7/quicktimeaudioplayer.mm | 2 ++ src/3rdparty/phonon/qt7/quicktimemetadata.mm | 2 ++ 5 files changed, 21 insertions(+), 12 deletions(-) diff --git a/src/3rdparty/phonon/qt7/audionode.mm b/src/3rdparty/phonon/qt7/audionode.mm index cb9e82f..77cd627 100644 --- a/src/3rdparty/phonon/qt7/audionode.mm +++ b/src/3rdparty/phonon/qt7/audionode.mm @@ -68,12 +68,15 @@ void AudioNode::createAndConnectAUNodes() << QString(!FindNextComponent(0, &description) ? "ERROR: COMPONENT NOT FOUND!" : "OK!")) OSStatus err = noErr; -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 - if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_5) - err = AUGraphAddNode(m_audioGraph->audioGraphRef(), &description, &m_auNode); - else -#endif - err = AUGraphNewNode(m_audioGraph->audioGraphRef(), &description, 0, 0, &m_auNode); + + // The proper function to call here is AUGraphAddNode() but the type has + // changed between 10.5 and 10.6. it's still OK to call this function, but + // if we want to use the proper thing we need to move over to + // AudioComponentDescription everywhere, which is very similar to the + // ComponentDescription, but a different size. however, + // AudioComponentDescription only exists on 10.6+. More fun than we need to + // deal with at the moment, so we'll take the "deprecated" warning instead. + err = AUGraphNewNode(m_audioGraph->audioGraphRef(), &description, 0, 0, &m_auNode); BACKEND_ASSERT2(err != kAUGraphErr_OutputNodeErr, "A MediaObject can only be connected to one audio output device.", FATAL_ERROR) BACKEND_ASSERT2(err == noErr, "Could not create new AUNode.", FATAL_ERROR) diff --git a/src/3rdparty/phonon/qt7/backendinfo.mm b/src/3rdparty/phonon/qt7/backendinfo.mm index e173f05..d84e014 100644 --- a/src/3rdparty/phonon/qt7/backendinfo.mm +++ b/src/3rdparty/phonon/qt7/backendinfo.mm @@ -15,6 +15,12 @@ along with this library. If not, see . */ +#import +#ifdef QUICKTIME_C_API_AVAILABLE + #include + #undef check // avoid name clash; +#endif + #include "backendinfo.h" #include "backendheader.h" @@ -22,12 +28,6 @@ #include #include -#import - -#ifdef QUICKTIME_C_API_AVAILABLE - #include - #undef check // avoid name clash; -#endif QT_BEGIN_NAMESPACE diff --git a/src/3rdparty/phonon/qt7/mediaobjectaudionode.mm b/src/3rdparty/phonon/qt7/mediaobjectaudionode.mm index 66d6041..39b0d4e 100644 --- a/src/3rdparty/phonon/qt7/mediaobjectaudionode.mm +++ b/src/3rdparty/phonon/qt7/mediaobjectaudionode.mm @@ -15,6 +15,8 @@ along with this library. If not, see . */ +#import + #include "mediaobjectaudionode.h" #include "quicktimeaudioplayer.h" #include "quicktimevideoplayer.h" diff --git a/src/3rdparty/phonon/qt7/quicktimeaudioplayer.mm b/src/3rdparty/phonon/qt7/quicktimeaudioplayer.mm index 61c97cc..aefec02 100644 --- a/src/3rdparty/phonon/qt7/quicktimeaudioplayer.mm +++ b/src/3rdparty/phonon/qt7/quicktimeaudioplayer.mm @@ -15,6 +15,8 @@ along with this library. If not, see . */ +#import + #include "quicktimeaudioplayer.h" #include "quicktimevideoplayer.h" #include "audiograph.h" diff --git a/src/3rdparty/phonon/qt7/quicktimemetadata.mm b/src/3rdparty/phonon/qt7/quicktimemetadata.mm index 851e707..4ae3e2c 100644 --- a/src/3rdparty/phonon/qt7/quicktimemetadata.mm +++ b/src/3rdparty/phonon/qt7/quicktimemetadata.mm @@ -15,6 +15,8 @@ along with this library. If not, see . */ +#import + #include "quicktimemetadata.h" #include "quicktimevideoplayer.h" -- cgit v0.12 From b66a253318de90e69ce864621b7c323d98c18783 Mon Sep 17 00:00:00 2001 From: Justin McPherson Date: Fri, 26 Mar 2010 13:43:32 +1000 Subject: Phonon core; compile fixes after merge. --- src/3rdparty/phonon/phonon/audiodataoutput.cpp | 2 -- src/3rdparty/phonon/phonon/audiooutput.cpp | 1 + 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/3rdparty/phonon/phonon/audiodataoutput.cpp b/src/3rdparty/phonon/phonon/audiodataoutput.cpp index 6c737c2..3a7d3a1 100644 --- a/src/3rdparty/phonon/phonon/audiodataoutput.cpp +++ b/src/3rdparty/phonon/phonon/audiodataoutput.cpp @@ -62,7 +62,5 @@ void AudioDataOutputPrivate::setupBackendObject() } // namespace Phonon -#include "audiodataoutput.moc" - #undef PHONON_CLASSNAME // vim: sw=4 ts=4 tw=80 diff --git a/src/3rdparty/phonon/phonon/audiooutput.cpp b/src/3rdparty/phonon/phonon/audiooutput.cpp index 932a875..e94caad 100644 --- a/src/3rdparty/phonon/phonon/audiooutput.cpp +++ b/src/3rdparty/phonon/phonon/audiooutput.cpp @@ -31,6 +31,7 @@ #include "pulsesupport.h" #include +#include #define PHONON_CLASSNAME AudioOutput #define IFACES2 AudioOutputInterface42 -- cgit v0.12 From d2a394ea9d433070ea0e8817b27debd9cfc8e7cd Mon Sep 17 00:00:00 2001 From: Dmytro Poplavskiy Date: Mon, 29 Mar 2010 10:35:18 +1000 Subject: QuickTime media backend: Render CIImage based video frames directly with OpenGL paint engine. This makes video rendering with QGraphicsVideoItem much faster on 64 bits systems. Reviewed-by: Justin McPherson --- src/multimedia/base/base.pri | 8 +- src/multimedia/base/qpaintervideosurface.cpp | 31 +-- src/multimedia/base/qpaintervideosurface_mac.mm | 274 +++++++++++++++++++++ src/multimedia/base/qpaintervideosurface_mac_p.h | 100 ++++++++ src/multimedia/base/qpaintervideosurface_p.h | 22 +- src/plugins/mediaservices/qt7/qt7.pro | 2 + .../mediaservices/qt7/qt7ciimagevideobuffer.h | 90 +++++++ .../mediaservices/qt7/qt7ciimagevideobuffer.mm | 104 ++++++++ src/plugins/mediaservices/qt7/qt7movierenderer.mm | 13 +- .../mediaservices/qt7/qt7movieviewrenderer.h | 1 + .../mediaservices/qt7/qt7movieviewrenderer.mm | 81 +++--- 11 files changed, 660 insertions(+), 66 deletions(-) create mode 100644 src/multimedia/base/qpaintervideosurface_mac.mm create mode 100644 src/multimedia/base/qpaintervideosurface_mac_p.h create mode 100644 src/plugins/mediaservices/qt7/qt7ciimagevideobuffer.h create mode 100644 src/plugins/mediaservices/qt7/qt7ciimagevideobuffer.mm diff --git a/src/multimedia/base/base.pri b/src/multimedia/base/base.pri index 5aebbf0..49eca49 100644 --- a/src/multimedia/base/base.pri +++ b/src/multimedia/base/base.pri @@ -60,4 +60,10 @@ SOURCES += \ $$PWD/qpaintervideosurface.cpp \ $$PWD/qmediatimerange.cpp - +mac { + HEADERS += $$PWD/qpaintervideosurface_mac_p.h + OBJECTIVE_SOURCES += $$PWD/qpaintervideosurface_mac.mm + + LIBS += -framework AppKit -framework QuartzCore -framework QTKit + +} diff --git a/src/multimedia/base/qpaintervideosurface.cpp b/src/multimedia/base/qpaintervideosurface.cpp index 695dc73..b8028d8f 100644 --- a/src/multimedia/base/qpaintervideosurface.cpp +++ b/src/multimedia/base/qpaintervideosurface.cpp @@ -40,6 +40,7 @@ ****************************************************************************/ #include "qpaintervideosurface_p.h" +#include "qpaintervideosurface_mac_p.h" #include @@ -56,28 +57,6 @@ QT_BEGIN_NAMESPACE -class QVideoSurfacePainter -{ -public: - virtual ~QVideoSurfacePainter(); - - virtual QList supportedPixelFormats( - QAbstractVideoBuffer::HandleType handleType) const = 0; - - virtual bool isFormatSupported( - const QVideoSurfaceFormat &format, QVideoSurfaceFormat *similar) const = 0; - - virtual QAbstractVideoSurface::Error start(const QVideoSurfaceFormat &format) = 0; - virtual void stop() = 0; - - virtual QAbstractVideoSurface::Error setCurrentFrame(const QVideoFrame &frame) = 0; - - virtual QAbstractVideoSurface::Error paint( - const QRectF &target, QPainter *painter, const QRectF &source) = 0; - - virtual void updateColors(int brightness, int contrast, int hue, int saturation) = 0; -}; - QVideoSurfacePainter::~QVideoSurfacePainter() { } @@ -1544,6 +1523,14 @@ void QPainterVideoSurface::createPainter() { Q_ASSERT(!m_painter); +#ifdef Q_WS_MAC + if (m_glContext) + m_glContext->makeCurrent(); + + m_painter = new QVideoSurfaceCoreGraphicsPainter(m_glContext != 0); + return; +#endif + #if !defined(QT_NO_OPENGL) && !defined(QT_OPENGL_ES_1_CL) && !defined(QT_OPENGL_ES_1) switch (m_shaderType) { #ifndef QT_OPENGL_ES diff --git a/src/multimedia/base/qpaintervideosurface_mac.mm b/src/multimedia/base/qpaintervideosurface_mac.mm new file mode 100644 index 0000000..899b98f --- /dev/null +++ b/src/multimedia/base/qpaintervideosurface_mac.mm @@ -0,0 +1,274 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qpaintervideosurface_mac_p.h" + +#include + +#include + +#include +#include +#include + +#include + +#include + + +QT_BEGIN_NAMESPACE + +extern CGContextRef qt_mac_cg_context(const QPaintDevice *pdev); //qpaintdevice_mac.cpp + +QVideoSurfaceCoreGraphicsPainter::QVideoSurfaceCoreGraphicsPainter(bool glSupported) + : ciContext(0) + , m_imageFormat(QImage::Format_Invalid) + , m_scanLineDirection(QVideoSurfaceFormat::TopToBottom) +{ + //qDebug() << "QVideoSurfaceCoreGraphicsPainter, GL supported:" << glSupported; + ciContext = 0; + m_imagePixelFormats + << QVideoFrame::Format_RGB32; + + m_supportedHandles + << QAbstractVideoBuffer::NoHandle + << QAbstractVideoBuffer::CoreImageHandle; + + if (glSupported) + m_supportedHandles << QAbstractVideoBuffer::GLTextureHandle; +} + +QVideoSurfaceCoreGraphicsPainter::~QVideoSurfaceCoreGraphicsPainter() +{ + [(CIContext*)ciContext release]; +} + +QList QVideoSurfaceCoreGraphicsPainter::supportedPixelFormats( + QAbstractVideoBuffer::HandleType handleType) const +{ + return m_supportedHandles.contains(handleType) + ? m_imagePixelFormats + : QList(); +} + +bool QVideoSurfaceCoreGraphicsPainter::isFormatSupported( + const QVideoSurfaceFormat &format, QVideoSurfaceFormat *) const +{ + return m_supportedHandles.contains(format.handleType()) + && m_imagePixelFormats.contains(format.pixelFormat()) + && !format.frameSize().isEmpty(); +} + +QAbstractVideoSurface::Error QVideoSurfaceCoreGraphicsPainter::start(const QVideoSurfaceFormat &format) +{ + m_frame = QVideoFrame(); + m_imageFormat = QVideoFrame::imageFormatFromPixelFormat(format.pixelFormat()); + m_imageSize = format.frameSize(); + m_scanLineDirection = format.scanLineDirection(); + + return m_supportedHandles.contains(format.handleType()) + && m_imageFormat != QImage::Format_Invalid + && !m_imageSize.isEmpty() + ? QAbstractVideoSurface::NoError + : QAbstractVideoSurface::UnsupportedFormatError; +} + +void QVideoSurfaceCoreGraphicsPainter::stop() +{ + m_frame = QVideoFrame(); +} + +QAbstractVideoSurface::Error QVideoSurfaceCoreGraphicsPainter::setCurrentFrame(const QVideoFrame &frame) +{ + m_frame = frame; + + return QAbstractVideoSurface::NoError; +} + +QAbstractVideoSurface::Error QVideoSurfaceCoreGraphicsPainter::paint( + const QRectF &target, QPainter *painter, const QRectF &source) +{ + if (m_frame.handleType() == QAbstractVideoBuffer::CoreImageHandle) { + if (painter->paintEngine()->type() == QPaintEngine::CoreGraphics ) { + + CIImage *img = (CIImage*)(m_frame.handle().value()); + + if (img) { + CGContextRef cgContext = qt_mac_cg_context(painter->device()); + + if (cgContext) { + painter->beginNativePainting(); + + CGRect sRect = CGRectMake(source.x(), source.y(), source.width(), source.height()); + CGRect dRect = CGRectMake(target.x(), target.y(), target.width(), target.height()); + + NSBitmapImageRep *bitmap = [[NSBitmapImageRep alloc] initWithCIImage:img]; + + if (m_scanLineDirection == QVideoSurfaceFormat::TopToBottom) { + CGContextSaveGState( cgContext ); + CGContextTranslateCTM(cgContext, 0, dRect.origin.y + CGRectGetMaxY(dRect)); + CGContextScaleCTM(cgContext, 1, -1); + + CGContextDrawImage(cgContext, dRect, [bitmap CGImage]); + + CGContextRestoreGState(cgContext); + } else { + CGContextDrawImage(cgContext, dRect, [bitmap CGImage]); + } + + [bitmap release]; + + painter->endNativePainting(); + + return QAbstractVideoSurface::NoError; + } + } + } else if (painter->paintEngine()->type() == QPaintEngine::OpenGL2 || + painter->paintEngine()->type() == QPaintEngine::OpenGL) { + CIImage *img = (CIImage*)(m_frame.handle().value()); + + if (img) { + CGLContextObj cglContext = CGLGetCurrentContext(); + + if (cglContext) { + + if (!ciContext) { + CGLContextObj cglContext = CGLGetCurrentContext(); + NSOpenGLPixelFormat *nsglPixelFormat = [NSOpenGLView defaultPixelFormat]; + CGLPixelFormatObj cglPixelFormat = static_cast([nsglPixelFormat CGLPixelFormatObj]); + + ciContext = [CIContext contextWithCGLContext:cglContext + pixelFormat:cglPixelFormat + options:nil]; + + [(CIContext*)ciContext retain]; + } + + CGRect sRect = CGRectMake(source.x(), source.y(), source.width(), source.height()); + CGRect dRect = m_scanLineDirection == QVideoSurfaceFormat::TopToBottom ? + CGRectMake(target.x(), target.y()+target.height(), target.width(), -target.height()) : + CGRectMake(target.x(), target.y(), target.width(), target.height()); + + + painter->beginNativePainting(); + + [(CIContext*)ciContext drawImage:img inRect:dRect fromRect:sRect]; + + painter->endNativePainting(); + + return QAbstractVideoSurface::NoError; + } + } + } + } + + if (m_frame.handleType() == QAbstractVideoBuffer::GLTextureHandle && + (painter->paintEngine()->type() == QPaintEngine::OpenGL2 || + painter->paintEngine()->type() == QPaintEngine::OpenGL)) { + + painter->beginNativePainting(); + GLuint texture = m_frame.handle().toUInt(); + + glDisable(GL_CULL_FACE); + glEnable(GL_TEXTURE_2D); + + glBindTexture(GL_TEXTURE_2D, texture); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + const float txLeft = source.left() / m_frame.width(); + const float txRight = source.right() / m_frame.width(); + const float txTop = m_scanLineDirection == QVideoSurfaceFormat::TopToBottom + ? source.top() / m_frame.height() + : source.bottom() / m_frame.height(); + const float txBottom = m_scanLineDirection == QVideoSurfaceFormat::TopToBottom + ? source.bottom() / m_frame.height() + : source.top() / m_frame.height(); + + glBegin(GL_QUADS); + QRectF rect = target; + glTexCoord2f(txLeft, txBottom); + glVertex2f(rect.topLeft().x(), rect.topLeft().y()); + glTexCoord2f(txRight, txBottom); + glVertex2f(rect.topRight().x() + 1, rect.topRight().y()); + glTexCoord2f(txRight, txTop); + glVertex2f(rect.bottomRight().x() + 1, rect.bottomRight().y() + 1); + glTexCoord2f(txLeft, txTop); + glVertex2f(rect.bottomLeft().x(), rect.bottomLeft().y() + 1); + glEnd(); + painter->endNativePainting(); + + return QAbstractVideoSurface::NoError; + } + + //fallback case, software rendering + if (m_frame.map(QAbstractVideoBuffer::ReadOnly)) { + QImage image( + m_frame.bits(), + m_imageSize.width(), + m_imageSize.height(), + m_frame.bytesPerLine(), + m_imageFormat); + + if (m_scanLineDirection == QVideoSurfaceFormat::BottomToTop) { + const QTransform oldTransform = painter->transform(); + + painter->scale(1, -1); + painter->translate(0, -target.bottom()); + painter->drawImage( + QRectF(target.x(), 0, target.width(), target.height()), image, source); + painter->setTransform(oldTransform); + } else { + painter->drawImage(target, image, source); + } + + m_frame.unmap(); + } else { + painter->fillRect(target, Qt::black); + } + return QAbstractVideoSurface::NoError; +} + +void QVideoSurfaceCoreGraphicsPainter::updateColors(int, int, int, int) +{ +} + +QT_END_NAMESPACE diff --git a/src/multimedia/base/qpaintervideosurface_mac_p.h b/src/multimedia/base/qpaintervideosurface_mac_p.h new file mode 100644 index 0000000..64442ed --- /dev/null +++ b/src/multimedia/base/qpaintervideosurface_mac_p.h @@ -0,0 +1,100 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QPAINTERVIDEOSURFACE_MAC_P_H +#define QPAINTERVIDEOSURFACE_MAC_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qpaintervideosurface_p.h" +#include +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QVideoSurfaceCoreGraphicsPainter : public QVideoSurfacePainter +{ +public: + QVideoSurfaceCoreGraphicsPainter(bool glSupported); + ~QVideoSurfaceCoreGraphicsPainter(); + + QList supportedPixelFormats( + QAbstractVideoBuffer::HandleType handleType) const; + + bool isFormatSupported( + const QVideoSurfaceFormat &format, QVideoSurfaceFormat *similar) const; + + QAbstractVideoSurface::Error start(const QVideoSurfaceFormat &format); + void stop(); + + QAbstractVideoSurface::Error setCurrentFrame(const QVideoFrame &frame); + + QAbstractVideoSurface::Error paint( + const QRectF &target, QPainter *painter, const QRectF &source); + + void updateColors(int brightness, int contrast, int hue, int saturation); + +private: + void* ciContext; + QList m_imagePixelFormats; + QVideoFrame m_frame; + QSize m_imageSize; + QImage::Format m_imageFormat; + QVector m_supportedHandles; + QVideoSurfaceFormat::Direction m_scanLineDirection; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/multimedia/base/qpaintervideosurface_p.h b/src/multimedia/base/qpaintervideosurface_p.h index d4b6740..caba3ba 100644 --- a/src/multimedia/base/qpaintervideosurface_p.h +++ b/src/multimedia/base/qpaintervideosurface_p.h @@ -67,8 +67,28 @@ QT_BEGIN_NAMESPACE class QGLContext; +class QVideoSurfacePainter +{ +public: + virtual ~QVideoSurfacePainter(); + + virtual QList supportedPixelFormats( + QAbstractVideoBuffer::HandleType handleType) const = 0; + + virtual bool isFormatSupported( + const QVideoSurfaceFormat &format, QVideoSurfaceFormat *similar) const = 0; + + virtual QAbstractVideoSurface::Error start(const QVideoSurfaceFormat &format) = 0; + virtual void stop() = 0; + + virtual QAbstractVideoSurface::Error setCurrentFrame(const QVideoFrame &frame) = 0; + + virtual QAbstractVideoSurface::Error paint( + const QRectF &target, QPainter *painter, const QRectF &source) = 0; + + virtual void updateColors(int brightness, int contrast, int hue, int saturation) = 0; +}; -class QVideoSurfacePainter; class Q_MULTIMEDIA_EXPORT QPainterVideoSurface : public QAbstractVideoSurface { Q_OBJECT diff --git a/src/plugins/mediaservices/qt7/qt7.pro b/src/plugins/mediaservices/qt7/qt7.pro index 6624d13..8791d73 100644 --- a/src/plugins/mediaservices/qt7/qt7.pro +++ b/src/plugins/mediaservices/qt7/qt7.pro @@ -25,6 +25,7 @@ HEADERS += \ qt7movieviewrenderer.h \ qt7serviceplugin.h \ qt7movierenderer.h \ + qt7ciimagevideobuffer.h \ qcvdisplaylink.h OBJECTIVE_SOURCES += \ @@ -35,6 +36,7 @@ OBJECTIVE_SOURCES += \ qt7movieviewrenderer.mm \ qt7movierenderer.mm \ qt7videooutputcontrol.mm \ + qt7ciimagevideobuffer.mm \ qcvdisplaylink.mm include(mediaplayer/mediaplayer.pri) diff --git a/src/plugins/mediaservices/qt7/qt7ciimagevideobuffer.h b/src/plugins/mediaservices/qt7/qt7ciimagevideobuffer.h new file mode 100644 index 0000000..669724f --- /dev/null +++ b/src/plugins/mediaservices/qt7/qt7ciimagevideobuffer.h @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT7CIIMAGEVIDEOBUFFER_H +#define QT7CIIMAGEVIDEOBUFFER_H + +#include "qt7backend.h" +#import + +#include +#include + + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QT7CIImageVideoBuffer : public QAbstractVideoBuffer +{ +public: + QT7CIImageVideoBuffer(CIImage *image); + + virtual ~QT7CIImageVideoBuffer(); + + MapMode mapMode() const; + uchar *map(MapMode mode, int *numBytes, int *bytesPerLine); + void unmap(); + QVariant handle() const; + +private: + CIImage *m_image; + NSBitmapImageRep *m_buffer; + MapMode m_mode; +}; + + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/plugins/mediaservices/qt7/qt7ciimagevideobuffer.mm b/src/plugins/mediaservices/qt7/qt7ciimagevideobuffer.mm new file mode 100644 index 0000000..3778b58 --- /dev/null +++ b/src/plugins/mediaservices/qt7/qt7ciimagevideobuffer.mm @@ -0,0 +1,104 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qt7ciimagevideobuffer.h" + +QT7CIImageVideoBuffer::QT7CIImageVideoBuffer(CIImage *image) + : QAbstractVideoBuffer(CoreImageHandle) + , m_image(image) + , m_buffer(0) + , m_mode(NotMapped) +{ + [m_image retain]; +} + +QT7CIImageVideoBuffer::~QT7CIImageVideoBuffer() +{ + [m_image release]; + [m_buffer release]; +} + +QAbstractVideoBuffer::MapMode QT7CIImageVideoBuffer::mapMode() const +{ + return m_mode; +} + +uchar *QT7CIImageVideoBuffer::map(QAbstractVideoBuffer::MapMode mode, int *numBytes, int *bytesPerLine) +{ + if (mode == NotMapped || m_mode != NotMapped || !m_image) + return 0; + + if (!m_buffer) { + //swap R and B channels + CIFilter *colorSwapFilter = [CIFilter filterWithName: @"CIColorMatrix" keysAndValues: + @"inputImage", m_image, + @"inputRVector", [CIVector vectorWithX: 0 Y: 0 Z: 1 W: 0], + @"inputGVector", [CIVector vectorWithX: 0 Y: 1 Z: 0 W: 0], + @"inputBVector", [CIVector vectorWithX: 1 Y: 0 Z: 0 W: 0], + @"inputAVector", [CIVector vectorWithX: 0 Y: 0 Z: 0 W: 1], + @"inputBiasVector", [CIVector vectorWithX: 0 Y: 0 Z: 0 W: 0], + nil]; + CIImage *img = [colorSwapFilter valueForKey: @"outputImage"]; + + m_buffer = [[NSBitmapImageRep alloc] initWithCIImage:img]; + } + + if (numBytes) + *numBytes = [m_buffer bytesPerPlane]; + + if (bytesPerLine) + *bytesPerLine = [m_buffer bytesPerRow]; + + m_mode = mode; + + return [m_buffer bitmapData]; +} + +void QT7CIImageVideoBuffer::unmap() +{ + m_mode = NotMapped; +} + +QVariant QT7CIImageVideoBuffer::handle() const +{ + return QVariant::fromValue(m_image); +} + diff --git a/src/plugins/mediaservices/qt7/qt7movierenderer.mm b/src/plugins/mediaservices/qt7/qt7movierenderer.mm index 1c1f5e4..a6d9d8d 100644 --- a/src/plugins/mediaservices/qt7/qt7movierenderer.mm +++ b/src/plugins/mediaservices/qt7/qt7movierenderer.mm @@ -46,6 +46,7 @@ #include "qt7playercontrol.h" #include "qt7movierenderer.h" #include "qt7playersession.h" +#include "qt7ciimagevideobuffer.h" #include "qcvdisplaylink.h" #include #include @@ -64,7 +65,7 @@ class CVGLTextureVideoBuffer : public QAbstractVideoBuffer { public: CVGLTextureVideoBuffer(CVOpenGLTextureRef buffer) - : QAbstractVideoBuffer(NoHandle) + : QAbstractVideoBuffer(GLTextureHandle) , m_buffer(buffer) , m_mode(NotMapped) { @@ -82,11 +83,6 @@ public: return QVariant(int(id)); } - HandleType handleType() const - { - return GLTextureHandle; - } - MapMode mapMode() const { return m_mode; } uchar *map(MapMode mode, int *numBytes, int *bytesPerLine) @@ -447,15 +443,14 @@ void QT7MovieRenderer::updateVideoFrame(const CVTimeStamp &ts) OSStatus status = QTVisualContextCopyImageForTime(m_visualContext, NULL, &ts, &imageBuffer); if (status == noErr && imageBuffer) { - //qDebug() << "render video frame"; QAbstractVideoBuffer *buffer = 0; if (m_usingGLContext) { - buffer = new CVGLTextureVideoBuffer((CVOpenGLTextureRef)imageBuffer); + buffer = new QT7CIImageVideoBuffer([CIImage imageWithCVImageBuffer:imageBuffer]); CVOpenGLTextureRelease((CVOpenGLTextureRef)imageBuffer); - //qDebug() << "render GL video frame" << buffer->handle(); } else { buffer = new CVPixelBufferVideoBuffer((CVPixelBufferRef)imageBuffer); + //buffer = new QT7CIImageVideoBuffer( [CIImage imageWithCVImageBuffer:imageBuffer] ); CVPixelBufferRelease((CVPixelBufferRef)imageBuffer); } diff --git a/src/plugins/mediaservices/qt7/qt7movieviewrenderer.h b/src/plugins/mediaservices/qt7/qt7movieviewrenderer.h index 336006c..0126360 100644 --- a/src/plugins/mediaservices/qt7/qt7movieviewrenderer.h +++ b/src/plugins/mediaservices/qt7/qt7movieviewrenderer.h @@ -87,6 +87,7 @@ private: QSize m_nativeSize; QAbstractVideoSurface *m_surface; QVideoFrame m_currentFrame; + bool m_pendingRenderEvent; QMutex m_mutex; }; diff --git a/src/plugins/mediaservices/qt7/qt7movieviewrenderer.mm b/src/plugins/mediaservices/qt7/qt7movieviewrenderer.mm index 5047853..5f11479 100644 --- a/src/plugins/mediaservices/qt7/qt7movieviewrenderer.mm +++ b/src/plugins/mediaservices/qt7/qt7movieviewrenderer.mm @@ -46,6 +46,7 @@ #include "qt7playercontrol.h" #include "qt7movieviewrenderer.h" #include "qt7playersession.h" +#include "qt7ciimagevideobuffer.h" #include #include #include @@ -113,6 +114,7 @@ QT_END_NAMESPACE - (HiddenQTMovieView *) initWithRenderer:(QT7MovieViewRenderer *)renderer; - (void) setRenderer:(QT7MovieViewRenderer *)renderer; - (void) setDrawRect:(const QRect &)rect; +- (CIImage *) view:(QTMovieView *)view willDisplayImage:(CIImage *)img; @end @implementation HiddenQTMovieView @@ -163,33 +165,37 @@ QT_END_NAMESPACE // before the image will be drawn. Q_UNUSED(view); if (m_renderer) { - NSBitmapImageRep *bitmap = [[NSBitmapImageRep alloc] initWithCIImage:img]; CGRect bounds = [img extent]; int w = bounds.size.width; int h = bounds.size.height; - // Swap red and blue (same as QImage::rgbSwapped, but without copy) - uchar *data = [bitmap bitmapData]; - //qDebug() << data << w << h; - int bytesPerLine = [bitmap bytesPerRow]; - for (int i=0; i> 16) & 0xff) | (*p & 0xff00ff00); - p++; - } - } + QVideoFrame frame; - QVideoFrame frame( new NSBitmapVideoBuffer(bitmap), QSize(w,h), QVideoFrame::Format_RGB32 ); + QAbstractVideoSurface *surface = m_renderer->surface(); + if (!surface || !surface->isActive()) + return img; - //static int i=0; - //i++; - //QImage img([bitmap bitmapData], w, h, QImage::Format_RGB32); - //img.save(QString("img%1.jpg").arg(i)); - - [bitmap release]; + if (surface->surfaceFormat().handleType() == QAbstractVideoBuffer::CoreImageHandle) { + //surface supports rendering of opengl based CIImage + frame = QVideoFrame(new QT7CIImageVideoBuffer(img), QSize(w,h), QVideoFrame::Format_RGB32 ); + } else { + //Swap R and B colors + CIFilter *colorSwapFilter = [CIFilter filterWithName: @"CIColorMatrix" keysAndValues: + @"inputImage", img, + @"inputRVector", [CIVector vectorWithX: 0 Y: 0 Z: 1 W: 0], + @"inputGVector", [CIVector vectorWithX: 0 Y: 1 Z: 0 W: 0], + @"inputBVector", [CIVector vectorWithX: 1 Y: 0 Z: 0 W: 0], + @"inputAVector", [CIVector vectorWithX: 0 Y: 0 Z: 0 W: 1], + @"inputBiasVector", [CIVector vectorWithX: 0 Y: 0 Z: 0 W: 0], + nil]; + CIImage *img = [colorSwapFilter valueForKey: @"outputImage"]; + NSBitmapImageRep *bitmap =[[NSBitmapImageRep alloc] initWithCIImage:img]; + //requesting the bitmap data is slow, + //but it's better to do it here to avoid blocking the main thread for a long. + [bitmap bitmapData]; + frame = QVideoFrame(new NSBitmapVideoBuffer(bitmap), QSize(w,h), QVideoFrame::Format_RGB32 ); + [bitmap release]; + } if (m_renderer) m_renderer->renderFrame(frame); @@ -230,7 +236,8 @@ QT7MovieViewRenderer::QT7MovieViewRenderer(QObject *parent) :QT7VideoRendererControl(parent), m_movie(0), m_movieView(0), - m_surface(0) + m_surface(0), + m_pendingRenderEvent(false) { } @@ -267,11 +274,15 @@ void QT7MovieViewRenderer::setupVideoOutput() } [movieView setMovie:(QTMovie*)m_movie]; - //[movieView setDrawRect:QRect(QPoint(0,0), m_nativeSize)]; + [movieView setDrawRect:QRect(QPoint(0,0), m_nativeSize)]; } if (m_surface && !m_nativeSize.isEmpty()) { - QVideoSurfaceFormat format(m_nativeSize, QVideoFrame::Format_RGB32); + bool coreImageFrameSupported = !m_surface->supportedPixelFormats(QAbstractVideoBuffer::CoreImageHandle).isEmpty() && + !m_surface->supportedPixelFormats(QAbstractVideoBuffer::GLTextureHandle).isEmpty(); + + QVideoSurfaceFormat format(m_nativeSize, QVideoFrame::Format_RGB32, + coreImageFrameSupported ? QAbstractVideoBuffer::CoreImageHandle : QAbstractVideoBuffer::NoHandle); if (m_surface->isActive() && m_surface->surfaceFormat() != format) { // qDebug() << "Surface format was changed, stop the surface."; @@ -279,10 +290,11 @@ void QT7MovieViewRenderer::setupVideoOutput() } if (!m_surface->isActive()) { -// qDebug() << "Starting the surface with format" << format; - m_surface->start(format); -// if (!m_surface->start(format)) -// qDebug() << "failed to start video surface" << m_surface->error(); + //qDebug() << "Starting the surface with format" << format; + if (!m_surface->start(format)) { + qWarning() << "Failed to start video surface" << m_surface->error(); + qWarning() << "Surface format:" << format; + } } } } @@ -330,18 +342,21 @@ void QT7MovieViewRenderer::setSurface(QAbstractVideoSurface *surface) void QT7MovieViewRenderer::renderFrame(const QVideoFrame &frame) { - { - QMutexLocker locker(&m_mutex); - m_currentFrame = frame; - } - qApp->postEvent(this, new QEvent(QEvent::User), Qt::HighEventPriority); + QMutexLocker locker(&m_mutex); + m_currentFrame = frame; + + if (!m_pendingRenderEvent) + qApp->postEvent(this, new QEvent(QEvent::User), Qt::HighEventPriority); + + m_pendingRenderEvent = true; } bool QT7MovieViewRenderer::event(QEvent *event) { if (event->type() == QEvent::User) { QMutexLocker locker(&m_mutex); + m_pendingRenderEvent = false; if (m_surface->isActive()) m_surface->present(m_currentFrame); } -- cgit v0.12 From 04d3b7ada83042c587a9ba199395b639c5f83623 Mon Sep 17 00:00:00 2001 From: Justin McPherson Date: Mon, 29 Mar 2010 11:08:21 +1000 Subject: Remove references to evr based renderer from .pro. --- src/plugins/phonon/ds9/ds9.pro | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/src/plugins/phonon/ds9/ds9.pro b/src/plugins/phonon/ds9/ds9.pro index 301808e..de7efbe 100644 --- a/src/plugins/phonon/ds9/ds9.pro +++ b/src/plugins/phonon/ds9/ds9.pro @@ -7,7 +7,7 @@ LIBS += -lstrmiids -ldmoguids -luuid -lmsdmo -lole32 -loleaut32 TARGET = phonon_ds9 DEFINES += PHONON_MAKE_QT_ONLY_BACKEND -PHONON_DS9_DIR = $$QT_SOURCE_TREE/src/3rdparty/phonon/ds9 +PHONON_DS9_DI = $$QT_SOURCE_TREE/src/3rdparty/phonon/ds9 # Input HEADERS += \ @@ -51,15 +51,6 @@ SOURCES += \ $$PHONON_DS9_DIR/qaudiocdreader.cpp \ $$PHONON_DS9_DIR/qmeminputpin.cpp -#the EVR renderer (only available on desktop) -!wince*:SOURCES += $$PHONON_DS9_DIR/videorenderer_evr.cpp \ - $$PHONON_DS9_DIR/videorenderer_vmr9.cpp -!wince*:HEADERS += $$PHONON_DS9_DIR/qevr9.h \ - $$PHONON_DS9_DIR/videorenderer_evr.h \ - $$PHONON_DS9_DIR/videorenderer_vmr9.h -wince*:SOURCES += $$PHONON_DS9_DIR/videorenderer_default.cpp -wince*:HEADERS += $$PHONON_DS9_DIR/videorenderer_default.h - target.path = $$[QT_INSTALL_PLUGINS]/phonon_backend INSTALLS += target -- cgit v0.12 From c90402f06dbd84a372209fc643f0e3463c41e48a Mon Sep 17 00:00:00 2001 From: Dmytro Poplavskiy Date: Mon, 29 Mar 2010 13:21:32 +1000 Subject: QuickTime backend: disable video outputs in stopped state. To keep backend behaviour consistent with other platforms. Also dropped QT7VideoOutput::setEnabled(), currentry the video output is disabled with passing null movie, this allows to ensure the movie is not retained more than necessary. Reviewed-by: Justin McPherson --- .../qt7/mediaplayer/qt7playersession.mm | 31 +++++++++++++--------- src/plugins/mediaservices/qt7/qt7movierenderer.h | 1 - src/plugins/mediaservices/qt7/qt7movierenderer.mm | 4 --- .../mediaservices/qt7/qt7movievideowidget.h | 1 - .../mediaservices/qt7/qt7movievideowidget.mm | 4 --- src/plugins/mediaservices/qt7/qt7movieviewoutput.h | 1 - .../mediaservices/qt7/qt7movieviewoutput.mm | 4 --- .../mediaservices/qt7/qt7movieviewrenderer.h | 1 - .../mediaservices/qt7/qt7movieviewrenderer.mm | 4 --- .../mediaservices/qt7/qt7videooutputcontrol.h | 1 - 10 files changed, 19 insertions(+), 33 deletions(-) diff --git a/src/plugins/mediaservices/qt7/mediaplayer/qt7playersession.mm b/src/plugins/mediaservices/qt7/mediaplayer/qt7playersession.mm index d83c0e3..f35a9fa 100644 --- a/src/plugins/mediaservices/qt7/mediaplayer/qt7playersession.mm +++ b/src/plugins/mediaservices/qt7/mediaplayer/qt7playersession.mm @@ -193,17 +193,13 @@ void QT7PlayerSession::setVideoOutput(QT7VideoOutput *output) if (m_videoOutput == output) return; - if (m_videoOutput) { - m_videoOutput->setEnabled(false); + if (m_videoOutput) m_videoOutput->setMovie(0); - } m_videoOutput = output; - if (m_videoOutput) { - m_videoOutput->setEnabled(m_QTMovie != 0); + if (m_videoOutput && m_state != QMediaPlayer::StoppedState) m_videoOutput->setMovie(m_QTMovie); - } } @@ -297,6 +293,9 @@ void QT7PlayerSession::setPosition(qint64 pos) void QT7PlayerSession::play() { + if (m_videoOutput) + m_videoOutput->setMovie(m_QTMovie); + float preferredRate = [[(QTMovie*)m_QTMovie attributeForKey:@"QTMoviePreferredRateAttribute"] floatValue]; [(QTMovie*)m_QTMovie setRate:preferredRate*m_rate]; @@ -306,6 +305,9 @@ void QT7PlayerSession::play() void QT7PlayerSession::pause() { + if (m_videoOutput) + m_videoOutput->setMovie(m_QTMovie); + m_state = QMediaPlayer::PausedState; [(QTMovie*)m_QTMovie setRate:0]; @@ -320,6 +322,9 @@ void QT7PlayerSession::stop() [(QTMovie*)m_QTMovie setRate:0]; setPosition(0); + if (m_videoOutput) + m_videoOutput->setMovie(0); + if (m_state == QMediaPlayer::StoppedState) emit stateChanged(m_state); } @@ -361,10 +366,8 @@ void QT7PlayerSession::setMedia(const QMediaContent &content, QIODevice *stream) if (m_QTMovie) { [(QTMovieObserver*)m_movieObserver setMovie:nil]; - if (m_videoOutput) { - m_videoOutput->setEnabled(false); + if (m_videoOutput) m_videoOutput->setMovie(0); - } [(QTMovie*)m_QTMovie release]; m_QTMovie = 0; @@ -425,10 +428,9 @@ void QT7PlayerSession::setMedia(const QMediaContent &content, QIODevice *stream) } else { [(QTMovieObserver*)m_movieObserver setMovie:(QTMovie*)m_QTMovie]; - if (m_videoOutput) { + if (m_videoOutput && m_state != QMediaPlayer::StoppedState) m_videoOutput->setMovie(m_QTMovie); - m_videoOutput->setEnabled(true); - } + processLoadStateChange(); [(QTMovie*)m_QTMovie setMuted:m_muted]; @@ -457,6 +459,8 @@ bool QT7PlayerSession::isVideoAvailable() const void QT7PlayerSession::processEOS() { m_mediaStatus = QMediaPlayer::EndOfMedia; + if (m_videoOutput) + m_videoOutput->setMovie(0); emit stateChanged(m_state = QMediaPlayer::StoppedState); emit mediaStatusChanged(m_mediaStatus); } @@ -493,6 +497,9 @@ void QT7PlayerSession::processLoadStateChange() if (state == kMovieLoadStateError) { newStatus = QMediaPlayer::InvalidMedia; + if (m_videoOutput) + m_videoOutput->setMovie(0); + emit error(QMediaPlayer::FormatError, tr("Failed to load media")); emit stateChanged(m_state = QMediaPlayer::StoppedState); } diff --git a/src/plugins/mediaservices/qt7/qt7movierenderer.h b/src/plugins/mediaservices/qt7/qt7movierenderer.h index a547329..c2dd177 100644 --- a/src/plugins/mediaservices/qt7/qt7movierenderer.h +++ b/src/plugins/mediaservices/qt7/qt7movierenderer.h @@ -74,7 +74,6 @@ public: QT7MovieRenderer(QObject *parent = 0); virtual ~QT7MovieRenderer(); - void setEnabled(bool); void setMovie(void *movie); void updateNaturalSize(const QSize &newSize); diff --git a/src/plugins/mediaservices/qt7/qt7movierenderer.mm b/src/plugins/mediaservices/qt7/qt7movierenderer.mm index a6d9d8d..95f5d4c 100644 --- a/src/plugins/mediaservices/qt7/qt7movierenderer.mm +++ b/src/plugins/mediaservices/qt7/qt7movierenderer.mm @@ -368,10 +368,6 @@ void QT7MovieRenderer::setupVideoOutput() } -void QT7MovieRenderer::setEnabled(bool) -{ -} - void QT7MovieRenderer::setMovie(void *movie) { // qDebug() << "QT7MovieRenderer::setMovie" << movie; diff --git a/src/plugins/mediaservices/qt7/qt7movievideowidget.h b/src/plugins/mediaservices/qt7/qt7movievideowidget.h index 7908efd..831a18d 100644 --- a/src/plugins/mediaservices/qt7/qt7movievideowidget.h +++ b/src/plugins/mediaservices/qt7/qt7movievideowidget.h @@ -72,7 +72,6 @@ public: QT7MovieVideoWidget(QObject *parent = 0); virtual ~QT7MovieVideoWidget(); - void setEnabled(bool); void setMovie(void *movie); void updateNaturalSize(const QSize &newSize); diff --git a/src/plugins/mediaservices/qt7/qt7movievideowidget.mm b/src/plugins/mediaservices/qt7/qt7movievideowidget.mm index 197c26e..c58d0a0 100644 --- a/src/plugins/mediaservices/qt7/qt7movievideowidget.mm +++ b/src/plugins/mediaservices/qt7/qt7movievideowidget.mm @@ -279,10 +279,6 @@ void QT7MovieVideoWidget::setupVideoOutput() m_displayLink->start(); } -void QT7MovieVideoWidget::setEnabled(bool) -{ -} - void QT7MovieVideoWidget::setMovie(void *movie) { if (m_movie == movie) diff --git a/src/plugins/mediaservices/qt7/qt7movieviewoutput.h b/src/plugins/mediaservices/qt7/qt7movieviewoutput.h index 49049ad..0fee41c 100644 --- a/src/plugins/mediaservices/qt7/qt7movieviewoutput.h +++ b/src/plugins/mediaservices/qt7/qt7movieviewoutput.h @@ -63,7 +63,6 @@ public: QT7MovieViewOutput(QObject *parent = 0); ~QT7MovieViewOutput(); - void setEnabled(bool); void setMovie(void *movie); void updateNaturalSize(const QSize &newSize); diff --git a/src/plugins/mediaservices/qt7/qt7movieviewoutput.mm b/src/plugins/mediaservices/qt7/qt7movieviewoutput.mm index 8e4dd9b..20f1a02 100644 --- a/src/plugins/mediaservices/qt7/qt7movieviewoutput.mm +++ b/src/plugins/mediaservices/qt7/qt7movieviewoutput.mm @@ -194,10 +194,6 @@ void QT7MovieViewOutput::setupVideoOutput() setDisplayRect(m_displayRect); } -void QT7MovieViewOutput::setEnabled(bool) -{ -} - void QT7MovieViewOutput::setMovie(void *movie) { if (m_movie != movie) { diff --git a/src/plugins/mediaservices/qt7/qt7movieviewrenderer.h b/src/plugins/mediaservices/qt7/qt7movieviewrenderer.h index 0126360..0b515ae 100644 --- a/src/plugins/mediaservices/qt7/qt7movieviewrenderer.h +++ b/src/plugins/mediaservices/qt7/qt7movieviewrenderer.h @@ -67,7 +67,6 @@ public: QT7MovieViewRenderer(QObject *parent = 0); ~QT7MovieViewRenderer(); - void setEnabled(bool); void setMovie(void *movie); void updateNaturalSize(const QSize &newSize); diff --git a/src/plugins/mediaservices/qt7/qt7movieviewrenderer.mm b/src/plugins/mediaservices/qt7/qt7movieviewrenderer.mm index 5f11479..33a6970 100644 --- a/src/plugins/mediaservices/qt7/qt7movieviewrenderer.mm +++ b/src/plugins/mediaservices/qt7/qt7movieviewrenderer.mm @@ -299,10 +299,6 @@ void QT7MovieViewRenderer::setupVideoOutput() } } -void QT7MovieViewRenderer::setEnabled(bool) -{ -} - void QT7MovieViewRenderer::setMovie(void *movie) { if (movie == m_movie) diff --git a/src/plugins/mediaservices/qt7/qt7videooutputcontrol.h b/src/plugins/mediaservices/qt7/qt7videooutputcontrol.h index 2c60919..3c74cb8 100644 --- a/src/plugins/mediaservices/qt7/qt7videooutputcontrol.h +++ b/src/plugins/mediaservices/qt7/qt7videooutputcontrol.h @@ -67,7 +67,6 @@ class QT7PlayerService; class QT7VideoOutput { public: virtual ~QT7VideoOutput() {} - virtual void setEnabled(bool enabled) = 0; virtual void setMovie(void *movie) = 0; virtual void updateNaturalSize(const QSize &newSize) = 0; }; -- cgit v0.12 From 6a90b60d5c794470334e961d724b2f26a082cad7 Mon Sep 17 00:00:00 2001 From: Dmytro Poplavskiy Date: Mon, 29 Mar 2010 13:27:15 +1000 Subject: QuickTime media backend: ensure quicktime notification are received in the player session thread. Reviewed-by: Justin McPherson --- src/plugins/mediaservices/qt7/mediaplayer/qt7playersession.mm | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/plugins/mediaservices/qt7/mediaplayer/qt7playersession.mm b/src/plugins/mediaservices/qt7/mediaplayer/qt7playersession.mm index f35a9fa..65c9f7d 100644 --- a/src/plugins/mediaservices/qt7/mediaplayer/qt7playersession.mm +++ b/src/plugins/mediaservices/qt7/mediaplayer/qt7playersession.mm @@ -128,25 +128,25 @@ - (void) processEOS:(NSNotification *)notification { Q_UNUSED(notification); - m_session->processEOS(); + QMetaObject::invokeMethod(m_session, "processEOS", Qt::AutoConnection); } - (void) processLoadStateChange:(NSNotification *)notification { Q_UNUSED(notification); - m_session->processLoadStateChange(); + QMetaObject::invokeMethod(m_session, "processLoadStateChange", Qt::AutoConnection); } - (void) processVolumeChange:(NSNotification *)notification { Q_UNUSED(notification); - m_session->processVolumeChange(); + QMetaObject::invokeMethod(m_session, "processVolumeChange", Qt::AutoConnection); } - (void) processNaturalSizeChange :(NSNotification *)notification { Q_UNUSED(notification); - m_session->processNaturalSizeChange(); + QMetaObject::invokeMethod(m_session, "processNaturalSizeChange", Qt::AutoConnection); } @end -- cgit v0.12 From 131c96bb02fd584af04cd765aec46d9198ebeca8 Mon Sep 17 00:00:00 2001 From: Justin McPherson Date: Mon, 29 Mar 2010 14:21:11 +1000 Subject: Change availabilty of camera related code. Reviewed-by: Dmytro Poplavskiy --- src/plugins/mediaservices/gstreamer/qgstreamerserviceplugin.cpp | 9 ++++++++- .../gstreamer/qgstreamervideoinputdevicecontrol.cpp | 2 ++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/plugins/mediaservices/gstreamer/qgstreamerserviceplugin.cpp b/src/plugins/mediaservices/gstreamer/qgstreamerserviceplugin.cpp index 589d2b5..98068ac 100644 --- a/src/plugins/mediaservices/gstreamer/qgstreamerserviceplugin.cpp +++ b/src/plugins/mediaservices/gstreamer/qgstreamerserviceplugin.cpp @@ -52,9 +52,9 @@ #ifdef QMEDIA_GSTREAMER_CAPTURE #include "qgstreamercaptureservice.h" #endif - #include +#ifdef QMEDIA_GSTREAMER_CAPTURE #include #include #include @@ -66,6 +66,7 @@ #include #include #include +#endif QT_BEGIN_NAMESPACE @@ -109,18 +110,21 @@ void QGstreamerServicePlugin::release(QMediaService *service) QList QGstreamerServicePlugin::devices(const QByteArray &service) const { +#ifdef QMEDIA_GSTREAMER_CAPTURE if (service == Q_MEDIASERVICE_CAMERA) { if (m_cameraDevices.isEmpty()) updateDevices(); return m_cameraDevices; } +#endif return QList(); } QString QGstreamerServicePlugin::deviceDescription(const QByteArray &service, const QByteArray &device) { +#ifdef QMEDIA_GSTREAMER_CAPTURE if (service == Q_MEDIASERVICE_CAMERA) { if (m_cameraDevices.isEmpty()) updateDevices(); @@ -129,12 +133,14 @@ QString QGstreamerServicePlugin::deviceDescription(const QByteArray &service, co if (m_cameraDevices[i] == device) return m_cameraDescriptions[i]; } +#endif return QString(); } void QGstreamerServicePlugin::updateDevices() const { +#ifdef QMEDIA_GSTREAMER_CAPTURE m_cameraDevices.clear(); m_cameraDescriptions.clear(); @@ -178,6 +184,7 @@ void QGstreamerServicePlugin::updateDevices() const } ::close(fd); } +#endif } Q_EXPORT_PLUGIN2(gstengine, QGstreamerServicePlugin); diff --git a/src/plugins/mediaservices/gstreamer/qgstreamervideoinputdevicecontrol.cpp b/src/plugins/mediaservices/gstreamer/qgstreamervideoinputdevicecontrol.cpp index 406cefe11..4ecf10b 100644 --- a/src/plugins/mediaservices/gstreamer/qgstreamervideoinputdevicecontrol.cpp +++ b/src/plugins/mediaservices/gstreamer/qgstreamervideoinputdevicecontrol.cpp @@ -117,6 +117,7 @@ void QGstreamerVideoInputDeviceControl::update() m_names.clear(); m_descriptions.clear(); +#ifdef QMEDIA_GSTREAMER_CAPTURE QDir devDir("/dev"); devDir.setFilter(QDir::System); @@ -157,6 +158,7 @@ void QGstreamerVideoInputDeviceControl::update() } ::close(fd); } +#endif } QT_END_NAMESPACE -- cgit v0.12 From 56c18942a13da36d79707ebc814d486dc0dbbc67 Mon Sep 17 00:00:00 2001 From: Justin McPherson Date: Mon, 29 Mar 2010 14:36:04 +1000 Subject: Fix strange typo? in Phonon/ds9.pro. Reviewed-by: Andrew den Exter --- src/plugins/phonon/ds9/ds9.pro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/phonon/ds9/ds9.pro b/src/plugins/phonon/ds9/ds9.pro index de7efbe..e77c50d 100644 --- a/src/plugins/phonon/ds9/ds9.pro +++ b/src/plugins/phonon/ds9/ds9.pro @@ -7,7 +7,7 @@ LIBS += -lstrmiids -ldmoguids -luuid -lmsdmo -lole32 -loleaut32 TARGET = phonon_ds9 DEFINES += PHONON_MAKE_QT_ONLY_BACKEND -PHONON_DS9_DI = $$QT_SOURCE_TREE/src/3rdparty/phonon/ds9 +PHONON_DS9_DIR = $$QT_SOURCE_TREE/src/3rdparty/phonon/ds9 # Input HEADERS += \ -- cgit v0.12 From 0c2f6d17b3eecf88feb3e7720f9654601d75033a Mon Sep 17 00:00:00 2001 From: Justin McPherson Date: Mon, 29 Mar 2010 16:05:53 +1000 Subject: Update PulseAudio config.test. Originally by Thiago Macieira Reviewed-by: Justin McPherson --- config.tests/unix/pulseaudio/pulseaudio.cpp | 58 +++++++++++++++++++++++++ config.tests/unix/pulseaudio/pulseaudio.pro | 7 ++- config.tests/unix/pulseaudio/pulseaudiotest.cpp | 49 --------------------- configure | 33 ++++++++++---- src/multimedia/effects/effects.pri | 3 +- 5 files changed, 87 insertions(+), 63 deletions(-) create mode 100644 config.tests/unix/pulseaudio/pulseaudio.cpp delete mode 100644 config.tests/unix/pulseaudio/pulseaudiotest.cpp diff --git a/config.tests/unix/pulseaudio/pulseaudio.cpp b/config.tests/unix/pulseaudio/pulseaudio.cpp new file mode 100644 index 0000000..ba5405b --- /dev/null +++ b/config.tests/unix/pulseaudio/pulseaudio.cpp @@ -0,0 +1,58 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the config.tests of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include + +#if !defined(PA_API_VERSION) || PA_API_VERSION-0 != 12 +# error "Incompatible PulseAudio API version" +#endif +#if !PA_CHECK_VERSION(0,9,0) +# error "PulseAudio version too old" +#endif + +int main(int, char **) +{ + const char *headers = pa_get_headers_version(); + const char *library = pa_get_library_version(); + pa_glib_mainloop_new(0); + return (headers - library) * 0; +} diff --git a/config.tests/unix/pulseaudio/pulseaudio.pro b/config.tests/unix/pulseaudio/pulseaudio.pro index 698a35f..d75b16f 100644 --- a/config.tests/unix/pulseaudio/pulseaudio.pro +++ b/config.tests/unix/pulseaudio/pulseaudio.pro @@ -1,4 +1,3 @@ -SOURCES = pulseaudiotest.cpp -LIBS+=-lpulse -CONFIG -= qt dylib -mac:CONFIG -= app_bundle +SOURCES = pulseaudio.cpp +CONFIG -= qt +LIBS += diff --git a/config.tests/unix/pulseaudio/pulseaudiotest.cpp b/config.tests/unix/pulseaudio/pulseaudiotest.cpp deleted file mode 100644 index eed88da..0000000 --- a/config.tests/unix/pulseaudio/pulseaudiotest.cpp +++ /dev/null @@ -1,49 +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 documentation of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -** -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include - -int main(int ,char **) -{ - pa_threaded_mainloop *mainloop = pa_threaded_mainloop_new(); - return 0; -} - diff --git a/configure b/configure index 3c38763..4ffc457 100755 --- a/configure +++ b/configure @@ -5213,6 +5213,29 @@ if [ "$PLATFORM_X11" = "yes" -o "$PLATFORM_QWS" = "yes" ]; then elif [ "$CFG_GLIB" = "no" ]; then CFG_ICD=no fi + + # Auto-detect PulseAudio support + if [ "$CFG_PULSEAUDIO" != "no" ]; then + if [ -n "$PKG_CONFIG" ]; then + QT_CFLAGS_PULSEAUDIO=`$PKG_CONFIG --cflags libpulse '>=' 0.9.10 libpulse-mainloop-glib 2>/dev/null` + QT_LIBS_PULSEAUDIO=`$PKG_CONFIG --libs libpulse '>=' 0.9.10 libpulse-mainloop-glib 2>/dev/null` + fi + if "$unixtests/compile.test" "$XQMAKESPEC" "$QMAKE_CONFIG" $OPT_VERBOSE "$relpath" "$outpath" config.tests/unix/pulseaudio "PulseAudio" $L_FLAGS $I_FLAGS $l_FLAGS $QT_CFLAGS_PULSEAUDIO $QT_LIBS_PULSEAUDIO $X11TESTS_FLAGS; then + CFG_PULSEAUDIO=yes + QMakeVar set QT_CFLAGS_PULSEAUDIO "$QT_CFLAGS_PULSEAUDIO" + QMakeVar set QT_LIBS_PULSEAUDIO "$QT_LIBS_PULSEAUDIO" + else + if [ "$CFG_PULSEAUDIO" = "yes" ] && [ "$CFG_CONFIGURE_EXIT_ON_ERROR" = "yes" ]; then + echo "PulseAudio support cannot be enabled due to functionality tests!" + echo " Turn on verbose messaging (-v) to $0 to see the final report." + echo " If you believe this message is in error you may use the continue" + echo " switch (-continue) to $0 to continue." + exit 101 + else + CFG_PULSEAUDIO=no + fi + fi + fi fi # X11/QWS # x11 @@ -6036,14 +6059,6 @@ if [ "$CFG_ALSA" = "auto" ]; then fi fi -if [ "$CFG_PULSEAUDIO" = "auto" ]; then - if "$unixtests/compile.test" "$XQMAKESPEC" "$QMAKE_CONFIG" $OPT_VERBOSE "$relpath" "$outpath" config.tests/unix/pulseaudio "pulseaudio" $L_FLAGS $I_FLAGS $l_FLAGS; then - CFG_PULSEAUDIO=yes - else - CFG_PULSEAUDIO=no - fi -fi - if [ "$CFG_JAVASCRIPTCORE_JIT" = "yes" ] || [ "$CFG_JAVASCRIPTCORE_JIT" = "auto" ]; then if [ "$CFG_ARCH" = "arm" ] || [ "$CFG_ARCH" = "armv6" ]; then "$unixtests/compile.test" "$XQMAKESPEC" "$QMAKE_CONFIG" $OPT_VERBOSE "$relpath" "$outpath" config.tests/unix/javascriptcore-jit "javascriptcore-jit" $L_FLAGS $I_FLAGS $l_FLAGS @@ -7700,6 +7715,7 @@ echo "CUPS support ........... $CFG_CUPS" echo "Iconv support .......... $CFG_ICONV" echo "Glib support ........... $CFG_GLIB" echo "GStreamer support ...... $CFG_GSTREAMER" +echo "PulseAudio support ..... $CFG_PULSEAUDIO" echo "Large File support ..... $CFG_LARGEFILE" echo "GIF support ............ $CFG_GIF" if [ "$CFG_TIFF" = "no" ]; then @@ -7807,7 +7823,6 @@ elif [ "$CFG_OPENSSL" = "linked" ]; then fi echo "OpenSSL support ........ $CFG_OPENSSL $OPENSSL_LINKAGE" echo "Alsa support ........... $CFG_ALSA" -echo "Pulse Audio support .... $CFG_PULSEAUDIO" if [ "$PLATFORM_MAC" = "yes" ]; then echo "CoreWlan support ....... $CFG_COREWLAN" fi diff --git a/src/multimedia/effects/effects.pri b/src/multimedia/effects/effects.pri index be2b696..6307255 100644 --- a/src/multimedia/effects/effects.pri +++ b/src/multimedia/effects/effects.pri @@ -5,7 +5,8 @@ unix:!mac { DEFINES += QT_MULTIMEDIA_PULSEAUDIO HEADERS += $$PWD/qsoundeffect_pulse_p.h SOURCES += $$PWD/qsoundeffect_pulse_p.cpp - LIBS += -lpulse + QMAKE_CXXFLAGS += $$QT_CFLAGS_PULSEAUDIO + LIBS += $$QT_LIBS_PULSEAUDIO } else { DEFINES += QT_MULTIMEDIA_QMEDIAPLAYER HEADERS += $$PWD/qsoundeffect_qmedia_p.h -- cgit v0.12 From 60039ad6f100c10c4e95a0caeeb46e3038272319 Mon Sep 17 00:00:00 2001 From: Dmytro Poplavskiy Date: Mon, 29 Mar 2010 16:21:03 +1000 Subject: QuickTime video widget: use widget palette for video background color. Reviewed-by: Justin McPherson --- src/plugins/mediaservices/qt7/qt7movievideowidget.mm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/plugins/mediaservices/qt7/qt7movievideowidget.mm b/src/plugins/mediaservices/qt7/qt7movievideowidget.mm index c58d0a0..648d6b4 100644 --- a/src/plugins/mediaservices/qt7/qt7movievideowidget.mm +++ b/src/plugins/mediaservices/qt7/qt7movievideowidget.mm @@ -73,7 +73,8 @@ public: void initializeGL() { - glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + QColor bgColor = palette().color(QPalette::Background); + glClearColor(bgColor.redF(), bgColor.greenF(), bgColor.blueF(), bgColor.alphaF()); } void resizeGL(int w, int h) -- cgit v0.12 From ef4d44f7513bc69a33e3c0328d9f4ed856f6da57 Mon Sep 17 00:00:00 2001 From: Andrew den Exter Date: Mon, 29 Mar 2010 17:13:15 +1000 Subject: Fix compile. Add videorenderer_vmr9.h/cpp back into ds9.pro Reviewed-by: Justin McPherson --- src/plugins/phonon/ds9/ds9.pro | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/plugins/phonon/ds9/ds9.pro b/src/plugins/phonon/ds9/ds9.pro index e77c50d..f40c561 100644 --- a/src/plugins/phonon/ds9/ds9.pro +++ b/src/plugins/phonon/ds9/ds9.pro @@ -22,6 +22,7 @@ HEADERS += \ $$PHONON_DS9_DIR/mediaobject.h \ $$PHONON_DS9_DIR/videowidget.h \ $$PHONON_DS9_DIR/videorenderer_soft.h \ + $$PHONON_DS9_DIR/videorenderer_vmr9.h \ $$PHONON_DS9_DIR/volumeeffect.h \ $$PHONON_DS9_DIR/qbasefilter.h \ $$PHONON_DS9_DIR/qpin.h \ @@ -44,6 +45,7 @@ SOURCES += \ $$PHONON_DS9_DIR/mediaobject.cpp \ $$PHONON_DS9_DIR/videowidget.cpp \ $$PHONON_DS9_DIR/videorenderer_soft.cpp \ + $$PHONON_DS9_DIR/videorenderer_vmr9.cpp \ $$PHONON_DS9_DIR/volumeeffect.cpp \ $$PHONON_DS9_DIR/qbasefilter.cpp \ $$PHONON_DS9_DIR/qpin.cpp \ -- cgit v0.12 From 3546fcbd83b2a255894e6ad9aa673f6feaba6fe7 Mon Sep 17 00:00:00 2001 From: Andrew den Exter Date: Tue, 30 Mar 2010 10:42:43 +1000 Subject: Don't fill the video widget borders or background by default. Can be enabled by settings setAutoFillBackground or the Qt::WA_OpaquePaintEvent to true. Reviewed-by: Dmytro Poplavskiy --- demos/multimedia/player/videowidget.cpp | 6 ++++ src/multimedia/base/qvideowidget.cpp | 33 +++++++++++++++++----- .../mediaplayer/vmr9videowindowcontrol.cpp | 1 + 3 files changed, 33 insertions(+), 7 deletions(-) diff --git a/demos/multimedia/player/videowidget.cpp b/demos/multimedia/player/videowidget.cpp index 3bf36c3..be864ec 100644 --- a/demos/multimedia/player/videowidget.cpp +++ b/demos/multimedia/player/videowidget.cpp @@ -47,6 +47,12 @@ VideoWidget::VideoWidget(QWidget *parent) : QVideoWidget(parent) { setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored); + + QPalette p = palette(); + p.setColor(QPalette::Window, Qt::black); + setPalette(p); + + setAttribute(Qt::WA_OpaquePaintEvent); } void VideoWidget::keyPressEvent(QKeyEvent *event) diff --git a/src/multimedia/base/qvideowidget.cpp b/src/multimedia/base/qvideowidget.cpp index 3820af9..467d7c6 100644 --- a/src/multimedia/base/qvideowidget.cpp +++ b/src/multimedia/base/qvideowidget.cpp @@ -218,13 +218,23 @@ void QRendererVideoWidgetBackend::paintEvent(QPaintEvent *event) { QPainter painter(m_widget); + if (m_widget->testAttribute(Qt::WA_OpaquePaintEvent)) { + QRegion borderRegion = event->region(); + borderRegion = borderRegion.subtracted(m_boundingRect); + + QBrush brush = m_widget->palette().window(); + + QVector rects = borderRegion.rects(); + for (QVector::iterator it = rects.begin(), end = rects.end(); it != end; ++it) { + painter.fillRect(*it, brush); + } + } + if (m_surface->isActive() && m_boundingRect.intersects(event->rect())) { m_surface->paint(&painter, m_boundingRect, m_sourceRect); m_surface->setReady(true); } else { - painter.fillRect(event->rect(), m_widget->palette().background()); - #if !defined(QT_NO_OPENGL) && !defined(QT_OPENGL_ES_1_CL) && !defined(QT_OPENGL_ES_1) if (m_updatePaintDevice && (painter.paintEngine()->type() == QPaintEngine::OpenGL || painter.paintEngine()->type() == QPaintEngine::OpenGL2)) { @@ -239,6 +249,7 @@ void QRendererVideoWidgetBackend::paintEvent(QPaintEvent *event) } #endif } + } void QRendererVideoWidgetBackend::formatChanged(const QVideoSurfaceFormat &format) @@ -364,6 +375,12 @@ void QWindowVideoWidgetBackend::resizeEvent(QResizeEvent *) void QWindowVideoWidgetBackend::paintEvent(QPaintEvent *event) { + if (m_widget->testAttribute(Qt::WA_OpaquePaintEvent)) { + QPainter painter(m_widget); + + painter.fillRect(event->rect(), m_widget->palette().window()); + } + m_windowControl->repaint(); event->accept(); @@ -545,10 +562,6 @@ QVideoWidget::QVideoWidget(QWidget *parent) , d_ptr(new QVideoWidgetPrivate) { d_ptr->q_ptr = this; - - QPalette palette = QWidget::palette(); - palette.setColor(QPalette::Background, Qt::black); - setPalette(palette); } /*! @@ -602,6 +615,7 @@ void QVideoWidget::setMediaObject(QMediaObject *object) QVideoWidgetControl *widgetControl = qobject_cast( d->service->control(QVideoWidgetControl_iid)); + widgetControl = 0; if (widgetControl != 0) { d->widgetBackend = new QVideoWidgetControlBackend(widgetControl, this); } else { @@ -913,8 +927,13 @@ void QVideoWidget::paintEvent(QPaintEvent *event) { Q_D(QVideoWidget); - if (d->currentBackend) + if (d->currentBackend) { d->currentBackend->paintEvent(event); + } else if (testAttribute(Qt::WA_OpaquePaintEvent)) { + QPainter painter(this); + + painter.fillRect(event->rect(), palette().window()); + } } #include "moc_qvideowidget.cpp" diff --git a/src/plugins/mediaservices/directshow/mediaplayer/vmr9videowindowcontrol.cpp b/src/plugins/mediaservices/directshow/mediaplayer/vmr9videowindowcontrol.cpp index e25dd99..1c6df2c 100644 --- a/src/plugins/mediaservices/directshow/mediaplayer/vmr9videowindowcontrol.cpp +++ b/src/plugins/mediaservices/directshow/mediaplayer/vmr9videowindowcontrol.cpp @@ -61,6 +61,7 @@ Vmr9VideoWindowControl::Vmr9VideoWindowControl(QObject *parent) if (IVMRFilterConfig9 *config = com_cast(m_filter, IID_IVMRFilterConfig9)) { config->SetRenderingMode(VMR9Mode_Windowless); config->SetNumberOfStreams(1); + config->SetRenderingPrefs(RenderPrefs9_DoNotRenderBorder); config->Release(); } } -- cgit v0.12 From 003b2755cc307676cb7f84a4a5ef7e23dfd75ce1 Mon Sep 17 00:00:00 2001 From: Andrew den Exter Date: Mon, 29 Mar 2010 15:59:42 +1000 Subject: Force a repaint on changes in the native size of video frames. This ensures old frame data is cleared when swithing to progressively smaller frame sizes. Reviewed-by: Derick Hawcroft --- src/multimedia/base/qvideowidget.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/multimedia/base/qvideowidget.cpp b/src/multimedia/base/qvideowidget.cpp index 467d7c6..486efc0 100644 --- a/src/multimedia/base/qvideowidget.cpp +++ b/src/multimedia/base/qvideowidget.cpp @@ -259,6 +259,7 @@ void QRendererVideoWidgetBackend::formatChanged(const QVideoSurfaceFormat &forma updateRects(); m_widget->updateGeometry(); + m_widget->update(); } void QRendererVideoWidgetBackend::frameChanged() @@ -521,6 +522,7 @@ void QVideoWidgetPrivate::_q_fullScreenChanged(bool fullScreen) void QVideoWidgetPrivate::_q_dimensionsChanged() { q_func()->updateGeometry(); + q_func()->update(); } /*! -- cgit v0.12 From 66a58d87c2d54bd4332ec9a8607222ac5c6521f1 Mon Sep 17 00:00:00 2001 From: Andrew den Exter Date: Tue, 30 Mar 2010 11:08:40 +1000 Subject: Remove debug code disabling the video widget output control. Reviewed-by: Derick Hawcroft --- src/multimedia/base/qvideowidget.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/multimedia/base/qvideowidget.cpp b/src/multimedia/base/qvideowidget.cpp index 486efc0..b791abd 100644 --- a/src/multimedia/base/qvideowidget.cpp +++ b/src/multimedia/base/qvideowidget.cpp @@ -617,7 +617,6 @@ void QVideoWidget::setMediaObject(QMediaObject *object) QVideoWidgetControl *widgetControl = qobject_cast( d->service->control(QVideoWidgetControl_iid)); - widgetControl = 0; if (widgetControl != 0) { d->widgetBackend = new QVideoWidgetControlBackend(widgetControl, this); } else { -- cgit v0.12 From 56aa9370dbafa8ee431dd2ffabef309aae01ec2f Mon Sep 17 00:00:00 2001 From: Martin Jones Date: Tue, 30 Mar 2010 11:11:01 +1000 Subject: Don't emit onPositionChanged before onPressed Task-number: QTBUG-9383 --- src/declarative/graphicsitems/qdeclarativemousearea.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/declarative/graphicsitems/qdeclarativemousearea.cpp b/src/declarative/graphicsitems/qdeclarativemousearea.cpp index 26242bc..dde3366 100644 --- a/src/declarative/graphicsitems/qdeclarativemousearea.cpp +++ b/src/declarative/graphicsitems/qdeclarativemousearea.cpp @@ -639,7 +639,6 @@ bool QDeclarativeMouseArea::setPressed(bool p) d->pressed = p; QDeclarativeMouseEvent me(d->lastPos.x(), d->lastPos.y(), d->lastButton, d->lastButtons, d->lastModifiers, isclick, d->longPress); if (d->pressed) { - emit positionChanged(&me); emit pressed(&me); } else { emit released(&me); -- cgit v0.12 From a1d30018e104bbc17ccebae742f72c0e39e1e7f6 Mon Sep 17 00:00:00 2001 From: Dmytro Poplavskiy Date: Tue, 30 Mar 2010 11:48:41 +1000 Subject: Fixed compilation on 64 bits Mac OS 10.5 Reviewed-by: Justin McPherson --- src/multimedia/base/qpaintervideosurface_mac.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/multimedia/base/qpaintervideosurface_mac.mm b/src/multimedia/base/qpaintervideosurface_mac.mm index 899b98f..ee03990 100644 --- a/src/multimedia/base/qpaintervideosurface_mac.mm +++ b/src/multimedia/base/qpaintervideosurface_mac.mm @@ -52,7 +52,7 @@ #include #include - +#include QT_BEGIN_NAMESPACE -- cgit v0.12 From 8368e041e35ab2a79c79f651a56e6ee53a46549f Mon Sep 17 00:00:00 2001 From: Martin Jones Date: Tue, 30 Mar 2010 12:20:58 +1000 Subject: Fix viewer resizing on reload and File->open Task-number: QTBUG-9325 --- src/declarative/util/qdeclarativeview.cpp | 1 + tools/qml/qmlruntime.cpp | 33 +++++++++++++++---------------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/declarative/util/qdeclarativeview.cpp b/src/declarative/util/qdeclarativeview.cpp index 138fe3c..22a7873 100644 --- a/src/declarative/util/qdeclarativeview.cpp +++ b/src/declarative/util/qdeclarativeview.cpp @@ -157,6 +157,7 @@ void QDeclarativeViewPrivate::execute() { delete root; delete component; + initialSize = QSize(); component = new QDeclarativeComponent(&engine, source, q); if (!component->isLoading()) { diff --git a/tools/qml/qmlruntime.cpp b/tools/qml/qmlruntime.cpp index d4ceb0b..44cab97 100644 --- a/tools/qml/qmlruntime.cpp +++ b/tools/qml/qmlruntime.cpp @@ -995,8 +995,22 @@ void QDeclarativeViewer::statusChanged() if (canvas->status() == QDeclarativeView::Error && tester) tester->executefailure(); - if (canvas->status() == QDeclarativeView::Ready) - resize(sizeHint()); + if (canvas->status() == QDeclarativeView::Ready) { + if (!skin) { + canvas->updateGeometry(); + if (mb) + mb->updateGeometry(); + if (!isFullScreen() && !isMaximized()) + resize(sizeHint()); + } else { + if (scaleSkin) + canvas->resize(canvas->sizeHint()); + else { + canvas->setFixedSize(skin->standardScreenSize()); + canvas->resize(skin->standardScreenSize()); + } + } + } } void QDeclarativeViewer::launch(const QString& file_or_url) @@ -1077,21 +1091,6 @@ void QDeclarativeViewer::openQml(const QString& file_or_url) qWarning() << "Wall startup time:" << t.elapsed(); - if (!skin) { - canvas->updateGeometry(); - if (mb) - mb->updateGeometry(); - if (!isFullScreen() && !isMaximized()) - resize(sizeHint()); - } else { - if (scaleSkin) - canvas->resize(canvas->sizeHint()); - else { - canvas->setFixedSize(skin->standardScreenSize()); - canvas->resize(skin->standardScreenSize()); - } - } - #ifdef QTOPIA show(); #endif -- cgit v0.12 From 68d3e2da7719ff0fc230e8204946b27018e42c14 Mon Sep 17 00:00:00 2001 From: Michael Brasser Date: Tue, 30 Mar 2010 13:28:43 +1000 Subject: Fix parenting after 6f88388db4e8e202780d789e66664ff824691948. --- .../graphicsitems/qdeclarativeflickable.cpp | 3 ++- .../graphicsitems/qdeclarativegridview.cpp | 11 ++++++----- src/declarative/graphicsitems/qdeclarativeitem.cpp | 10 +--------- src/declarative/graphicsitems/qdeclarativeitem.h | 1 - src/declarative/graphicsitems/qdeclarativeitem_p.h | 6 ++++-- .../graphicsitems/qdeclarativelistview.cpp | 22 +++++++++++++--------- .../graphicsitems/qdeclarativeloader.cpp | 8 ++------ .../graphicsitems/qdeclarativepathview.cpp | 5 +++-- 8 files changed, 31 insertions(+), 35 deletions(-) diff --git a/src/declarative/graphicsitems/qdeclarativeflickable.cpp b/src/declarative/graphicsitems/qdeclarativeflickable.cpp index 98502fd..fb22429 100644 --- a/src/declarative/graphicsitems/qdeclarativeflickable.cpp +++ b/src/declarative/graphicsitems/qdeclarativeflickable.cpp @@ -137,7 +137,8 @@ QDeclarativeFlickablePrivate::QDeclarativeFlickablePrivate() void QDeclarativeFlickablePrivate::init() { Q_Q(QDeclarativeFlickable); - viewport->setParent(q); + QDeclarative_setParent_noEvent(viewport, q); + viewport->setParentItem(q); static int timelineUpdatedIdx = -1; static int timelineCompletedIdx = -1; static int flickableTickedIdx = -1; diff --git a/src/declarative/graphicsitems/qdeclarativegridview.cpp b/src/declarative/graphicsitems/qdeclarativegridview.cpp index 17f74db..250832b 100644 --- a/src/declarative/graphicsitems/qdeclarativegridview.cpp +++ b/src/declarative/graphicsitems/qdeclarativegridview.cpp @@ -372,7 +372,7 @@ FxGridItem *QDeclarativeGridViewPrivate::createItem(int modelIndex) listItem->item->setZValue(1); // complete model->completeItem(); - listItem->item->setParent(q->viewport()); + listItem->item->setParentItem(q->viewport()); unrequestedItems.remove(listItem->item); } requestedIndex = -1; @@ -644,7 +644,7 @@ void QDeclarativeGridViewPrivate::createHighlight() QDeclarativeContext *highlightContext = new QDeclarativeContext(qmlContext(q)); QObject *nobj = highlightComponent->create(highlightContext); if (nobj) { - highlightContext->setParent(nobj); + QDeclarative_setParent_noEvent(highlightContext, nobj); item = qobject_cast(nobj); if (!item) delete nobj; @@ -653,10 +653,12 @@ void QDeclarativeGridViewPrivate::createHighlight() } } else { item = new QDeclarativeItem; - item->setParent(q->viewport()); + QDeclarative_setParent_noEvent(item, q->viewport()); + item->setParentItem(q->viewport()); } if (item) { - item->setParent(q->viewport()); + QDeclarative_setParent_noEvent(item, q->viewport()); + item->setParentItem(q->viewport()); highlight = new FxGridItem(item, q); highlightXAnimator = new QDeclarativeEaseFollow(q); highlightXAnimator->setTarget(QDeclarativeProperty(highlight->item, QLatin1String("x"))); @@ -2180,7 +2182,6 @@ void QDeclarativeGridView::modelReset() void QDeclarativeGridView::createdItem(int index, QDeclarativeItem *item) { Q_D(QDeclarativeGridView); - item->setParentItem(this); if (d->requestedIndex != index) { item->setParentItem(this); d->unrequestedItems.insert(item, index); diff --git a/src/declarative/graphicsitems/qdeclarativeitem.cpp b/src/declarative/graphicsitems/qdeclarativeitem.cpp index e8f3652..29490e3 100644 --- a/src/declarative/graphicsitems/qdeclarativeitem.cpp +++ b/src/declarative/graphicsitems/qdeclarativeitem.cpp @@ -1442,14 +1442,6 @@ void QDeclarativeItem::setParentItem(QDeclarativeItem *parent) } /*! - \fn void QDeclarativeItem::setParent(QDeclarativeItem *parent) - \overload - Sets both the parent object and parent item to \a parent. This - function avoids the programming error of calling setParent() - when you mean setParentItem(). -*/ - -/*! Returns the QDeclarativeItem parent of this item. */ QDeclarativeItem *QDeclarativeItem::parentItem() const @@ -1651,7 +1643,7 @@ QRectF QDeclarativeItem::childrenRect() Q_D(QDeclarativeItem); if (!d->_contents) { d->_contents = new QDeclarativeContents; - d->_contents->setParent(this); + QDeclarative_setParent_noEvent(d->_contents, this); d->_contents->setItem(this); } return d->_contents->rectF(); diff --git a/src/declarative/graphicsitems/qdeclarativeitem.h b/src/declarative/graphicsitems/qdeclarativeitem.h index 712e854..917e480 100644 --- a/src/declarative/graphicsitems/qdeclarativeitem.h +++ b/src/declarative/graphicsitems/qdeclarativeitem.h @@ -107,7 +107,6 @@ public: QDeclarativeItem *parentItem() const; void setParentItem(QDeclarativeItem *parent); - void setParent(QDeclarativeItem *parent) { setParentItem(parent); } QDeclarativeListProperty data(); QDeclarativeListProperty resources(); diff --git a/src/declarative/graphicsitems/qdeclarativeitem_p.h b/src/declarative/graphicsitems/qdeclarativeitem_p.h index 10c0c25..2607137 100644 --- a/src/declarative/graphicsitems/qdeclarativeitem_p.h +++ b/src/declarative/graphicsitems/qdeclarativeitem_p.h @@ -63,6 +63,7 @@ #include #include #include +#include #include #include @@ -129,9 +130,10 @@ public: void init(QDeclarativeItem *parent) { Q_Q(QDeclarativeItem); - - if (parent) + if (parent) { + QDeclarative_setParent_noEvent(q, parent); q->setParentItem(parent); + } _baselineOffset.invalidate(); mouseSetsFocus = false; } diff --git a/src/declarative/graphicsitems/qdeclarativelistview.cpp b/src/declarative/graphicsitems/qdeclarativelistview.cpp index 85fcc27..ef8d2fd 100644 --- a/src/declarative/graphicsitems/qdeclarativelistview.cpp +++ b/src/declarative/graphicsitems/qdeclarativelistview.cpp @@ -541,7 +541,7 @@ FxListItem *QDeclarativeListViewPrivate::createItem(int modelIndex) listItem->item->setZValue(1); // complete model->completeItem(); - listItem->item->setParent(q->viewport()); + listItem->item->setParentItem(q->viewport()); QDeclarativeItemPrivate *itemPrivate = static_cast(QGraphicsItemPrivate::get(item)); itemPrivate->addItemChangeListener(this, QDeclarativeItemPrivate::Geometry); if (sectionCriteria && sectionCriteria->delegate()) { @@ -803,7 +803,7 @@ void QDeclarativeListViewPrivate::createHighlight() QDeclarativeContext *highlightContext = new QDeclarativeContext(qmlContext(q)); QObject *nobj = highlightComponent->create(highlightContext); if (nobj) { - highlightContext->setParent(nobj); + QDeclarative_setParent_noEvent(highlightContext, nobj); item = qobject_cast(nobj); if (!item) delete nobj; @@ -814,7 +814,8 @@ void QDeclarativeListViewPrivate::createHighlight() item = new QDeclarativeItem; } if (item) { - item->setParent(q->viewport()); + QDeclarative_setParent_noEvent(item, q->viewport()); + item->setParentItem(q->viewport()); highlight = new FxListItem(item, q); if (currentItem && autoHighlight) { if (orient == QDeclarativeListView::Vertical) { @@ -880,13 +881,14 @@ void QDeclarativeListViewPrivate::createSection(FxListItem *listItem) context->setContextProperty(QLatin1String("section"), listItem->attached->m_section); QObject *nobj = sectionCriteria->delegate()->create(context); if (nobj) { - context->setParent(nobj); + QDeclarative_setParent_noEvent(context, nobj); listItem->section = qobject_cast(nobj); if (!listItem->section) { delete nobj; } else { listItem->section->setZValue(1); - listItem->section->setParent(q->viewport()); + QDeclarative_setParent_noEvent(listItem->section, q->viewport()); + listItem->section->setParentItem(q->viewport()); } } else { delete context; @@ -1002,7 +1004,7 @@ void QDeclarativeListViewPrivate::updateFooter() QDeclarativeContext *context = new QDeclarativeContext(qmlContext(q)); QObject *nobj = footerComponent->create(context); if (nobj) { - context->setParent(nobj); + QDeclarative_setParent_noEvent(context, nobj); item = qobject_cast(nobj); if (!item) delete nobj; @@ -1010,7 +1012,8 @@ void QDeclarativeListViewPrivate::updateFooter() delete context; } if (item) { - item->setParent(q->viewport()); + QDeclarative_setParent_noEvent(item, q->viewport()); + item->setParentItem(q->viewport()); item->setZValue(1); footer = new FxListItem(item, q); } @@ -1039,7 +1042,7 @@ void QDeclarativeListViewPrivate::updateHeader() QDeclarativeContext *context = new QDeclarativeContext(qmlContext(q)); QObject *nobj = headerComponent->create(context); if (nobj) { - context->setParent(nobj); + QDeclarative_setParent_noEvent(context, nobj); item = qobject_cast(nobj); if (!item) delete nobj; @@ -1047,7 +1050,8 @@ void QDeclarativeListViewPrivate::updateHeader() delete context; } if (item) { - item->setParent(q->viewport()); + QDeclarative_setParent_noEvent(item, q->viewport()); + item->setParentItem(q->viewport()); item->setZValue(1); header = new FxListItem(item, q); if (visibleItems.isEmpty()) diff --git a/src/declarative/graphicsitems/qdeclarativeloader.cpp b/src/declarative/graphicsitems/qdeclarativeloader.cpp index 0d62afa..2f1511e 100644 --- a/src/declarative/graphicsitems/qdeclarativeloader.cpp +++ b/src/declarative/graphicsitems/qdeclarativeloader.cpp @@ -301,12 +301,8 @@ void QDeclarativeLoaderPrivate::_q_sourceLoaded() item = qobject_cast(obj); if (item) { QDeclarative_setParent_noEvent(ctxt, obj); - if (QDeclarativeItem* qmlItem = qobject_cast(item)) { - qmlItem->setParentItem(q); - } else { - item->setParentItem(q); - item->setParent(q); - } + QDeclarative_setParent_noEvent(item, q); + item->setParentItem(q); // item->setFocus(true); initResize(); } else { diff --git a/src/declarative/graphicsitems/qdeclarativepathview.cpp b/src/declarative/graphicsitems/qdeclarativepathview.cpp index dd1edd6..3574c9f 100644 --- a/src/declarative/graphicsitems/qdeclarativepathview.cpp +++ b/src/declarative/graphicsitems/qdeclarativepathview.cpp @@ -188,7 +188,7 @@ void QDeclarativePathViewPrivate::createHighlight() QDeclarativeContext *highlightContext = new QDeclarativeContext(qmlContext(q)); QObject *nobj = highlightComponent->create(highlightContext); if (nobj) { - highlightContext->setParent(nobj); + QDeclarative_setParent_noEvent(highlightContext, nobj); item = qobject_cast(nobj); if (!item) delete nobj; @@ -199,7 +199,8 @@ void QDeclarativePathViewPrivate::createHighlight() item = new QDeclarativeItem; } if (item) { - item->setParent(q); + QDeclarative_setParent_noEvent(item, q); + item->setParentItem(q); highlightItem = item; changed = true; } -- cgit v0.12 From 7a060ca401b4e260fd08c854213024b050a67ff2 Mon Sep 17 00:00:00 2001 From: Leonardo Sobral Cunha Date: Fri, 12 Feb 2010 17:19:51 +1000 Subject: Change and rename qml EaseFollow to SmoothedAnimation QDeclarativeSmoothedAnimation inherits from QDeclarativeNumberAnimation, as a consequence SmoothedAnimation can be used inside Behaviors and as PropertySourceValues, like any other animation. The old EaseFollow properties changed to comply with the other declarative animations ('source' changed to 'to'), so now 'to' changes are not automatically 'followed' anymore. You can achieve the following behavior by putting a SmoothedAnimation inside a Behavior of a property that is bound to another, as the following example: If you want to follow an hypothetical rect1, you should do now: Rectangle { color: "green" width: 60; height: 60; x: rect1.x - 5; y: rect1.y - 5; Behavior on x { SmoothedAnimation { velocity: 200 } } Behavior on y { SmoothedAnimation { velocity: 200 } } } SmoothedAnimation also supports animating multiple target(s)/property(ies) in the transition case. When a QDeclarativeSmoothedAnimation is restarted, it will match the QDeclarativeProperty which were being animated and transfer the corresponding track velocity to the new starting animations. QSmoothedAnimation is an uncontrolled animation, duration == -1. The duration is set as -1 to avoid consecutive animation state changes stop()/start(). This is particularly useful when using QSmoothAnimation to 'follow' another property, which is also being animated (change the 'to' property every tick). Reviewed-by: Michael Brasser --- doc/src/declarative/elements.qdoc | 2 +- .../progressbar/content/ProgressBar.qml | 3 +- .../graphicsitems/qdeclarativegridview.cpp | 36 +- .../graphicsitems/qdeclarativelistview.cpp | 36 +- src/declarative/qml/qdeclarativeproperty.h | 5 + src/declarative/util/qdeclarativeanimation.cpp | 19 +- src/declarative/util/qdeclarativeanimation_p.h | 10 +- src/declarative/util/qdeclarativeanimation_p_p.h | 5 +- src/declarative/util/qdeclarativebehavior.cpp | 3 +- src/declarative/util/qdeclarativeeasefollow.cpp | 499 +++++++++------------ src/declarative/util/qdeclarativeeasefollow_p.h | 42 +- src/declarative/util/qdeclarativeeasefollow_p_p.h | 133 ++++++ src/declarative/util/qdeclarativespringfollow.cpp | 2 - src/declarative/util/qdeclarativetransition.cpp | 6 +- src/declarative/util/qdeclarativeutilmodule.cpp | 2 +- src/declarative/util/util.pri | 1 + .../qdeclarativeeasefollow/data/easefollow1.qml | 2 +- .../qdeclarativeeasefollow/data/easefollow2.qml | 4 +- .../qdeclarativeeasefollow/data/easefollow3.qml | 4 +- .../data/easefollowBehavior.qml | 23 + .../data/easefollowValueSource.qml | 13 + .../tst_qdeclarativeeasefollow.cpp | 119 ++++- .../qdeclarativelistview/data/listviewtest.qml | 2 +- .../qdeclarativeeasefollow/easefollow.qml | 15 +- .../qmlvisual/qdeclarativegridview/gridview2.qml | 9 +- 25 files changed, 609 insertions(+), 386 deletions(-) create mode 100644 src/declarative/util/qdeclarativeeasefollow_p_p.h create mode 100644 tests/auto/declarative/qdeclarativeeasefollow/data/easefollowBehavior.qml create mode 100644 tests/auto/declarative/qdeclarativeeasefollow/data/easefollowValueSource.qml diff --git a/doc/src/declarative/elements.qdoc b/doc/src/declarative/elements.qdoc index 8091f95..fcfc7d6 100644 --- a/doc/src/declarative/elements.qdoc +++ b/doc/src/declarative/elements.qdoc @@ -77,11 +77,11 @@ The following table lists the QML elements provided by the Qt Declarative module \o \l PauseAnimation \o \l ParentAnimation \o \l AnchorAnimation +\o \l SmoothedAnimation \o \l PropertyAction \o \l ScriptAction \o \l Transition \o \l SpringFollow -\o \l EaseFollow \o \l Behavior \endlist diff --git a/examples/declarative/progressbar/content/ProgressBar.qml b/examples/declarative/progressbar/content/ProgressBar.qml index 65c80b2..aafb12e 100644 --- a/examples/declarative/progressbar/content/ProgressBar.qml +++ b/examples/declarative/progressbar/content/ProgressBar.qml @@ -21,7 +21,8 @@ Item { id: highlight; radius: 1 anchors.left: parent.left; anchors.top: parent.top; anchors.bottom: parent.bottom anchors.leftMargin: 3; anchors.topMargin: 3; anchors.bottomMargin: 3 - EaseFollow on width { source: highlight.widthDest; velocity: 1200 } + width: highlight.widthDest + Behavior on width { SmoothedAnimation { velocity: 1200 } } gradient: Gradient { GradientStop { id: g1; position: 0.0 } GradientStop { id: g2; position: 1.0 } diff --git a/src/declarative/graphicsitems/qdeclarativegridview.cpp b/src/declarative/graphicsitems/qdeclarativegridview.cpp index 250832b..6d1dec6 100644 --- a/src/declarative/graphicsitems/qdeclarativegridview.cpp +++ b/src/declarative/graphicsitems/qdeclarativegridview.cpp @@ -44,7 +44,7 @@ #include "qdeclarativevisualitemmodel_p.h" #include "qdeclarativeflickable_p_p.h" -#include +#include "qdeclarativeeasefollow_p_p.h" #include #include @@ -324,8 +324,8 @@ public: enum MovementReason { Other, SetIndex, Mouse }; MovementReason moveReason; int buffer; - QDeclarativeEaseFollow *highlightXAnimator; - QDeclarativeEaseFollow *highlightYAnimator; + QSmoothedAnimation *highlightXAnimator; + QSmoothedAnimation *highlightYAnimator; enum BufferMode { NoBuffer = 0x00, BufferBefore = 0x01, BufferAfter = 0x02 }; BufferMode bufferMode; QDeclarativeGridView::SnapMode snapMode; @@ -660,14 +660,14 @@ void QDeclarativeGridViewPrivate::createHighlight() QDeclarative_setParent_noEvent(item, q->viewport()); item->setParentItem(q->viewport()); highlight = new FxGridItem(item, q); - highlightXAnimator = new QDeclarativeEaseFollow(q); - highlightXAnimator->setTarget(QDeclarativeProperty(highlight->item, QLatin1String("x"))); - highlightXAnimator->setDuration(150); - highlightXAnimator->setEnabled(autoHighlight); - highlightYAnimator = new QDeclarativeEaseFollow(q); - highlightYAnimator->setTarget(QDeclarativeProperty(highlight->item, QLatin1String("y"))); - highlightYAnimator->setDuration(150); - highlightYAnimator->setEnabled(autoHighlight); + highlightXAnimator = new QSmoothedAnimation(q); + highlightXAnimator->target = QDeclarativeProperty(highlight->item, QLatin1String("x")); + highlightXAnimator->userDuration = 150; + highlightYAnimator = new QSmoothedAnimation(q); + highlightYAnimator->target = QDeclarativeProperty(highlight->item, QLatin1String("y")); + highlightYAnimator->userDuration = 150; + highlightXAnimator->restart(); + highlightYAnimator->restart(); changed = true; } } @@ -681,10 +681,12 @@ void QDeclarativeGridViewPrivate::updateHighlight() createHighlight(); if (currentItem && autoHighlight && highlight && !moving) { // auto-update highlight - highlightXAnimator->setSourceValue(currentItem->item->x()); - highlightYAnimator->setSourceValue(currentItem->item->y()); + highlightXAnimator->to = currentItem->item->x(); + highlightYAnimator->to = currentItem->item->y(); highlight->item->setWidth(currentItem->item->width()); highlight->item->setHeight(currentItem->item->height()); + highlightXAnimator->restart(); + highlightYAnimator->restart(); } updateTrackedItem(); } @@ -1190,10 +1192,6 @@ void QDeclarativeGridView::setHighlightFollowsCurrentItem(bool autoHighlight) Q_D(QDeclarativeGridView); if (d->autoHighlight != autoHighlight) { d->autoHighlight = autoHighlight; - if (d->highlightXAnimator) { - d->highlightXAnimator->setEnabled(d->autoHighlight); - d->highlightYAnimator->setEnabled(d->autoHighlight); - } d->updateHighlight(); } } @@ -1484,9 +1482,9 @@ void QDeclarativeGridView::viewportMoved() d->updateCurrent(idx); if (d->currentItem && d->currentItem->colPos() != d->highlight->colPos() && d->autoHighlight) { if (d->flow == LeftToRight) - d->highlightXAnimator->setSourceValue(d->currentItem->item->x()); + d->highlightXAnimator->to = d->currentItem->item->x(); else - d->highlightYAnimator->setSourceValue(d->currentItem->item->y()); + d->highlightYAnimator->to = d->currentItem->item->y(); } } } diff --git a/src/declarative/graphicsitems/qdeclarativelistview.cpp b/src/declarative/graphicsitems/qdeclarativelistview.cpp index ef8d2fd..6a4f4b9 100644 --- a/src/declarative/graphicsitems/qdeclarativelistview.cpp +++ b/src/declarative/graphicsitems/qdeclarativelistview.cpp @@ -44,7 +44,7 @@ #include "qdeclarativeflickable_p_p.h" #include "qdeclarativevisualitemmodel_p.h" -#include +#include "qdeclarativeeasefollow_p_p.h" #include #include #include @@ -455,8 +455,8 @@ public: enum MovementReason { Other, SetIndex, Mouse }; MovementReason moveReason; int buffer; - QDeclarativeEaseFollow *highlightPosAnimator; - QDeclarativeEaseFollow *highlightSizeAnimator; + QSmoothedAnimation *highlightPosAnimator; + QSmoothedAnimation *highlightSizeAnimator; QDeclarativeViewSection *sectionCriteria; QString currentSection; static const int sectionCacheSize = 3; @@ -825,15 +825,15 @@ void QDeclarativeListViewPrivate::createHighlight() } } const QLatin1String posProp(orient == QDeclarativeListView::Vertical ? "y" : "x"); - highlightPosAnimator = new QDeclarativeEaseFollow(q); - highlightPosAnimator->setTarget(QDeclarativeProperty(highlight->item, posProp)); - highlightPosAnimator->setVelocity(highlightMoveSpeed); - highlightPosAnimator->setEnabled(autoHighlight); + highlightPosAnimator = new QSmoothedAnimation(q); + highlightPosAnimator->target = QDeclarativeProperty(highlight->item, posProp); + highlightPosAnimator->velocity = highlightMoveSpeed; + highlightPosAnimator->restart(); const QLatin1String sizeProp(orient == QDeclarativeListView::Vertical ? "height" : "width"); - highlightSizeAnimator = new QDeclarativeEaseFollow(q); - highlightSizeAnimator->setVelocity(highlightResizeSpeed); - highlightSizeAnimator->setTarget(QDeclarativeProperty(highlight->item, sizeProp)); - highlightSizeAnimator->setEnabled(autoHighlight); + highlightSizeAnimator = new QSmoothedAnimation(q); + highlightSizeAnimator->velocity = highlightResizeSpeed; + highlightSizeAnimator->target = QDeclarativeProperty(highlight->item, sizeProp); + highlightSizeAnimator->restart(); changed = true; } } @@ -847,8 +847,8 @@ void QDeclarativeListViewPrivate::updateHighlight() createHighlight(); if (currentItem && autoHighlight && highlight && !moving) { // auto-update highlight - highlightPosAnimator->setSourceValue(currentItem->position()); - highlightSizeAnimator->setSourceValue(currentItem->size()); + highlightPosAnimator->to = currentItem->position(); + highlightSizeAnimator->to = currentItem->size(); if (orient == QDeclarativeListView::Vertical) { if (highlight->item->width() == 0) highlight->item->setWidth(currentItem->item->width()); @@ -856,6 +856,8 @@ void QDeclarativeListViewPrivate::updateHighlight() if (highlight->item->height() == 0) highlight->item->setHeight(currentItem->item->height()); } + highlightPosAnimator->restart(); + highlightSizeAnimator->restart(); } updateTrackedItem(); } @@ -1604,10 +1606,6 @@ void QDeclarativeListView::setHighlightFollowsCurrentItem(bool autoHighlight) Q_D(QDeclarativeListView); if (d->autoHighlight != autoHighlight) { d->autoHighlight = autoHighlight; - if (d->highlightPosAnimator) { - d->highlightPosAnimator->setEnabled(d->autoHighlight); - d->highlightSizeAnimator->setEnabled(d->autoHighlight); - } d->updateHighlight(); emit highlightFollowsCurrentItemChanged(); } @@ -1867,7 +1865,7 @@ void QDeclarativeListView::setHighlightMoveSpeed(qreal speed) if (d->highlightMoveSpeed != speed) { d->highlightMoveSpeed = speed; if (d->highlightPosAnimator) - d->highlightPosAnimator->setVelocity(d->highlightMoveSpeed); + d->highlightPosAnimator->velocity = d->highlightMoveSpeed; emit highlightMoveSpeedChanged(); } } @@ -1884,7 +1882,7 @@ void QDeclarativeListView::setHighlightResizeSpeed(qreal speed) if (d->highlightResizeSpeed != speed) { d->highlightResizeSpeed = speed; if (d->highlightSizeAnimator) - d->highlightSizeAnimator->setVelocity(d->highlightResizeSpeed); + d->highlightSizeAnimator->velocity = d->highlightResizeSpeed; emit highlightResizeSpeedChanged(); } } diff --git a/src/declarative/qml/qdeclarativeproperty.h b/src/declarative/qml/qdeclarativeproperty.h index 73bccf3..8f6ea48 100644 --- a/src/declarative/qml/qdeclarativeproperty.h +++ b/src/declarative/qml/qdeclarativeproperty.h @@ -131,6 +131,11 @@ private: }; typedef QList QDeclarativeProperties; +inline uint qHash (const QDeclarativeProperty &key) +{ + return qHash(key.object()) + qHash(key.name()); +} + QT_END_NAMESPACE QT_END_HEADER diff --git a/src/declarative/util/qdeclarativeanimation.cpp b/src/declarative/util/qdeclarativeanimation.cpp index bad142c..ba1444e 100644 --- a/src/declarative/util/qdeclarativeanimation.cpp +++ b/src/declarative/util/qdeclarativeanimation.cpp @@ -1078,15 +1078,26 @@ void QDeclarativePropertyAction::transition(QDeclarativeStateActions &actions, QDeclarativeNumberAnimation::QDeclarativeNumberAnimation(QObject *parent) : QDeclarativePropertyAnimation(parent) { - Q_D(QDeclarativePropertyAnimation); - d->interpolatorType = QMetaType::QReal; - d->interpolator = QVariantAnimationPrivate::getInterpolator(d->interpolatorType); + init(); +} + +QDeclarativeNumberAnimation::QDeclarativeNumberAnimation(QDeclarativePropertyAnimationPrivate &dd, QObject *parent) +: QDeclarativePropertyAnimation(dd, parent) +{ + init(); } QDeclarativeNumberAnimation::~QDeclarativeNumberAnimation() { } +void QDeclarativeNumberAnimation::init() +{ + Q_D(QDeclarativePropertyAnimation); + d->interpolatorType = QMetaType::QReal; + d->interpolator = QVariantAnimationPrivate::getInterpolator(d->interpolatorType); +} + /*! \qmlproperty real NumberAnimation::from This property holds the starting value. @@ -2237,8 +2248,10 @@ void QDeclarativePropertyAnimation::transition(QDeclarativeStateActions &actions } d->va->setAnimValue(data, QAbstractAnimation::DeleteWhenStopped); d->va->setFromSourcedValue(&data->fromSourced); + d->actions = &data->actions; } else { delete data; + d->actions = 0; } } diff --git a/src/declarative/util/qdeclarativeanimation_p.h b/src/declarative/util/qdeclarativeanimation_p.h index 816520e..f620786 100644 --- a/src/declarative/util/qdeclarativeanimation_p.h +++ b/src/declarative/util/qdeclarativeanimation_p.h @@ -251,8 +251,8 @@ public: QDeclarativePropertyAnimation(QObject *parent=0); virtual ~QDeclarativePropertyAnimation(); - int duration() const; - void setDuration(int); + virtual int duration() const; + virtual void setDuration(int); QVariant from() const; void setFrom(const QVariant &); @@ -326,6 +326,12 @@ public: qreal to() const; void setTo(qreal); + +protected: + QDeclarativeNumberAnimation(QDeclarativePropertyAnimationPrivate &dd, QObject *parent); + +private: + void init(); }; class Q_AUTOTEST_EXPORT QDeclarativeVector3dAnimation : public QDeclarativePropertyAnimation diff --git a/src/declarative/util/qdeclarativeanimation_p_p.h b/src/declarative/util/qdeclarativeanimation_p_p.h index 2a66c8a..8bcbeff 100644 --- a/src/declarative/util/qdeclarativeanimation_p_p.h +++ b/src/declarative/util/qdeclarativeanimation_p_p.h @@ -304,7 +304,7 @@ class QDeclarativePropertyAnimationPrivate : public QDeclarativeAbstractAnimatio public: QDeclarativePropertyAnimationPrivate() : QDeclarativeAbstractAnimationPrivate(), target(0), fromSourced(false), fromIsDefined(false), toIsDefined(false), - rangeIsSet(false), defaultToInterpolatorType(0), interpolatorType(0), interpolator(0), va(0) {} + rangeIsSet(false), defaultToInterpolatorType(0), interpolatorType(0), interpolator(0), va(0), actions(0) {} void init(); @@ -330,6 +330,9 @@ public: QDeclarativeBulkValueAnimator *va; + // for animations that dont use the QDeclarativeBulkValueAnimator + QDeclarativeStateActions *actions; + static QVariant interpolateVariant(const QVariant &from, const QVariant &to, qreal progress); static void convertVariant(QVariant &variant, int type); }; diff --git a/src/declarative/util/qdeclarativebehavior.cpp b/src/declarative/util/qdeclarativebehavior.cpp index 7181777..87d6836 100644 --- a/src/declarative/util/qdeclarativebehavior.cpp +++ b/src/declarative/util/qdeclarativebehavior.cpp @@ -163,7 +163,8 @@ void QDeclarativeBehavior::write(const QVariant &value) d->currentValue = d->property.read(); - d->animation->qtAnimation()->stop(); + if (d->animation->qtAnimation()->duration() != -1) + d->animation->qtAnimation()->stop(); QDeclarativeStateOperation::ActionList actions; QDeclarativeAction action; diff --git a/src/declarative/util/qdeclarativeeasefollow.cpp b/src/declarative/util/qdeclarativeeasefollow.cpp index ee181dd..ce2c496 100644 --- a/src/declarative/util/qdeclarativeeasefollow.cpp +++ b/src/declarative/util/qdeclarativeeasefollow.cpp @@ -40,86 +40,79 @@ ****************************************************************************/ #include "qdeclarativeeasefollow_p.h" +#include "qdeclarativeeasefollow_p_p.h" #include "qdeclarativeanimation_p_p.h" #include +#include "qdeclarativeproperty_p.h" + +#include "qdeclarativeglobal_p.h" #include #include +#include + +#define DELAY_STOP_TIMER_INTERVAL 32 QT_BEGIN_NAMESPACE +QSmoothedAnimation::QSmoothedAnimation(QObject *parent) + : QAbstractAnimation(parent), to(0), velocity(200), userDuration(-1), maximumEasingTime(-1), + reversingMode(QDeclarativeSmoothedAnimation::Eased), initialVelocity(0), + trackVelocity(0), initialValue(0), invert(false), finalDuration(-1), lastTime(0) +{ + delayedStopTimer.setInterval(DELAY_STOP_TIMER_INTERVAL); + delayedStopTimer.setSingleShot(true); + connect(&delayedStopTimer, SIGNAL(timeout()), this, SLOT(stop())); +} +void QSmoothedAnimation::restart() +{ + if (state() != QAbstractAnimation::Running) + start(); + else + init(); +} -class QDeclarativeEaseFollowPrivate : public QObjectPrivate +void QSmoothedAnimation::updateState(QAbstractAnimation::State newState, QAbstractAnimation::State /*oldState*/) { - Q_DECLARE_PUBLIC(QDeclarativeEaseFollow) -public: - QDeclarativeEaseFollowPrivate() - : source(0), velocity(200), duration(-1), maximumEasingTime(-1), - reversingMode(QDeclarativeEaseFollow::Eased), initialVelocity(0), - initialValue(0), invert(false), enabled(true), trackVelocity(0), clockOffset(0), - lastTick(0), clock(this) - {} - - qreal source; - qreal velocity; - qreal duration; - qreal maximumEasingTime; - QDeclarativeEaseFollow::ReversingMode reversingMode; - - qreal initialVelocity; - qreal initialValue; - bool invert; - bool enabled; - - qreal trackVelocity; - - QDeclarativeProperty target; - - int clockOffset; - int lastTick; - void tick(int); - void clockStart(); - void clockStop(); - QTickAnimationProxy clock; - - void restart(); - - // Parameters for use in tick() - qreal a; // Acceleration - qreal d; // Deceleration - qreal tf; // Total time - qreal tp; // Time at which peak velocity occurs - qreal td; // Time at which decelleration begins - qreal vp; // Velocity at tp - qreal sp; // Displacement at tp - qreal sd; // Displacement at td - qreal vi; // "Normalized" initialvelocity - bool recalc(); -}; - -bool QDeclarativeEaseFollowPrivate::recalc() + if (newState == QAbstractAnimation::Running) + init(); +} + +void QSmoothedAnimation::delayedStop() { - qreal s = source - initialValue; + if (!delayedStopTimer.isActive()) + delayedStopTimer.start(); +} + +int QSmoothedAnimation::duration() const +{ + return -1; +} + +bool QSmoothedAnimation::recalc() +{ + s = to - initialValue; vi = initialVelocity; - s = (invert?-1.0:1.0) * s; - vi = (invert?-1.0:1.0) * vi; + s = (invert? -1.0: 1.0) * s; - if (duration > 0 && velocity > 0) { + if (userDuration > 0 && velocity > 0) { tf = s / velocity; - if (tf > (duration / 1000.)) tf = (duration / 1000.); - } else if (duration > 0) { - tf = duration / 1000.; + if (tf > (userDuration / 1000.)) tf = (userDuration / 1000.); + } else if (userDuration > 0) { + tf = userDuration / 1000.; } else if (velocity > 0) { tf = s / velocity; } else { return false; } + finalDuration = ceil(tf * 1000.0); + if (maximumEasingTime == 0) { a = 0; d = 0; @@ -129,7 +122,6 @@ bool QDeclarativeEaseFollowPrivate::recalc() sp = 0; sd = s; } else if (maximumEasingTime != -1 && tf > (maximumEasingTime / 1000.)) { - qreal met = maximumEasingTime / 1000.; td = tf - met; @@ -138,7 +130,6 @@ bool QDeclarativeEaseFollowPrivate::recalc() qreal c3 = -0.5 * (tf - td) * vi * vi; qreal vp1 = (-c2 + sqrt(c2 * c2 - 4 * c1 * c3)) / (2. * c1); - // qreal vp2 = (-c2 - sqrt(c2 * c2 - 4 * c1 * c3)) / (2. * c1); vp = vp1; a = vp / met; @@ -147,21 +138,16 @@ bool QDeclarativeEaseFollowPrivate::recalc() sp = vi * tp + 0.5 * a * tp * tp; sd = sp + (td - tp) * vp; } else { - qreal c1 = 0.25 * tf * tf; qreal c2 = 0.5 * vi * tf - s; qreal c3 = -0.25 * vi * vi; qreal a1 = (-c2 + sqrt(c2 * c2 - 4 * c1 * c3)) / (2. * c1); - //qreal a2 = (-c2 - sqrt(c2 * c2 - 4 * c1 * c3)) / (2. * c1); qreal tp1 = 0.5 * tf - 0.5 * vi / a1; - //qreal tp2 = 0.5 * tf - 0.5 * vi / a2; qreal vp1 = a1 * tp1 + vi; - //qreal vp2 = a2 * tp2 + vi; qreal sp1 = 0.5 * a1 * tp1 * tp1 + vi * tp1; - //qreal sp2 = 0.5 * a2 * tp2 * tp2 + vi * tp2; a = a1; d = a1; @@ -171,92 +157,103 @@ bool QDeclarativeEaseFollowPrivate::recalc() sp = sp1; sd = sp1; } - - /* - qWarning() << "a:" << a << "tf:" << tf << "tp:" << tp << "vp:" - << vp << "sp:" << sp << "vi:" << vi << "invert:" << invert; - */ return true; } -void QDeclarativeEaseFollowPrivate::clockStart() +qreal QSmoothedAnimation::easeFollow(qreal time_seconds) { - if (clock.state() == QAbstractAnimation::Running) { - clockOffset = lastTick; - return; + qreal value; + if (time_seconds < tp) { + trackVelocity = vi + time_seconds * a; + value = 0.5 * a * time_seconds * time_seconds + vi * time_seconds; + } else if (time_seconds < td) { + time_seconds -= tp; + trackVelocity = vp; + value = sp + time_seconds * vp; + } else if (time_seconds < tf) { + time_seconds -= td; + trackVelocity = vp - time_seconds * a; + value = sd - 0.5 * d * time_seconds * time_seconds + vp * time_seconds; } else { - clockOffset = 0; - lastTick = 0; - clock.start(); + trackVelocity = 0; + value = s; + delayedStop(); } -} -void QDeclarativeEaseFollowPrivate::clockStop() -{ - clockOffset = 0; - lastTick = 0; - clock.stop(); + // to normalize 's' between [0..1], divide 'value' by 's' + return value; } -void QDeclarativeEaseFollowPrivate::tick(int t) +void QSmoothedAnimation::updateCurrentTime(int t) { - lastTick = t; - t -= clockOffset; - - qreal time_seconds = qreal(t) / 1000.; - - qreal out = 0; - if (time_seconds < tp) { - - trackVelocity = vi + time_seconds * a; - trackVelocity = (invert?-1.0:1.0) * trackVelocity; - - qreal value = 0.5 * a * time_seconds * time_seconds + vi * time_seconds; - value = (invert?-1.0:1.0) * value; - target.write(initialValue + value); - out = initialValue + value; - } else if (time_seconds < td) { + qreal time_seconds = qreal(t - lastTime) / 1000.; - time_seconds -= tp; - trackVelocity = (invert?-1.0:1.0) * vp; - qreal value = sp + time_seconds * vp; - value = (invert?-1.0:1.0) * value; + qreal value = easeFollow(time_seconds); + value *= (invert? -1.0: 1.0); + QDeclarativePropertyPrivate::write(target, initialValue + value, + QDeclarativePropertyPrivate::BypassInterceptor + | QDeclarativePropertyPrivate::DontRemoveBinding); +} - target.write(initialValue + value); +void QSmoothedAnimation::init() +{ + if (velocity == 0) { + stop(); + return; + } - out = initialValue + value; - } else if (time_seconds < tf) { + if (delayedStopTimer.isActive()) + delayedStopTimer.stop(); - time_seconds -= td; + initialValue = target.read().toReal(); + lastTime = this->currentTime(); - trackVelocity = vp - time_seconds * a; - trackVelocity = (invert?-1.0:1.0) * trackVelocity; + if (to == initialValue) { + stop(); + return; + } - qreal value = sd - 0.5 * d * time_seconds * time_seconds + vp * time_seconds; - value = (invert?-1.0:1.0) * value; + bool hasReversed = trackVelocity != 0. && + ((trackVelocity > 0) == ((initialValue - to) > 0)); - target.write(initialValue + value); + if (hasReversed) { + switch (reversingMode) { + default: + case QDeclarativeSmoothedAnimation::Eased: + break; + case QDeclarativeSmoothedAnimation::Sync: + QDeclarativePropertyPrivate::write(target, to, + QDeclarativePropertyPrivate::BypassInterceptor + | QDeclarativePropertyPrivate::DontRemoveBinding); + return; + case QDeclarativeSmoothedAnimation::Immediate: + initialVelocity = 0; + delayedStop(); + break; + } + } - out = initialValue + value; - } else { + trackVelocity = initialVelocity; - clock.stop(); + invert = (to < initialValue); - trackVelocity = 0; - target.write(source); + if (!recalc()) { + QDeclarativePropertyPrivate::write(target, to, + QDeclarativePropertyPrivate::BypassInterceptor + | QDeclarativePropertyPrivate::DontRemoveBinding); + stop(); + return; } - - //qWarning() << out << trackVelocity << t << a; } /*! - \qmlclass EaseFollow QDeclarativeEaseFollow + \qmlclass SmoothedAnimation QDeclarativeSmoothedAnimation \since 4.7 - \brief The EaseFollow element allows a property to smoothly track a value. + \brief The SmoothedAnimation element allows a property to smoothly track a value. - The EaseFollow smoothly animates a property's value to a set target value - using an ease in/out quad easing curve. If the target value changes while - the animation is in progress, the easing curves used to animate to the old + The SmoothedAnimation smoothly animates a property's value to a set target value + using an ease in/out quad easing curve. If the animation is restarted + with a different target value, the easing curves used to animate to the old and the new target values are spliced together to avoid any obvious visual glitches. @@ -282,9 +279,9 @@ Rectangle { Rectangle { color: "green" width: 60; height: 60; - x: -5; y: -5; - EaseFollow on x { source: rect1.x - 5; velocity: 200 } - EaseFollow on y { source: rect1.y - 5; velocity: 200 } + x: rect1.x - 5; y: rect1.y - 5; + Behavior on x { SmoothedAnimation { velocity: 200 } } + Behavior on y { SmoothedAnimation { velocity: 200 } } } Rectangle { @@ -301,7 +298,7 @@ Rectangle { } \endcode - The default velocity of EaseFollow is 200 units/second. Note that if the range of the + The default velocity of SmoothedAnimation is 200 units/second. Note that if the range of the value being animated is small, then the velocity will need to be adjusted appropriately. For example, the opacity of an item ranges from 0 - 1.0. To enable a smooth animation in this range the velocity will need to be @@ -311,226 +308,176 @@ Rectangle { \sa SpringFollow */ -QDeclarativeEaseFollow::QDeclarativeEaseFollow(QObject *parent) -: QObject(*(new QDeclarativeEaseFollowPrivate), parent) +QDeclarativeSmoothedAnimation::QDeclarativeSmoothedAnimation(QObject *parent) +: QDeclarativeNumberAnimation(*(new QDeclarativeSmoothedAnimationPrivate), parent) { } -QDeclarativeEaseFollow::~QDeclarativeEaseFollow() +QDeclarativeSmoothedAnimation::~QDeclarativeSmoothedAnimation() { } -/*! - \qmlproperty qreal EaseFollow::source - This property holds the source value which will be tracked. - - Bind to a property in order to track its changes. -*/ -qreal QDeclarativeEaseFollow::sourceValue() const +QDeclarativeSmoothedAnimationPrivate::QDeclarativeSmoothedAnimationPrivate() + : wrapperGroup(new QParallelAnimationGroup), anim(new QSmoothedAnimation) { - Q_D(const QDeclarativeEaseFollow); - return d->source; + Q_Q(QDeclarativeSmoothedAnimation); + QDeclarative_setParent_noEvent(wrapperGroup, q); + QDeclarative_setParent_noEvent(anim, q); } -/*! - \qmlproperty enumeration EaseFollow::reversingMode - - Sets how the EaseFollow behaves if an animation direction is reversed. - - If reversing mode is \c Eased, the animation will smoothly decelerate, and - then reverse direction. If the reversing mode is \c Immediate, the - animation will immediately begin accelerating in the reverse direction, - begining with a velocity of 0. If the reversing mode is \c Sync, the - property is immediately set to the target value. -*/ -QDeclarativeEaseFollow::ReversingMode QDeclarativeEaseFollow::reversingMode() const +QAbstractAnimation* QDeclarativeSmoothedAnimation::qtAnimation() { - Q_D(const QDeclarativeEaseFollow); - return d->reversingMode; + Q_D(QDeclarativeSmoothedAnimation); + return d->wrapperGroup; } -void QDeclarativeEaseFollow::setReversingMode(ReversingMode m) +void QDeclarativeSmoothedAnimation::transition(QDeclarativeStateActions &actions, + QDeclarativeProperties &modified, + TransitionDirection direction) { - Q_D(QDeclarativeEaseFollow); - if (d->reversingMode == m) + Q_D(QDeclarativeSmoothedAnimation); + QDeclarativeNumberAnimation::transition(actions, modified, direction); + + if (!d->actions) return; - d->reversingMode = m; - emit reversingModeChanged(); -} + QSet anims; + for (int i = 0; i < d->actions->size(); i++) { + QSmoothedAnimation *ease; + qreal trackVelocity; + bool needsRestart; + if (!d->activeAnimations.contains((*d->actions)[i].property)) { + ease = new QSmoothedAnimation(); + d->wrapperGroup->addAnimation(ease); + d->activeAnimations.insert((*d->actions)[i].property, ease); + trackVelocity = 0.0; + needsRestart = false; + } else { + ease = d->activeAnimations.value((*d->actions)[i].property); + trackVelocity = ease->trackVelocity; + needsRestart = true; + } -void QDeclarativeEaseFollowPrivate::restart() -{ - if (!enabled || velocity == 0) { - clockStop(); - return; - } + ease->target = (*d->actions)[i].property; + ease->to = (*d->actions)[i].toValue.toReal(); - initialValue = target.read().toReal(); + // copying public members from main value holder animation + ease->maximumEasingTime = d->anim->maximumEasingTime; + ease->reversingMode = d->anim->reversingMode; + ease->velocity = d->anim->velocity; + ease->userDuration = d->anim->userDuration; - if (source == initialValue) { - clockStop(); - return; - } + ease->trackVelocity = trackVelocity; + ease->initialVelocity = trackVelocity; - bool hasReversed = trackVelocity != 0. && - ((trackVelocity > 0) == ((initialValue - source) > 0)); + if (needsRestart) + ease->init(); + anims.insert(ease); + } - if (hasReversed) { - switch (reversingMode) { - default: - case QDeclarativeEaseFollow::Eased: - break; - case QDeclarativeEaseFollow::Sync: - target.write(source); - return; - case QDeclarativeEaseFollow::Immediate: - initialVelocity = 0; - clockStop(); - break; + for (int i = d->wrapperGroup->animationCount() - 1; i >= 0 ; --i) { + if (!anims.contains(d->wrapperGroup->animationAt(i))) { + QSmoothedAnimation *ease = static_cast(d->wrapperGroup->animationAt(i)); + d->activeAnimations.remove(ease->target); + d->wrapperGroup->takeAnimation(i); + delete ease; } } +} - trackVelocity = initialVelocity; - - invert = (source < initialValue); +/*! + \qmlproperty enumeration SmoothedAnimation::reversingMode - if (!recalc()) { - target.write(source); - clockStop(); - return; - } + Sets how the SmoothedAnimation behaves if an animation direction is reversed. - clockStart(); + If reversing mode is \c Eased, the animation will smoothly decelerate, and + then reverse direction. If the reversing mode is \c Immediate, the + animation will immediately begin accelerating in the reverse direction, + begining with a velocity of 0. If the reversing mode is \c Sync, the + property is immediately set to the target value. +*/ +QDeclarativeSmoothedAnimation::ReversingMode QDeclarativeSmoothedAnimation::reversingMode() const +{ + Q_D(const QDeclarativeSmoothedAnimation); + return (QDeclarativeSmoothedAnimation::ReversingMode) d->anim->reversingMode; } -void QDeclarativeEaseFollow::setSourceValue(qreal s) +void QDeclarativeSmoothedAnimation::setReversingMode(ReversingMode m) { - Q_D(QDeclarativeEaseFollow); - - if (d->clock.state() == QAbstractAnimation::Running && d->source == s) + Q_D(QDeclarativeSmoothedAnimation); + if (d->anim->reversingMode == m) return; - d->source = s; - d->initialVelocity = d->trackVelocity; - d->restart(); - - emit sourceChanged(); + d->anim->reversingMode = m; + emit reversingModeChanged(); } /*! - \qmlproperty qreal EaseFollow::duration + \qmlproperty int SmoothedAnimation::duration - This property holds the animation duration used when tracking the source. + This property holds the animation duration, in msecs, used when tracking the source. Setting this to -1 (the default) disables the duration value. */ -qreal QDeclarativeEaseFollow::duration() const +int QDeclarativeSmoothedAnimation::duration() const { - Q_D(const QDeclarativeEaseFollow); - return d->duration; + Q_D(const QDeclarativeSmoothedAnimation); + return d->anim->userDuration; } -void QDeclarativeEaseFollow::setDuration(qreal v) +void QDeclarativeSmoothedAnimation::setDuration(int duration) { - Q_D(QDeclarativeEaseFollow); - if (d->duration == v) - return; - - d->duration = v; - d->trackVelocity = 0; - - if (d->clock.state() == QAbstractAnimation::Running) - d->restart(); - - emit durationChanged(); + Q_D(QDeclarativeSmoothedAnimation); + if (duration != -1) + QDeclarativeNumberAnimation::setDuration(duration); + d->anim->userDuration = duration; } -qreal QDeclarativeEaseFollow::velocity() const +qreal QDeclarativeSmoothedAnimation::velocity() const { - Q_D(const QDeclarativeEaseFollow); - return d->velocity; + Q_D(const QDeclarativeSmoothedAnimation); + return d->anim->velocity; } /*! - \qmlproperty qreal EaseFollow::velocity + \qmlproperty qreal SmoothedAnimation::velocity - This property holds the average velocity allowed when tracking the source. + This property holds the average velocity allowed when tracking the 'to' value. - The default velocity of EaseFollow is 200 units/second. + The default velocity of SmoothedAnimation is 200 units/second. Setting this to -1 disables the velocity value. */ -void QDeclarativeEaseFollow::setVelocity(qreal v) +void QDeclarativeSmoothedAnimation::setVelocity(qreal v) { - Q_D(QDeclarativeEaseFollow); - if (d->velocity == v) + Q_D(QDeclarativeSmoothedAnimation); + if (d->anim->velocity == v) return; - d->velocity = v; - d->trackVelocity = 0; - - if (d->clock.state() == QAbstractAnimation::Running) - d->restart(); - + d->anim->velocity = v; emit velocityChanged(); } /*! - \qmlproperty bool EaseFollow::enabled - This property holds whether the target will track the source. -*/ -bool QDeclarativeEaseFollow::enabled() const -{ - Q_D(const QDeclarativeEaseFollow); - return d->enabled; -} - -void QDeclarativeEaseFollow::setEnabled(bool enabled) -{ - Q_D(QDeclarativeEaseFollow); - if (d->enabled == enabled) - return; - - d->enabled = enabled; - if (enabled) - d->restart(); - else - d->clockStop(); - - emit enabledChanged(); -} - -void QDeclarativeEaseFollow::setTarget(const QDeclarativeProperty &t) -{ - Q_D(QDeclarativeEaseFollow); - d->target = t; -} +\qmlproperty qreal SmoothedAnimation::maximumEasingTime -/*! -\qmlproperty qreal EaseFollow::maximumEasingTime - -This property specifies the maximum time an "eases" during the follow should take. +This property specifies the maximum time, in msecs, an "eases" during the follow should take. Setting this property causes the velocity to "level out" after at a time. Setting a negative value reverts to the normal mode of easing over the entire animation duration. The default value is -1. */ -qreal QDeclarativeEaseFollow::maximumEasingTime() const +int QDeclarativeSmoothedAnimation::maximumEasingTime() const { - Q_D(const QDeclarativeEaseFollow); - return d->maximumEasingTime; + Q_D(const QDeclarativeSmoothedAnimation); + return d->anim->maximumEasingTime; } -void QDeclarativeEaseFollow::setMaximumEasingTime(qreal v) +void QDeclarativeSmoothedAnimation::setMaximumEasingTime(int v) { - Q_D(QDeclarativeEaseFollow); - d->maximumEasingTime = v; - - if (d->clock.state() == QAbstractAnimation::Running) - d->restart(); - + Q_D(QDeclarativeSmoothedAnimation); + d->anim->maximumEasingTime = v; emit maximumEasingTimeChanged(); } diff --git a/src/declarative/util/qdeclarativeeasefollow_p.h b/src/declarative/util/qdeclarativeeasefollow_p.h index 83d1eff..6c17d4f 100644 --- a/src/declarative/util/qdeclarativeeasefollow_p.h +++ b/src/declarative/util/qdeclarativeeasefollow_p.h @@ -43,7 +43,7 @@ #define QDECLARATIVEEASEFOLLOW_H #include -#include +#include "qdeclarativeanimation_p.h" #include @@ -54,60 +54,50 @@ QT_BEGIN_NAMESPACE QT_MODULE(Declarative) class QDeclarativeProperty; -class QDeclarativeEaseFollowPrivate; -class Q_DECLARATIVE_EXPORT QDeclarativeEaseFollow : public QObject, - public QDeclarativePropertyValueSource +class QDeclarativeSmoothedAnimationPrivate; +class Q_DECLARATIVE_EXPORT QDeclarativeSmoothedAnimation : public QDeclarativeNumberAnimation { Q_OBJECT - Q_DECLARE_PRIVATE(QDeclarativeEaseFollow) - Q_INTERFACES(QDeclarativePropertyValueSource) + Q_DECLARE_PRIVATE(QDeclarativeSmoothedAnimation) Q_ENUMS(ReversingMode) - Q_PROPERTY(qreal source READ sourceValue WRITE setSourceValue NOTIFY sourceChanged) Q_PROPERTY(qreal velocity READ velocity WRITE setVelocity NOTIFY velocityChanged) - Q_PROPERTY(qreal duration READ duration WRITE setDuration NOTIFY durationChanged) Q_PROPERTY(ReversingMode reversingMode READ reversingMode WRITE setReversingMode NOTIFY reversingModeChanged) - Q_PROPERTY(bool enabled READ enabled WRITE setEnabled NOTIFY enabledChanged) Q_PROPERTY(qreal maximumEasingTime READ maximumEasingTime WRITE setMaximumEasingTime NOTIFY maximumEasingTimeChanged) public: enum ReversingMode { Eased, Immediate, Sync }; - QDeclarativeEaseFollow(QObject *parent = 0); - ~QDeclarativeEaseFollow(); + QDeclarativeSmoothedAnimation(QObject *parent = 0); + ~QDeclarativeSmoothedAnimation(); ReversingMode reversingMode() const; void setReversingMode(ReversingMode); - qreal sourceValue() const; - void setSourceValue(qreal); + virtual int duration() const; + virtual void setDuration(int); qreal velocity() const; void setVelocity(qreal); - qreal duration() const; - void setDuration(qreal); + int maximumEasingTime() const; + void setMaximumEasingTime(int); - bool enabled() const; - void setEnabled(bool enabled); - - qreal maximumEasingTime() const; - void setMaximumEasingTime(qreal); - - virtual void setTarget(const QDeclarativeProperty &); +public: + virtual void transition(QDeclarativeStateActions &actions, + QDeclarativeProperties &modified, + TransitionDirection direction); + QAbstractAnimation* qtAnimation(); Q_SIGNALS: - void sourceChanged(); void velocityChanged(); - void durationChanged(); void reversingModeChanged(); - void enabledChanged(); void maximumEasingTimeChanged(); }; QT_END_NAMESPACE -QML_DECLARE_TYPE(QDeclarativeEaseFollow); +QML_DECLARE_TYPE(QDeclarativeSmoothedAnimation); QT_END_HEADER diff --git a/src/declarative/util/qdeclarativeeasefollow_p_p.h b/src/declarative/util/qdeclarativeeasefollow_p_p.h new file mode 100644 index 0000000..e71a009 --- /dev/null +++ b/src/declarative/util/qdeclarativeeasefollow_p_p.h @@ -0,0 +1,133 @@ +/**************************************************************************** +** +** 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 QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVESMOOTHEDANIMATION_P_H +#define QDECLARATIVESMOOTHEDANIMATION_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qdeclarativeanimation_p.h" +#include "qdeclarativeeasefollow_p.h" + +#include "qdeclarativeanimation_p_p.h" + +#include + +#include + +QT_BEGIN_NAMESPACE + +class QSmoothedAnimation : public QAbstractAnimation +{ +public: + QSmoothedAnimation(QObject *parent=0); + + qreal to; + qreal velocity; + int userDuration; + + int maximumEasingTime; + QDeclarativeSmoothedAnimation::ReversingMode reversingMode; + + qreal initialVelocity; + qreal trackVelocity; + + QDeclarativeProperty target; + + int duration() const; + void restart(); + void init(); + +protected: + virtual void updateCurrentTime(int); + virtual void updateState(QAbstractAnimation::State, QAbstractAnimation::State); + +private: + qreal easeFollow(qreal); + qreal initialValue; + + bool invert; + + int finalDuration; + + // Parameters for use in updateCurrentTime() + qreal a; // Acceleration + qreal d; // Deceleration + qreal tf; // Total time + qreal tp; // Time at which peak velocity occurs + qreal td; // Time at which decelleration begins + qreal vp; // Velocity at tp + qreal sp; // Displacement at tp + qreal sd; // Displacement at td + qreal vi; // "Normalized" initialvelocity + qreal s; // Total s + + int lastTime; + + bool recalc(); + void delayedStop(); + + QTimer delayedStopTimer; +}; + +class QDeclarativeSmoothedAnimationPrivate : public QDeclarativePropertyAnimationPrivate +{ + Q_DECLARE_PUBLIC(QDeclarativeSmoothedAnimation) +public: + QDeclarativeSmoothedAnimationPrivate(); + + QParallelAnimationGroup *wrapperGroup; + QSmoothedAnimation *anim; + QHash activeAnimations; +}; + +QT_END_NAMESPACE + +#endif // QDECLARATIVESMOOTHEDANIMATION_P_H diff --git a/src/declarative/util/qdeclarativespringfollow.cpp b/src/declarative/util/qdeclarativespringfollow.cpp index 76d7c98..063c3df 100644 --- a/src/declarative/util/qdeclarativespringfollow.cpp +++ b/src/declarative/util/qdeclarativespringfollow.cpp @@ -242,8 +242,6 @@ void QDeclarativeSpringFollowPrivate::stop() SpringFollow on y { source: rect1.y; velocity: 200 } } \endcode - - \sa EaseFollow */ QDeclarativeSpringFollow::QDeclarativeSpringFollow(QObject *parent) diff --git a/src/declarative/util/qdeclarativetransition.cpp b/src/declarative/util/qdeclarativetransition.cpp index 4326a55..1e8be7f 100644 --- a/src/declarative/util/qdeclarativetransition.cpp +++ b/src/declarative/util/qdeclarativetransition.cpp @@ -116,9 +116,9 @@ void QDeclarativeTransitionPrivate::append_animation(QDeclarativeListPropertycomplete(); } diff --git a/src/declarative/util/qdeclarativeutilmodule.cpp b/src/declarative/util/qdeclarativeutilmodule.cpp index 2a02ffe..bf50a8b 100644 --- a/src/declarative/util/qdeclarativeutilmodule.cpp +++ b/src/declarative/util/qdeclarativeutilmodule.cpp @@ -111,7 +111,7 @@ void QDeclarativeUtilModule::defineModule() qmlRegisterType("Qt",4,6,"Binding"); qmlRegisterType("Qt",4,6,"ColorAnimation"); qmlRegisterType("Qt",4,6,"Connections"); - qmlRegisterType("Qt",4,6,"EaseFollow"); + qmlRegisterType("Qt",4,6,"SmoothedAnimation"); qmlRegisterType("Qt",4,6,"FontLoader"); qmlRegisterType("Qt",4,6,"ListElement"); qmlRegisterType("Qt",4,6,"NumberAnimation"); diff --git a/src/declarative/util/util.pri b/src/declarative/util/util.pri index f537806..249465a 100644 --- a/src/declarative/util/util.pri +++ b/src/declarative/util/util.pri @@ -38,6 +38,7 @@ HEADERS += \ $$PWD/qdeclarativesystempalette_p.h \ $$PWD/qdeclarativespringfollow_p.h \ $$PWD/qdeclarativeeasefollow_p.h \ + $$PWD/qdeclarativeeasefollow_p_p.h \ $$PWD/qdeclarativestate_p.h\ $$PWD/qdeclarativestateoperations_p.h \ $$PWD/qdeclarativepropertychanges_p.h \ diff --git a/tests/auto/declarative/qdeclarativeeasefollow/data/easefollow1.qml b/tests/auto/declarative/qdeclarativeeasefollow/data/easefollow1.qml index 0cc19eb..cfece41 100644 --- a/tests/auto/declarative/qdeclarativeeasefollow/data/easefollow1.qml +++ b/tests/auto/declarative/qdeclarativeeasefollow/data/easefollow1.qml @@ -1,3 +1,3 @@ import Qt 4.6 -EaseFollow {} +SmoothedAnimation {} diff --git a/tests/auto/declarative/qdeclarativeeasefollow/data/easefollow2.qml b/tests/auto/declarative/qdeclarativeeasefollow/data/easefollow2.qml index b65964e..74a110d 100644 --- a/tests/auto/declarative/qdeclarativeeasefollow/data/easefollow2.qml +++ b/tests/auto/declarative/qdeclarativeeasefollow/data/easefollow2.qml @@ -1,5 +1,5 @@ import Qt 4.6 -EaseFollow { - source: 10; duration: 300; enabled: true; reversingMode: EaseFollow.Immediate +SmoothedAnimation { + to: 10; duration: 300; reversingMode: SmoothedAnimation.Immediate } diff --git a/tests/auto/declarative/qdeclarativeeasefollow/data/easefollow3.qml b/tests/auto/declarative/qdeclarativeeasefollow/data/easefollow3.qml index f8886e9..3111e82 100644 --- a/tests/auto/declarative/qdeclarativeeasefollow/data/easefollow3.qml +++ b/tests/auto/declarative/qdeclarativeeasefollow/data/easefollow3.qml @@ -1,6 +1,6 @@ import Qt 4.6 -EaseFollow { - source: 10; velocity: 250; enabled: false; reversingMode: EaseFollow.Sync +SmoothedAnimation { + to: 10; velocity: 250; reversingMode: SmoothedAnimation.Sync maximumEasingTime: 150 } diff --git a/tests/auto/declarative/qdeclarativeeasefollow/data/easefollowBehavior.qml b/tests/auto/declarative/qdeclarativeeasefollow/data/easefollowBehavior.qml new file mode 100644 index 0000000..eb06344 --- /dev/null +++ b/tests/auto/declarative/qdeclarativeeasefollow/data/easefollowBehavior.qml @@ -0,0 +1,23 @@ +import Qt 4.6 + +Rectangle { + width: 400; height: 400; color: "blue" + + Rectangle { + id: rect1 + color: "red" + width: 60; height: 60; + x: 100; y: 100; + SmoothedAnimation on x { to: 200; velocity: 500 } + SmoothedAnimation on y { to: 200; velocity: 500 } + } + + Rectangle { + objectName: "theRect" + color: "green" + width: 60; height: 60; + x: rect1.x; y: rect1.y; + Behavior on x { SmoothedAnimation { objectName: "easeX"; velocity: 400 } } + Behavior on y { SmoothedAnimation { objectName: "easeY"; velocity: 400 } } + } + } diff --git a/tests/auto/declarative/qdeclarativeeasefollow/data/easefollowValueSource.qml b/tests/auto/declarative/qdeclarativeeasefollow/data/easefollowValueSource.qml new file mode 100644 index 0000000..9ae744c --- /dev/null +++ b/tests/auto/declarative/qdeclarativeeasefollow/data/easefollowValueSource.qml @@ -0,0 +1,13 @@ +import Qt 4.6 + +Rectangle { + width: 300; height: 300; + Rectangle { + objectName: "theRect" + color: "red" + width: 60; height: 60; + x: 100; y: 100; + SmoothedAnimation on x { objectName: "easeX"; to: 200; velocity: 500 } + SmoothedAnimation on y { objectName: "easeY"; to: 200; duration: 250; velocity: 500 } + } +} diff --git a/tests/auto/declarative/qdeclarativeeasefollow/tst_qdeclarativeeasefollow.cpp b/tests/auto/declarative/qdeclarativeeasefollow/tst_qdeclarativeeasefollow.cpp index 036eec0..401688b 100644 --- a/tests/auto/declarative/qdeclarativeeasefollow/tst_qdeclarativeeasefollow.cpp +++ b/tests/auto/declarative/qdeclarativeeasefollow/tst_qdeclarativeeasefollow.cpp @@ -42,6 +42,7 @@ #include #include #include +#include #include #include "../../../shared/util.h" @@ -55,6 +56,9 @@ private slots: void defaultValues(); void values(); void disabled(); + void simpleAnimation(); + void valueSource(); + void behavior(); private: QDeclarativeEngine engine; @@ -68,16 +72,15 @@ void tst_qdeclarativeeasefollow::defaultValues() { QDeclarativeEngine engine; QDeclarativeComponent c(&engine, QUrl::fromLocalFile(SRCDIR "/data/easefollow1.qml")); - QDeclarativeEaseFollow *obj = qobject_cast(c.create()); + QDeclarativeSmoothedAnimation *obj = qobject_cast(c.create()); QVERIFY(obj != 0); - QCOMPARE(obj->sourceValue(), 0.); + QCOMPARE(obj->to(), 0.); QCOMPARE(obj->velocity(), 200.); - QCOMPARE(obj->enabled(), true); - QCOMPARE(obj->duration(), -1.); - QCOMPARE(obj->maximumEasingTime(), -1.); - QCOMPARE(obj->reversingMode(), QDeclarativeEaseFollow::Eased); + QCOMPARE(obj->duration(), -1); + QCOMPARE(obj->maximumEasingTime(), -1); + QCOMPARE(obj->reversingMode(), QDeclarativeSmoothedAnimation::Eased); delete obj; } @@ -86,16 +89,15 @@ void tst_qdeclarativeeasefollow::values() { QDeclarativeEngine engine; QDeclarativeComponent c(&engine, QUrl::fromLocalFile(SRCDIR "/data/easefollow2.qml")); - QDeclarativeEaseFollow *obj = qobject_cast(c.create()); + QDeclarativeSmoothedAnimation *obj = qobject_cast(c.create()); QVERIFY(obj != 0); - QCOMPARE(obj->sourceValue(), 10.); + QCOMPARE(obj->to(), 10.); QCOMPARE(obj->velocity(), 200.); - QCOMPARE(obj->enabled(), true); - QCOMPARE(obj->duration(), 300.); - QCOMPARE(obj->maximumEasingTime(), -1.); - QCOMPARE(obj->reversingMode(), QDeclarativeEaseFollow::Immediate); + QCOMPARE(obj->duration(), 300); + QCOMPARE(obj->maximumEasingTime(), -1); + QCOMPARE(obj->reversingMode(), QDeclarativeSmoothedAnimation::Immediate); delete obj; } @@ -104,19 +106,102 @@ void tst_qdeclarativeeasefollow::disabled() { QDeclarativeEngine engine; QDeclarativeComponent c(&engine, QUrl::fromLocalFile(SRCDIR "/data/easefollow3.qml")); - QDeclarativeEaseFollow *obj = qobject_cast(c.create()); + QDeclarativeSmoothedAnimation *obj = qobject_cast(c.create()); QVERIFY(obj != 0); - QCOMPARE(obj->sourceValue(), 10.); + QCOMPARE(obj->to(), 10.); QCOMPARE(obj->velocity(), 250.); - QCOMPARE(obj->enabled(), false); - QCOMPARE(obj->maximumEasingTime(), 150.); - QCOMPARE(obj->reversingMode(), QDeclarativeEaseFollow::Sync); + QCOMPARE(obj->maximumEasingTime(), 150); + QCOMPARE(obj->reversingMode(), QDeclarativeSmoothedAnimation::Sync); delete obj; } +void tst_qdeclarativeeasefollow::simpleAnimation() +{ + QDeclarativeRectangle rect; + QDeclarativeSmoothedAnimation animation; + animation.setTarget(&rect); + animation.setProperty("x"); + animation.setTo(200); + animation.setDuration(250); + QVERIFY(animation.target() == &rect); + QVERIFY(animation.property() == "x"); + QVERIFY(animation.to() == 200); + animation.start(); + QVERIFY(animation.isRunning()); + QTest::qWait(animation.duration()); + QTRY_COMPARE(rect.x(), qreal(200)); + + rect.setX(0); + animation.start(); + animation.pause(); + QVERIFY(animation.isRunning()); + QVERIFY(animation.isPaused()); + animation.setCurrentTime(125); + QVERIFY(animation.currentTime() == 125); + QCOMPARE(rect.x(), qreal(100)); +} + +void tst_qdeclarativeeasefollow::valueSource() +{ + QDeclarativeEngine engine; + + QDeclarativeComponent c(&engine, QUrl::fromLocalFile(SRCDIR "/data/easefollowValueSource.qml")); + + QDeclarativeRectangle *rect = qobject_cast(c.create()); + QVERIFY(rect); + + QDeclarativeRectangle *theRect = rect->findChild("theRect"); + QVERIFY(theRect); + + QDeclarativeSmoothedAnimation *easeX = rect->findChild("easeX"); + QVERIFY(easeX); + QVERIFY(easeX->isRunning()); + + QDeclarativeSmoothedAnimation *easeY = rect->findChild("easeY"); + QVERIFY(easeY); + QVERIFY(easeY->isRunning()); + + // XXX get the proper duration + QTest::qWait(100); + + QTRY_VERIFY(!easeX->isRunning()); + QTRY_VERIFY(!easeY->isRunning()); + + QTRY_COMPARE(theRect->x(), qreal(200)); + QTRY_COMPARE(theRect->y(), qreal(200)); +} + +void tst_qdeclarativeeasefollow::behavior() +{ + QDeclarativeEngine engine; + + QDeclarativeComponent c(&engine, QUrl::fromLocalFile(SRCDIR "/data/easefollowBehavior.qml")); + + QDeclarativeRectangle *rect = qobject_cast(c.create()); + QVERIFY(rect); + + QDeclarativeRectangle *theRect = rect->findChild("theRect"); + QVERIFY(theRect); + + QDeclarativeSmoothedAnimation *easeX = rect->findChild("easeX"); + QVERIFY(easeX); + + QDeclarativeSmoothedAnimation *easeY = rect->findChild("easeY"); + QVERIFY(easeY); + + // XXX get the proper duration + QTest::qWait(400); + + QTRY_VERIFY(!easeX->isRunning()); + QTRY_VERIFY(!easeY->isRunning()); + + QTRY_COMPARE(theRect->x(), qreal(200)); + QTRY_COMPARE(theRect->y(), qreal(200)); +} + QTEST_MAIN(tst_qdeclarativeeasefollow) #include "tst_qdeclarativeeasefollow.moc" diff --git a/tests/auto/declarative/qdeclarativelistview/data/listviewtest.qml b/tests/auto/declarative/qdeclarativelistview/data/listviewtest.qml index cc64c3f..40fc436 100644 --- a/tests/auto/declarative/qdeclarativelistview/data/listviewtest.qml +++ b/tests/auto/declarative/qdeclarativelistview/data/listviewtest.qml @@ -98,7 +98,7 @@ Rectangle { }, Component { id: invalidHl - EaseFollow {} + SmoothedAnimation {} } ] ListView { diff --git a/tests/auto/declarative/qmlvisual/qdeclarativeeasefollow/easefollow.qml b/tests/auto/declarative/qmlvisual/qdeclarativeeasefollow/easefollow.qml index 121328b..ee94857 100644 --- a/tests/auto/declarative/qmlvisual/qdeclarativeeasefollow/easefollow.qml +++ b/tests/auto/declarative/qmlvisual/qdeclarativeeasefollow/easefollow.qml @@ -15,26 +15,31 @@ Rectangle { Rectangle { width: 50; height: 20; y: 60; color: "red" - EaseFollow on x { source: rect.x; velocity: 400 } + x: rect.x + Behavior on x { SmoothedAnimation { velocity: 400 } } } Rectangle { width: 50; height: 20; y: 90; color: "yellow" - EaseFollow on x { source: rect.x; velocity: 300; reversingMode: EaseFollow.Immediate } + x: rect.x + Behavior on x { SmoothedAnimation { velocity: 300; reversingMode: SmoothedAnimation.Immediate } } } Rectangle { width: 50; height: 20; y: 120; color: "green" - EaseFollow on x { source: rect.x; reversingMode: EaseFollow.Sync } + x: rect.x + Behavior on x { SmoothedAnimation { reversingMode: SmoothedAnimation.Sync } } } Rectangle { width: 50; height: 20; y: 150; color: "purple" - EaseFollow on x { source: rect.x; maximumEasingTime: 200 } + x: rect.x + Behavior on x { SmoothedAnimation { maximumEasingTime: 200 } } } Rectangle { width: 50; height: 20; y: 180; color: "blue" - EaseFollow on x { source: rect.x; duration: 300 } + x: rect.x + Behavior on x { SmoothedAnimation { duration: 300 } } } } diff --git a/tests/auto/declarative/qmlvisual/qdeclarativegridview/gridview2.qml b/tests/auto/declarative/qmlvisual/qdeclarativegridview/gridview2.qml index f4fb863..d8512eb 100644 --- a/tests/auto/declarative/qmlvisual/qdeclarativegridview/gridview2.qml +++ b/tests/auto/declarative/qmlvisual/qdeclarativegridview/gridview2.qml @@ -48,9 +48,12 @@ Rectangle { flickableData: [ Rectangle { color: "transparent"; border.color: "white"; border.width: 8; z: 3000 - height: 100; width: 100; x: 4; y: 4 - EaseFollow on x { source: gridView.currentItem.x; velocity: 500 } - EaseFollow on y { source: gridView.currentItem.y; velocity: 500 } + height: 100; width: 100 + x: gridView.currentItem.x + y: gridView.currentItem.y + + Behavior on x { SmoothedAnimation { velocity: 500 } } + Behavior on y { SmoothedAnimation { velocity: 500 } } } ] } -- cgit v0.12 From e2f9d31227e9a2126a99503c4285efaf8d894dd9 Mon Sep 17 00:00:00 2001 From: Leonardo Sobral Cunha Date: Mon, 29 Mar 2010 13:58:00 +1000 Subject: Finished file rename of qdeclarative easefollow to smoothedanimation --- .../graphicsitems/qdeclarativegridview.cpp | 2 +- .../graphicsitems/qdeclarativelistview.cpp | 2 +- .../graphicsitems/qdeclarativepathview.cpp | 1 - src/declarative/util/qdeclarativeeasefollow.cpp | 484 ------ src/declarative/util/qdeclarativeeasefollow_p.h | 104 -- src/declarative/util/qdeclarativeeasefollow_p_p.h | 133 -- .../util/qdeclarativesmoothedanimation.cpp | 483 ++++++ .../util/qdeclarativesmoothedanimation_p.h | 104 ++ .../util/qdeclarativesmoothedanimation_p_p.h | 134 ++ src/declarative/util/qdeclarativeutilmodule.cpp | 2 +- src/declarative/util/util.pri | 6 +- tests/auto/declarative/declarative.pro | 2 +- .../qdeclarativeeasefollow/data/easefollow1.qml | 3 - .../qdeclarativeeasefollow/data/easefollow2.qml | 5 - .../qdeclarativeeasefollow/data/easefollow3.qml | 6 - .../data/easefollowBehavior.qml | 23 - .../data/easefollowValueSource.qml | 13 - .../qdeclarativeeasefollow.pro | 8 - .../tst_qdeclarativeeasefollow.cpp | 207 --- .../data/smoothedanimation1.qml | 3 + .../data/smoothedanimation2.qml | 5 + .../data/smoothedanimation3.qml | 6 + .../data/smoothedanimationBehavior.qml | 23 + .../data/smoothedanimationValueSource.qml | 13 + .../qdeclarativesmoothedanimation.pro | 8 + .../tst_qdeclarativesmoothedanimation.cpp | 207 +++ .../qdeclarativeeasefollow/data/easefollow.0.png | Bin 1305 -> 0 bytes .../qdeclarativeeasefollow/data/easefollow.1.png | Bin 1306 -> 0 bytes .../qdeclarativeeasefollow/data/easefollow.2.png | Bin 1305 -> 0 bytes .../qdeclarativeeasefollow/data/easefollow.3.png | Bin 1303 -> 0 bytes .../qdeclarativeeasefollow/data/easefollow.4.png | Bin 1303 -> 0 bytes .../qdeclarativeeasefollow/data/easefollow.5.png | Bin 1305 -> 0 bytes .../qdeclarativeeasefollow/data/easefollow.6.png | Bin 1306 -> 0 bytes .../qdeclarativeeasefollow/data/easefollow.qml | 1807 -------------------- .../qdeclarativeeasefollow/easefollow.qml | 45 - .../data/easefollow.0.png | Bin 0 -> 1305 bytes .../data/easefollow.1.png | Bin 0 -> 1306 bytes .../data/easefollow.2.png | Bin 0 -> 1305 bytes .../data/easefollow.3.png | Bin 0 -> 1303 bytes .../data/easefollow.4.png | Bin 0 -> 1303 bytes .../data/easefollow.5.png | Bin 0 -> 1305 bytes .../data/easefollow.6.png | Bin 0 -> 1306 bytes .../data/easefollow.qml | 1807 ++++++++++++++++++++ .../smoothedanimation.qml | 45 + 44 files changed, 2845 insertions(+), 2846 deletions(-) delete mode 100644 src/declarative/util/qdeclarativeeasefollow.cpp delete mode 100644 src/declarative/util/qdeclarativeeasefollow_p.h delete mode 100644 src/declarative/util/qdeclarativeeasefollow_p_p.h create mode 100644 src/declarative/util/qdeclarativesmoothedanimation.cpp create mode 100644 src/declarative/util/qdeclarativesmoothedanimation_p.h create mode 100644 src/declarative/util/qdeclarativesmoothedanimation_p_p.h delete mode 100644 tests/auto/declarative/qdeclarativeeasefollow/data/easefollow1.qml delete mode 100644 tests/auto/declarative/qdeclarativeeasefollow/data/easefollow2.qml delete mode 100644 tests/auto/declarative/qdeclarativeeasefollow/data/easefollow3.qml delete mode 100644 tests/auto/declarative/qdeclarativeeasefollow/data/easefollowBehavior.qml delete mode 100644 tests/auto/declarative/qdeclarativeeasefollow/data/easefollowValueSource.qml delete mode 100644 tests/auto/declarative/qdeclarativeeasefollow/qdeclarativeeasefollow.pro delete mode 100644 tests/auto/declarative/qdeclarativeeasefollow/tst_qdeclarativeeasefollow.cpp create mode 100644 tests/auto/declarative/qdeclarativesmoothedanimation/data/smoothedanimation1.qml create mode 100644 tests/auto/declarative/qdeclarativesmoothedanimation/data/smoothedanimation2.qml create mode 100644 tests/auto/declarative/qdeclarativesmoothedanimation/data/smoothedanimation3.qml create mode 100644 tests/auto/declarative/qdeclarativesmoothedanimation/data/smoothedanimationBehavior.qml create mode 100644 tests/auto/declarative/qdeclarativesmoothedanimation/data/smoothedanimationValueSource.qml create mode 100644 tests/auto/declarative/qdeclarativesmoothedanimation/qdeclarativesmoothedanimation.pro create mode 100644 tests/auto/declarative/qdeclarativesmoothedanimation/tst_qdeclarativesmoothedanimation.cpp delete mode 100644 tests/auto/declarative/qmlvisual/qdeclarativeeasefollow/data/easefollow.0.png delete mode 100644 tests/auto/declarative/qmlvisual/qdeclarativeeasefollow/data/easefollow.1.png delete mode 100644 tests/auto/declarative/qmlvisual/qdeclarativeeasefollow/data/easefollow.2.png delete mode 100644 tests/auto/declarative/qmlvisual/qdeclarativeeasefollow/data/easefollow.3.png delete mode 100644 tests/auto/declarative/qmlvisual/qdeclarativeeasefollow/data/easefollow.4.png delete mode 100644 tests/auto/declarative/qmlvisual/qdeclarativeeasefollow/data/easefollow.5.png delete mode 100644 tests/auto/declarative/qmlvisual/qdeclarativeeasefollow/data/easefollow.6.png delete mode 100644 tests/auto/declarative/qmlvisual/qdeclarativeeasefollow/data/easefollow.qml delete mode 100644 tests/auto/declarative/qmlvisual/qdeclarativeeasefollow/easefollow.qml create mode 100644 tests/auto/declarative/qmlvisual/qdeclarativesmoothedanimation/data/easefollow.0.png create mode 100644 tests/auto/declarative/qmlvisual/qdeclarativesmoothedanimation/data/easefollow.1.png create mode 100644 tests/auto/declarative/qmlvisual/qdeclarativesmoothedanimation/data/easefollow.2.png create mode 100644 tests/auto/declarative/qmlvisual/qdeclarativesmoothedanimation/data/easefollow.3.png create mode 100644 tests/auto/declarative/qmlvisual/qdeclarativesmoothedanimation/data/easefollow.4.png create mode 100644 tests/auto/declarative/qmlvisual/qdeclarativesmoothedanimation/data/easefollow.5.png create mode 100644 tests/auto/declarative/qmlvisual/qdeclarativesmoothedanimation/data/easefollow.6.png create mode 100644 tests/auto/declarative/qmlvisual/qdeclarativesmoothedanimation/data/easefollow.qml create mode 100644 tests/auto/declarative/qmlvisual/qdeclarativesmoothedanimation/smoothedanimation.qml diff --git a/src/declarative/graphicsitems/qdeclarativegridview.cpp b/src/declarative/graphicsitems/qdeclarativegridview.cpp index 6d1dec6..12ede34 100644 --- a/src/declarative/graphicsitems/qdeclarativegridview.cpp +++ b/src/declarative/graphicsitems/qdeclarativegridview.cpp @@ -44,7 +44,7 @@ #include "qdeclarativevisualitemmodel_p.h" #include "qdeclarativeflickable_p_p.h" -#include "qdeclarativeeasefollow_p_p.h" +#include "qdeclarativesmoothedanimation_p_p.h" #include #include diff --git a/src/declarative/graphicsitems/qdeclarativelistview.cpp b/src/declarative/graphicsitems/qdeclarativelistview.cpp index 6a4f4b9..cbf8eac 100644 --- a/src/declarative/graphicsitems/qdeclarativelistview.cpp +++ b/src/declarative/graphicsitems/qdeclarativelistview.cpp @@ -44,7 +44,7 @@ #include "qdeclarativeflickable_p_p.h" #include "qdeclarativevisualitemmodel_p.h" -#include "qdeclarativeeasefollow_p_p.h" +#include "qdeclarativesmoothedanimation_p_p.h" #include #include #include diff --git a/src/declarative/graphicsitems/qdeclarativepathview.cpp b/src/declarative/graphicsitems/qdeclarativepathview.cpp index 3574c9f..c2cfbb1 100644 --- a/src/declarative/graphicsitems/qdeclarativepathview.cpp +++ b/src/declarative/graphicsitems/qdeclarativepathview.cpp @@ -44,7 +44,6 @@ #include #include -#include #include #include #include diff --git a/src/declarative/util/qdeclarativeeasefollow.cpp b/src/declarative/util/qdeclarativeeasefollow.cpp deleted file mode 100644 index ce2c496..0000000 --- a/src/declarative/util/qdeclarativeeasefollow.cpp +++ /dev/null @@ -1,484 +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 QtDeclarative module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -** -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qdeclarativeeasefollow_p.h" -#include "qdeclarativeeasefollow_p_p.h" - -#include "qdeclarativeanimation_p_p.h" - -#include -#include "qdeclarativeproperty_p.h" - -#include "qdeclarativeglobal_p.h" - -#include - -#include -#include - -#define DELAY_STOP_TIMER_INTERVAL 32 - -QT_BEGIN_NAMESPACE - -QSmoothedAnimation::QSmoothedAnimation(QObject *parent) - : QAbstractAnimation(parent), to(0), velocity(200), userDuration(-1), maximumEasingTime(-1), - reversingMode(QDeclarativeSmoothedAnimation::Eased), initialVelocity(0), - trackVelocity(0), initialValue(0), invert(false), finalDuration(-1), lastTime(0) -{ - delayedStopTimer.setInterval(DELAY_STOP_TIMER_INTERVAL); - delayedStopTimer.setSingleShot(true); - connect(&delayedStopTimer, SIGNAL(timeout()), this, SLOT(stop())); -} - -void QSmoothedAnimation::restart() -{ - if (state() != QAbstractAnimation::Running) - start(); - else - init(); -} - -void QSmoothedAnimation::updateState(QAbstractAnimation::State newState, QAbstractAnimation::State /*oldState*/) -{ - if (newState == QAbstractAnimation::Running) - init(); -} - -void QSmoothedAnimation::delayedStop() -{ - if (!delayedStopTimer.isActive()) - delayedStopTimer.start(); -} - -int QSmoothedAnimation::duration() const -{ - return -1; -} - -bool QSmoothedAnimation::recalc() -{ - s = to - initialValue; - vi = initialVelocity; - - s = (invert? -1.0: 1.0) * s; - - if (userDuration > 0 && velocity > 0) { - tf = s / velocity; - if (tf > (userDuration / 1000.)) tf = (userDuration / 1000.); - } else if (userDuration > 0) { - tf = userDuration / 1000.; - } else if (velocity > 0) { - tf = s / velocity; - } else { - return false; - } - - finalDuration = ceil(tf * 1000.0); - - if (maximumEasingTime == 0) { - a = 0; - d = 0; - tp = 0; - td = tf; - vp = velocity; - sp = 0; - sd = s; - } else if (maximumEasingTime != -1 && tf > (maximumEasingTime / 1000.)) { - qreal met = maximumEasingTime / 1000.; - td = tf - met; - - qreal c1 = td; - qreal c2 = (tf - td) * vi - tf * velocity; - qreal c3 = -0.5 * (tf - td) * vi * vi; - - qreal vp1 = (-c2 + sqrt(c2 * c2 - 4 * c1 * c3)) / (2. * c1); - - vp = vp1; - a = vp / met; - d = a; - tp = (vp - vi) / a; - sp = vi * tp + 0.5 * a * tp * tp; - sd = sp + (td - tp) * vp; - } else { - qreal c1 = 0.25 * tf * tf; - qreal c2 = 0.5 * vi * tf - s; - qreal c3 = -0.25 * vi * vi; - - qreal a1 = (-c2 + sqrt(c2 * c2 - 4 * c1 * c3)) / (2. * c1); - - qreal tp1 = 0.5 * tf - 0.5 * vi / a1; - qreal vp1 = a1 * tp1 + vi; - - qreal sp1 = 0.5 * a1 * tp1 * tp1 + vi * tp1; - - a = a1; - d = a1; - tp = tp1; - td = tp1; - vp = vp1; - sp = sp1; - sd = sp1; - } - return true; -} - -qreal QSmoothedAnimation::easeFollow(qreal time_seconds) -{ - qreal value; - if (time_seconds < tp) { - trackVelocity = vi + time_seconds * a; - value = 0.5 * a * time_seconds * time_seconds + vi * time_seconds; - } else if (time_seconds < td) { - time_seconds -= tp; - trackVelocity = vp; - value = sp + time_seconds * vp; - } else if (time_seconds < tf) { - time_seconds -= td; - trackVelocity = vp - time_seconds * a; - value = sd - 0.5 * d * time_seconds * time_seconds + vp * time_seconds; - } else { - trackVelocity = 0; - value = s; - delayedStop(); - } - - // to normalize 's' between [0..1], divide 'value' by 's' - return value; -} - -void QSmoothedAnimation::updateCurrentTime(int t) -{ - qreal time_seconds = qreal(t - lastTime) / 1000.; - - qreal value = easeFollow(time_seconds); - value *= (invert? -1.0: 1.0); - QDeclarativePropertyPrivate::write(target, initialValue + value, - QDeclarativePropertyPrivate::BypassInterceptor - | QDeclarativePropertyPrivate::DontRemoveBinding); -} - -void QSmoothedAnimation::init() -{ - if (velocity == 0) { - stop(); - return; - } - - if (delayedStopTimer.isActive()) - delayedStopTimer.stop(); - - initialValue = target.read().toReal(); - lastTime = this->currentTime(); - - if (to == initialValue) { - stop(); - return; - } - - bool hasReversed = trackVelocity != 0. && - ((trackVelocity > 0) == ((initialValue - to) > 0)); - - if (hasReversed) { - switch (reversingMode) { - default: - case QDeclarativeSmoothedAnimation::Eased: - break; - case QDeclarativeSmoothedAnimation::Sync: - QDeclarativePropertyPrivate::write(target, to, - QDeclarativePropertyPrivate::BypassInterceptor - | QDeclarativePropertyPrivate::DontRemoveBinding); - return; - case QDeclarativeSmoothedAnimation::Immediate: - initialVelocity = 0; - delayedStop(); - break; - } - } - - trackVelocity = initialVelocity; - - invert = (to < initialValue); - - if (!recalc()) { - QDeclarativePropertyPrivate::write(target, to, - QDeclarativePropertyPrivate::BypassInterceptor - | QDeclarativePropertyPrivate::DontRemoveBinding); - stop(); - return; - } -} - -/*! - \qmlclass SmoothedAnimation QDeclarativeSmoothedAnimation - \since 4.7 - \brief The SmoothedAnimation element allows a property to smoothly track a value. - - The SmoothedAnimation smoothly animates a property's value to a set target value - using an ease in/out quad easing curve. If the animation is restarted - with a different target value, the easing curves used to animate to the old - and the new target values are spliced together to avoid any obvious visual - glitches. - - The property animation is configured by setting the velocity at which the - animation should occur, or the duration that the animation should take. - If both a velocity and a duration are specified, the one that results in - the quickest animation is chosen for each change in the target value. - - For example, animating from 0 to 800 will take 4 seconds if a velocity - of 200 is set, will take 8 seconds with a duration of 8000 set, and will - take 4 seconds with both a velocity of 200 and a duration of 8000 set. - Animating from 0 to 20000 will take 10 seconds if a velocity of 200 is set, - will take 8 seconds with a duration of 8000 set, and will take 8 seconds - with both a velocity of 200 and a duration of 8000 set. - - The follow example shows one rectangle tracking the position of another. -\code -import Qt 4.6 - -Rectangle { - width: 800; height: 600; color: "blue" - - Rectangle { - color: "green" - width: 60; height: 60; - x: rect1.x - 5; y: rect1.y - 5; - Behavior on x { SmoothedAnimation { velocity: 200 } } - Behavior on y { SmoothedAnimation { velocity: 200 } } - } - - Rectangle { - id: rect1 - color: "red" - width: 50; height: 50; - } - - focus: true - Keys.onRightPressed: rect1.x = rect1.x + 100 - Keys.onLeftPressed: rect1.x = rect1.x - 100 - Keys.onUpPressed: rect1.y = rect1.y - 100 - Keys.onDownPressed: rect1.y = rect1.y + 100 -} -\endcode - - The default velocity of SmoothedAnimation is 200 units/second. Note that if the range of the - value being animated is small, then the velocity will need to be adjusted - appropriately. For example, the opacity of an item ranges from 0 - 1.0. - To enable a smooth animation in this range the velocity will need to be - set to a value such as 0.5 units/second. Animating from 0 to 1.0 with a velocity - of 0.5 will take 2000 ms to complete. - - \sa SpringFollow -*/ - -QDeclarativeSmoothedAnimation::QDeclarativeSmoothedAnimation(QObject *parent) -: QDeclarativeNumberAnimation(*(new QDeclarativeSmoothedAnimationPrivate), parent) -{ -} - -QDeclarativeSmoothedAnimation::~QDeclarativeSmoothedAnimation() -{ -} - -QDeclarativeSmoothedAnimationPrivate::QDeclarativeSmoothedAnimationPrivate() - : wrapperGroup(new QParallelAnimationGroup), anim(new QSmoothedAnimation) -{ - Q_Q(QDeclarativeSmoothedAnimation); - QDeclarative_setParent_noEvent(wrapperGroup, q); - QDeclarative_setParent_noEvent(anim, q); -} - -QAbstractAnimation* QDeclarativeSmoothedAnimation::qtAnimation() -{ - Q_D(QDeclarativeSmoothedAnimation); - return d->wrapperGroup; -} - -void QDeclarativeSmoothedAnimation::transition(QDeclarativeStateActions &actions, - QDeclarativeProperties &modified, - TransitionDirection direction) -{ - Q_D(QDeclarativeSmoothedAnimation); - QDeclarativeNumberAnimation::transition(actions, modified, direction); - - if (!d->actions) - return; - - QSet anims; - for (int i = 0; i < d->actions->size(); i++) { - QSmoothedAnimation *ease; - qreal trackVelocity; - bool needsRestart; - if (!d->activeAnimations.contains((*d->actions)[i].property)) { - ease = new QSmoothedAnimation(); - d->wrapperGroup->addAnimation(ease); - d->activeAnimations.insert((*d->actions)[i].property, ease); - trackVelocity = 0.0; - needsRestart = false; - } else { - ease = d->activeAnimations.value((*d->actions)[i].property); - trackVelocity = ease->trackVelocity; - needsRestart = true; - } - - ease->target = (*d->actions)[i].property; - ease->to = (*d->actions)[i].toValue.toReal(); - - // copying public members from main value holder animation - ease->maximumEasingTime = d->anim->maximumEasingTime; - ease->reversingMode = d->anim->reversingMode; - ease->velocity = d->anim->velocity; - ease->userDuration = d->anim->userDuration; - - ease->trackVelocity = trackVelocity; - ease->initialVelocity = trackVelocity; - - if (needsRestart) - ease->init(); - anims.insert(ease); - } - - for (int i = d->wrapperGroup->animationCount() - 1; i >= 0 ; --i) { - if (!anims.contains(d->wrapperGroup->animationAt(i))) { - QSmoothedAnimation *ease = static_cast(d->wrapperGroup->animationAt(i)); - d->activeAnimations.remove(ease->target); - d->wrapperGroup->takeAnimation(i); - delete ease; - } - } -} - -/*! - \qmlproperty enumeration SmoothedAnimation::reversingMode - - Sets how the SmoothedAnimation behaves if an animation direction is reversed. - - If reversing mode is \c Eased, the animation will smoothly decelerate, and - then reverse direction. If the reversing mode is \c Immediate, the - animation will immediately begin accelerating in the reverse direction, - begining with a velocity of 0. If the reversing mode is \c Sync, the - property is immediately set to the target value. -*/ -QDeclarativeSmoothedAnimation::ReversingMode QDeclarativeSmoothedAnimation::reversingMode() const -{ - Q_D(const QDeclarativeSmoothedAnimation); - return (QDeclarativeSmoothedAnimation::ReversingMode) d->anim->reversingMode; -} - -void QDeclarativeSmoothedAnimation::setReversingMode(ReversingMode m) -{ - Q_D(QDeclarativeSmoothedAnimation); - if (d->anim->reversingMode == m) - return; - - d->anim->reversingMode = m; - emit reversingModeChanged(); -} - -/*! - \qmlproperty int SmoothedAnimation::duration - - This property holds the animation duration, in msecs, used when tracking the source. - - Setting this to -1 (the default) disables the duration value. -*/ -int QDeclarativeSmoothedAnimation::duration() const -{ - Q_D(const QDeclarativeSmoothedAnimation); - return d->anim->userDuration; -} - -void QDeclarativeSmoothedAnimation::setDuration(int duration) -{ - Q_D(QDeclarativeSmoothedAnimation); - if (duration != -1) - QDeclarativeNumberAnimation::setDuration(duration); - d->anim->userDuration = duration; -} - -qreal QDeclarativeSmoothedAnimation::velocity() const -{ - Q_D(const QDeclarativeSmoothedAnimation); - return d->anim->velocity; -} - -/*! - \qmlproperty qreal SmoothedAnimation::velocity - - This property holds the average velocity allowed when tracking the 'to' value. - - The default velocity of SmoothedAnimation is 200 units/second. - - Setting this to -1 disables the velocity value. -*/ -void QDeclarativeSmoothedAnimation::setVelocity(qreal v) -{ - Q_D(QDeclarativeSmoothedAnimation); - if (d->anim->velocity == v) - return; - - d->anim->velocity = v; - emit velocityChanged(); -} - -/*! -\qmlproperty qreal SmoothedAnimation::maximumEasingTime - -This property specifies the maximum time, in msecs, an "eases" during the follow should take. -Setting this property causes the velocity to "level out" after at a time. Setting -a negative value reverts to the normal mode of easing over the entire animation -duration. - -The default value is -1. -*/ -int QDeclarativeSmoothedAnimation::maximumEasingTime() const -{ - Q_D(const QDeclarativeSmoothedAnimation); - return d->anim->maximumEasingTime; -} - -void QDeclarativeSmoothedAnimation::setMaximumEasingTime(int v) -{ - Q_D(QDeclarativeSmoothedAnimation); - d->anim->maximumEasingTime = v; - emit maximumEasingTimeChanged(); -} - -QT_END_NAMESPACE diff --git a/src/declarative/util/qdeclarativeeasefollow_p.h b/src/declarative/util/qdeclarativeeasefollow_p.h deleted file mode 100644 index 6c17d4f..0000000 --- a/src/declarative/util/qdeclarativeeasefollow_p.h +++ /dev/null @@ -1,104 +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 QtDeclarative module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -** -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QDECLARATIVEEASEFOLLOW_H -#define QDECLARATIVEEASEFOLLOW_H - -#include -#include "qdeclarativeanimation_p.h" - -#include - -QT_BEGIN_HEADER - -QT_BEGIN_NAMESPACE - -QT_MODULE(Declarative) - -class QDeclarativeProperty; -class QDeclarativeSmoothedAnimationPrivate; -class Q_DECLARATIVE_EXPORT QDeclarativeSmoothedAnimation : public QDeclarativeNumberAnimation -{ - Q_OBJECT - Q_DECLARE_PRIVATE(QDeclarativeSmoothedAnimation) - Q_ENUMS(ReversingMode) - - Q_PROPERTY(qreal velocity READ velocity WRITE setVelocity NOTIFY velocityChanged) - Q_PROPERTY(ReversingMode reversingMode READ reversingMode WRITE setReversingMode NOTIFY reversingModeChanged) - Q_PROPERTY(qreal maximumEasingTime READ maximumEasingTime WRITE setMaximumEasingTime NOTIFY maximumEasingTimeChanged) - -public: - enum ReversingMode { Eased, Immediate, Sync }; - - QDeclarativeSmoothedAnimation(QObject *parent = 0); - ~QDeclarativeSmoothedAnimation(); - - ReversingMode reversingMode() const; - void setReversingMode(ReversingMode); - - virtual int duration() const; - virtual void setDuration(int); - - qreal velocity() const; - void setVelocity(qreal); - - int maximumEasingTime() const; - void setMaximumEasingTime(int); - -public: - virtual void transition(QDeclarativeStateActions &actions, - QDeclarativeProperties &modified, - TransitionDirection direction); - QAbstractAnimation* qtAnimation(); - -Q_SIGNALS: - void velocityChanged(); - void reversingModeChanged(); - void maximumEasingTimeChanged(); -}; - -QT_END_NAMESPACE - -QML_DECLARE_TYPE(QDeclarativeSmoothedAnimation); - -QT_END_HEADER - -#endif // QDECLARATIVEEASEFOLLOW_H diff --git a/src/declarative/util/qdeclarativeeasefollow_p_p.h b/src/declarative/util/qdeclarativeeasefollow_p_p.h deleted file mode 100644 index e71a009..0000000 --- a/src/declarative/util/qdeclarativeeasefollow_p_p.h +++ /dev/null @@ -1,133 +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 QtDeclarative module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -** -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QDECLARATIVESMOOTHEDANIMATION_P_H -#define QDECLARATIVESMOOTHEDANIMATION_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include "qdeclarativeanimation_p.h" -#include "qdeclarativeeasefollow_p.h" - -#include "qdeclarativeanimation_p_p.h" - -#include - -#include - -QT_BEGIN_NAMESPACE - -class QSmoothedAnimation : public QAbstractAnimation -{ -public: - QSmoothedAnimation(QObject *parent=0); - - qreal to; - qreal velocity; - int userDuration; - - int maximumEasingTime; - QDeclarativeSmoothedAnimation::ReversingMode reversingMode; - - qreal initialVelocity; - qreal trackVelocity; - - QDeclarativeProperty target; - - int duration() const; - void restart(); - void init(); - -protected: - virtual void updateCurrentTime(int); - virtual void updateState(QAbstractAnimation::State, QAbstractAnimation::State); - -private: - qreal easeFollow(qreal); - qreal initialValue; - - bool invert; - - int finalDuration; - - // Parameters for use in updateCurrentTime() - qreal a; // Acceleration - qreal d; // Deceleration - qreal tf; // Total time - qreal tp; // Time at which peak velocity occurs - qreal td; // Time at which decelleration begins - qreal vp; // Velocity at tp - qreal sp; // Displacement at tp - qreal sd; // Displacement at td - qreal vi; // "Normalized" initialvelocity - qreal s; // Total s - - int lastTime; - - bool recalc(); - void delayedStop(); - - QTimer delayedStopTimer; -}; - -class QDeclarativeSmoothedAnimationPrivate : public QDeclarativePropertyAnimationPrivate -{ - Q_DECLARE_PUBLIC(QDeclarativeSmoothedAnimation) -public: - QDeclarativeSmoothedAnimationPrivate(); - - QParallelAnimationGroup *wrapperGroup; - QSmoothedAnimation *anim; - QHash activeAnimations; -}; - -QT_END_NAMESPACE - -#endif // QDECLARATIVESMOOTHEDANIMATION_P_H diff --git a/src/declarative/util/qdeclarativesmoothedanimation.cpp b/src/declarative/util/qdeclarativesmoothedanimation.cpp new file mode 100644 index 0000000..b3a9b9a --- /dev/null +++ b/src/declarative/util/qdeclarativesmoothedanimation.cpp @@ -0,0 +1,483 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdeclarativesmoothedanimation_p.h" +#include "qdeclarativesmoothedanimation_p_p.h" + +#include "qdeclarativeanimation_p_p.h" + +#include +#include "qdeclarativeproperty_p.h" + +#include "qdeclarativeglobal_p.h" + +#include + +#include + +#define DELAY_STOP_TIMER_INTERVAL 32 + +QT_BEGIN_NAMESPACE + +QSmoothedAnimation::QSmoothedAnimation(QObject *parent) + : QAbstractAnimation(parent), to(0), velocity(200), userDuration(-1), maximumEasingTime(-1), + reversingMode(QDeclarativeSmoothedAnimation::Eased), initialVelocity(0), + trackVelocity(0), initialValue(0), invert(false), finalDuration(-1), lastTime(0) +{ + delayedStopTimer.setInterval(DELAY_STOP_TIMER_INTERVAL); + delayedStopTimer.setSingleShot(true); + connect(&delayedStopTimer, SIGNAL(timeout()), this, SLOT(stop())); +} + +void QSmoothedAnimation::restart() +{ + if (state() != QAbstractAnimation::Running) + start(); + else + init(); +} + +void QSmoothedAnimation::updateState(QAbstractAnimation::State newState, QAbstractAnimation::State /*oldState*/) +{ + if (newState == QAbstractAnimation::Running) + init(); +} + +void QSmoothedAnimation::delayedStop() +{ + if (!delayedStopTimer.isActive()) + delayedStopTimer.start(); +} + +int QSmoothedAnimation::duration() const +{ + return -1; +} + +bool QSmoothedAnimation::recalc() +{ + s = to - initialValue; + vi = initialVelocity; + + s = (invert? -1.0: 1.0) * s; + + if (userDuration > 0 && velocity > 0) { + tf = s / velocity; + if (tf > (userDuration / 1000.)) tf = (userDuration / 1000.); + } else if (userDuration > 0) { + tf = userDuration / 1000.; + } else if (velocity > 0) { + tf = s / velocity; + } else { + return false; + } + + finalDuration = ceil(tf * 1000.0); + + if (maximumEasingTime == 0) { + a = 0; + d = 0; + tp = 0; + td = tf; + vp = velocity; + sp = 0; + sd = s; + } else if (maximumEasingTime != -1 && tf > (maximumEasingTime / 1000.)) { + qreal met = maximumEasingTime / 1000.; + td = tf - met; + + qreal c1 = td; + qreal c2 = (tf - td) * vi - tf * velocity; + qreal c3 = -0.5 * (tf - td) * vi * vi; + + qreal vp1 = (-c2 + sqrt(c2 * c2 - 4 * c1 * c3)) / (2. * c1); + + vp = vp1; + a = vp / met; + d = a; + tp = (vp - vi) / a; + sp = vi * tp + 0.5 * a * tp * tp; + sd = sp + (td - tp) * vp; + } else { + qreal c1 = 0.25 * tf * tf; + qreal c2 = 0.5 * vi * tf - s; + qreal c3 = -0.25 * vi * vi; + + qreal a1 = (-c2 + sqrt(c2 * c2 - 4 * c1 * c3)) / (2. * c1); + + qreal tp1 = 0.5 * tf - 0.5 * vi / a1; + qreal vp1 = a1 * tp1 + vi; + + qreal sp1 = 0.5 * a1 * tp1 * tp1 + vi * tp1; + + a = a1; + d = a1; + tp = tp1; + td = tp1; + vp = vp1; + sp = sp1; + sd = sp1; + } + return true; +} + +qreal QSmoothedAnimation::easeFollow(qreal time_seconds) +{ + qreal value; + if (time_seconds < tp) { + trackVelocity = vi + time_seconds * a; + value = 0.5 * a * time_seconds * time_seconds + vi * time_seconds; + } else if (time_seconds < td) { + time_seconds -= tp; + trackVelocity = vp; + value = sp + time_seconds * vp; + } else if (time_seconds < tf) { + time_seconds -= td; + trackVelocity = vp - time_seconds * a; + value = sd - 0.5 * d * time_seconds * time_seconds + vp * time_seconds; + } else { + trackVelocity = 0; + value = s; + delayedStop(); + } + + // to normalize 's' between [0..1], divide 'value' by 's' + return value; +} + +void QSmoothedAnimation::updateCurrentTime(int t) +{ + qreal time_seconds = qreal(t - lastTime) / 1000.; + + qreal value = easeFollow(time_seconds); + value *= (invert? -1.0: 1.0); + QDeclarativePropertyPrivate::write(target, initialValue + value, + QDeclarativePropertyPrivate::BypassInterceptor + | QDeclarativePropertyPrivate::DontRemoveBinding); +} + +void QSmoothedAnimation::init() +{ + if (velocity == 0) { + stop(); + return; + } + + if (delayedStopTimer.isActive()) + delayedStopTimer.stop(); + + initialValue = target.read().toReal(); + lastTime = this->currentTime(); + + if (to == initialValue) { + stop(); + return; + } + + bool hasReversed = trackVelocity != 0. && + ((trackVelocity > 0) == ((initialValue - to) > 0)); + + if (hasReversed) { + switch (reversingMode) { + default: + case QDeclarativeSmoothedAnimation::Eased: + break; + case QDeclarativeSmoothedAnimation::Sync: + QDeclarativePropertyPrivate::write(target, to, + QDeclarativePropertyPrivate::BypassInterceptor + | QDeclarativePropertyPrivate::DontRemoveBinding); + return; + case QDeclarativeSmoothedAnimation::Immediate: + initialVelocity = 0; + delayedStop(); + break; + } + } + + trackVelocity = initialVelocity; + + invert = (to < initialValue); + + if (!recalc()) { + QDeclarativePropertyPrivate::write(target, to, + QDeclarativePropertyPrivate::BypassInterceptor + | QDeclarativePropertyPrivate::DontRemoveBinding); + stop(); + return; + } +} + +/*! + \qmlclass SmoothedAnimation QDeclarativeSmoothedAnimation + \since 4.7 + \brief The SmoothedAnimation element allows a property to smoothly track a value. + + The SmoothedAnimation smoothly animates a property's value to a set target value + using an ease in/out quad easing curve. If the animation is restarted + with a different target value, the easing curves used to animate to the old + and the new target values are spliced together to avoid any obvious visual + glitches. + + The property animation is configured by setting the velocity at which the + animation should occur, or the duration that the animation should take. + If both a velocity and a duration are specified, the one that results in + the quickest animation is chosen for each change in the target value. + + For example, animating from 0 to 800 will take 4 seconds if a velocity + of 200 is set, will take 8 seconds with a duration of 8000 set, and will + take 4 seconds with both a velocity of 200 and a duration of 8000 set. + Animating from 0 to 20000 will take 10 seconds if a velocity of 200 is set, + will take 8 seconds with a duration of 8000 set, and will take 8 seconds + with both a velocity of 200 and a duration of 8000 set. + + The follow example shows one rectangle tracking the position of another. +\code +import Qt 4.6 + +Rectangle { + width: 800; height: 600; color: "blue" + + Rectangle { + color: "green" + width: 60; height: 60; + x: rect1.x - 5; y: rect1.y - 5; + Behavior on x { SmoothedAnimation { velocity: 200 } } + Behavior on y { SmoothedAnimation { velocity: 200 } } + } + + Rectangle { + id: rect1 + color: "red" + width: 50; height: 50; + } + + focus: true + Keys.onRightPressed: rect1.x = rect1.x + 100 + Keys.onLeftPressed: rect1.x = rect1.x - 100 + Keys.onUpPressed: rect1.y = rect1.y - 100 + Keys.onDownPressed: rect1.y = rect1.y + 100 +} +\endcode + + The default velocity of SmoothedAnimation is 200 units/second. Note that if the range of the + value being animated is small, then the velocity will need to be adjusted + appropriately. For example, the opacity of an item ranges from 0 - 1.0. + To enable a smooth animation in this range the velocity will need to be + set to a value such as 0.5 units/second. Animating from 0 to 1.0 with a velocity + of 0.5 will take 2000 ms to complete. + + \sa SpringFollow +*/ + +QDeclarativeSmoothedAnimation::QDeclarativeSmoothedAnimation(QObject *parent) +: QDeclarativeNumberAnimation(*(new QDeclarativeSmoothedAnimationPrivate), parent) +{ +} + +QDeclarativeSmoothedAnimation::~QDeclarativeSmoothedAnimation() +{ +} + +QDeclarativeSmoothedAnimationPrivate::QDeclarativeSmoothedAnimationPrivate() + : wrapperGroup(new QParallelAnimationGroup), anim(new QSmoothedAnimation) +{ + Q_Q(QDeclarativeSmoothedAnimation); + QDeclarative_setParent_noEvent(wrapperGroup, q); + QDeclarative_setParent_noEvent(anim, q); +} + +QAbstractAnimation* QDeclarativeSmoothedAnimation::qtAnimation() +{ + Q_D(QDeclarativeSmoothedAnimation); + return d->wrapperGroup; +} + +void QDeclarativeSmoothedAnimation::transition(QDeclarativeStateActions &actions, + QDeclarativeProperties &modified, + TransitionDirection direction) +{ + Q_D(QDeclarativeSmoothedAnimation); + QDeclarativeNumberAnimation::transition(actions, modified, direction); + + if (!d->actions) + return; + + QSet anims; + for (int i = 0; i < d->actions->size(); i++) { + QSmoothedAnimation *ease; + qreal trackVelocity; + bool needsRestart; + if (!d->activeAnimations.contains((*d->actions)[i].property)) { + ease = new QSmoothedAnimation(); + d->wrapperGroup->addAnimation(ease); + d->activeAnimations.insert((*d->actions)[i].property, ease); + trackVelocity = 0.0; + needsRestart = false; + } else { + ease = d->activeAnimations.value((*d->actions)[i].property); + trackVelocity = ease->trackVelocity; + needsRestart = true; + } + + ease->target = (*d->actions)[i].property; + ease->to = (*d->actions)[i].toValue.toReal(); + + // copying public members from main value holder animation + ease->maximumEasingTime = d->anim->maximumEasingTime; + ease->reversingMode = d->anim->reversingMode; + ease->velocity = d->anim->velocity; + ease->userDuration = d->anim->userDuration; + + ease->trackVelocity = trackVelocity; + ease->initialVelocity = trackVelocity; + + if (needsRestart) + ease->init(); + anims.insert(ease); + } + + for (int i = d->wrapperGroup->animationCount() - 1; i >= 0 ; --i) { + if (!anims.contains(d->wrapperGroup->animationAt(i))) { + QSmoothedAnimation *ease = static_cast(d->wrapperGroup->animationAt(i)); + d->activeAnimations.remove(ease->target); + d->wrapperGroup->takeAnimation(i); + delete ease; + } + } +} + +/*! + \qmlproperty enumeration SmoothedAnimation::reversingMode + + Sets how the SmoothedAnimation behaves if an animation direction is reversed. + + If reversing mode is \c Eased, the animation will smoothly decelerate, and + then reverse direction. If the reversing mode is \c Immediate, the + animation will immediately begin accelerating in the reverse direction, + begining with a velocity of 0. If the reversing mode is \c Sync, the + property is immediately set to the target value. +*/ +QDeclarativeSmoothedAnimation::ReversingMode QDeclarativeSmoothedAnimation::reversingMode() const +{ + Q_D(const QDeclarativeSmoothedAnimation); + return (QDeclarativeSmoothedAnimation::ReversingMode) d->anim->reversingMode; +} + +void QDeclarativeSmoothedAnimation::setReversingMode(ReversingMode m) +{ + Q_D(QDeclarativeSmoothedAnimation); + if (d->anim->reversingMode == m) + return; + + d->anim->reversingMode = m; + emit reversingModeChanged(); +} + +/*! + \qmlproperty int SmoothedAnimation::duration + + This property holds the animation duration, in msecs, used when tracking the source. + + Setting this to -1 (the default) disables the duration value. +*/ +int QDeclarativeSmoothedAnimation::duration() const +{ + Q_D(const QDeclarativeSmoothedAnimation); + return d->anim->userDuration; +} + +void QDeclarativeSmoothedAnimation::setDuration(int duration) +{ + Q_D(QDeclarativeSmoothedAnimation); + if (duration != -1) + QDeclarativeNumberAnimation::setDuration(duration); + d->anim->userDuration = duration; +} + +qreal QDeclarativeSmoothedAnimation::velocity() const +{ + Q_D(const QDeclarativeSmoothedAnimation); + return d->anim->velocity; +} + +/*! + \qmlproperty qreal SmoothedAnimation::velocity + + This property holds the average velocity allowed when tracking the 'to' value. + + The default velocity of SmoothedAnimation is 200 units/second. + + Setting this to -1 disables the velocity value. +*/ +void QDeclarativeSmoothedAnimation::setVelocity(qreal v) +{ + Q_D(QDeclarativeSmoothedAnimation); + if (d->anim->velocity == v) + return; + + d->anim->velocity = v; + emit velocityChanged(); +} + +/*! +\qmlproperty qreal SmoothedAnimation::maximumEasingTime + +This property specifies the maximum time, in msecs, an "eases" during the follow should take. +Setting this property causes the velocity to "level out" after at a time. Setting +a negative value reverts to the normal mode of easing over the entire animation +duration. + +The default value is -1. +*/ +int QDeclarativeSmoothedAnimation::maximumEasingTime() const +{ + Q_D(const QDeclarativeSmoothedAnimation); + return d->anim->maximumEasingTime; +} + +void QDeclarativeSmoothedAnimation::setMaximumEasingTime(int v) +{ + Q_D(QDeclarativeSmoothedAnimation); + d->anim->maximumEasingTime = v; + emit maximumEasingTimeChanged(); +} + +QT_END_NAMESPACE diff --git a/src/declarative/util/qdeclarativesmoothedanimation_p.h b/src/declarative/util/qdeclarativesmoothedanimation_p.h new file mode 100644 index 0000000..50ed00c --- /dev/null +++ b/src/declarative/util/qdeclarativesmoothedanimation_p.h @@ -0,0 +1,104 @@ +/**************************************************************************** +** +** 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 QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVESMOOTHEDANIMATION_H +#define QDECLARATIVESMOOTHEDANIMATION_H + +#include +#include "qdeclarativeanimation_p.h" + +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +class QDeclarativeProperty; +class QDeclarativeSmoothedAnimationPrivate; +class Q_DECLARATIVE_EXPORT QDeclarativeSmoothedAnimation : public QDeclarativeNumberAnimation +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QDeclarativeSmoothedAnimation) + Q_ENUMS(ReversingMode) + + Q_PROPERTY(qreal velocity READ velocity WRITE setVelocity NOTIFY velocityChanged) + Q_PROPERTY(ReversingMode reversingMode READ reversingMode WRITE setReversingMode NOTIFY reversingModeChanged) + Q_PROPERTY(qreal maximumEasingTime READ maximumEasingTime WRITE setMaximumEasingTime NOTIFY maximumEasingTimeChanged) + +public: + enum ReversingMode { Eased, Immediate, Sync }; + + QDeclarativeSmoothedAnimation(QObject *parent = 0); + ~QDeclarativeSmoothedAnimation(); + + ReversingMode reversingMode() const; + void setReversingMode(ReversingMode); + + virtual int duration() const; + virtual void setDuration(int); + + qreal velocity() const; + void setVelocity(qreal); + + int maximumEasingTime() const; + void setMaximumEasingTime(int); + +public: + virtual void transition(QDeclarativeStateActions &actions, + QDeclarativeProperties &modified, + TransitionDirection direction); + QAbstractAnimation* qtAnimation(); + +Q_SIGNALS: + void velocityChanged(); + void reversingModeChanged(); + void maximumEasingTimeChanged(); +}; + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QDeclarativeSmoothedAnimation); + +QT_END_HEADER + +#endif // QDECLARATIVESMOOTHEDANIMATION_H diff --git a/src/declarative/util/qdeclarativesmoothedanimation_p_p.h b/src/declarative/util/qdeclarativesmoothedanimation_p_p.h new file mode 100644 index 0000000..bdceeb3 --- /dev/null +++ b/src/declarative/util/qdeclarativesmoothedanimation_p_p.h @@ -0,0 +1,134 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVESMOOTHEDANIMATION_P_H +#define QDECLARATIVESMOOTHEDANIMATION_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qdeclarativesmoothedanimation_p.h" +#include "qdeclarativeanimation_p.h" + +#include "qdeclarativeanimation_p_p.h" + +#include + +#include +#include + +QT_BEGIN_NAMESPACE + +class QSmoothedAnimation : public QAbstractAnimation +{ +public: + QSmoothedAnimation(QObject *parent=0); + + qreal to; + qreal velocity; + int userDuration; + + int maximumEasingTime; + QDeclarativeSmoothedAnimation::ReversingMode reversingMode; + + qreal initialVelocity; + qreal trackVelocity; + + QDeclarativeProperty target; + + int duration() const; + void restart(); + void init(); + +protected: + virtual void updateCurrentTime(int); + virtual void updateState(QAbstractAnimation::State, QAbstractAnimation::State); + +private: + qreal easeFollow(qreal); + qreal initialValue; + + bool invert; + + int finalDuration; + + // Parameters for use in updateCurrentTime() + qreal a; // Acceleration + qreal d; // Deceleration + qreal tf; // Total time + qreal tp; // Time at which peak velocity occurs + qreal td; // Time at which decelleration begins + qreal vp; // Velocity at tp + qreal sp; // Displacement at tp + qreal sd; // Displacement at td + qreal vi; // "Normalized" initialvelocity + qreal s; // Total s + + int lastTime; + + bool recalc(); + void delayedStop(); + + QTimer delayedStopTimer; +}; + +class QDeclarativeSmoothedAnimationPrivate : public QDeclarativePropertyAnimationPrivate +{ + Q_DECLARE_PUBLIC(QDeclarativeSmoothedAnimation) +public: + QDeclarativeSmoothedAnimationPrivate(); + + QParallelAnimationGroup *wrapperGroup; + QSmoothedAnimation *anim; + QHash activeAnimations; +}; + +QT_END_NAMESPACE + +#endif // QDECLARATIVESMOOTHEDANIMATION_P_H diff --git a/src/declarative/util/qdeclarativeutilmodule.cpp b/src/declarative/util/qdeclarativeutilmodule.cpp index bf50a8b..7f2f64a 100644 --- a/src/declarative/util/qdeclarativeutilmodule.cpp +++ b/src/declarative/util/qdeclarativeutilmodule.cpp @@ -45,7 +45,7 @@ #include "qdeclarativebehavior_p.h" #include "qdeclarativebind_p.h" #include "qdeclarativeconnections_p.h" -#include "qdeclarativeeasefollow_p.h" +#include "qdeclarativesmoothedanimation_p.h" #include "qdeclarativefontloader_p.h" #include "qdeclarativelistaccessor_p.h" #include "qdeclarativelistmodel_p.h" diff --git a/src/declarative/util/util.pri b/src/declarative/util/util.pri index 249465a..4163596 100644 --- a/src/declarative/util/util.pri +++ b/src/declarative/util/util.pri @@ -8,7 +8,7 @@ SOURCES += \ $$PWD/qdeclarativeanimation.cpp \ $$PWD/qdeclarativesystempalette.cpp \ $$PWD/qdeclarativespringfollow.cpp \ - $$PWD/qdeclarativeeasefollow.cpp \ + $$PWD/qdeclarativesmoothedanimation.cpp \ $$PWD/qdeclarativestate.cpp\ $$PWD/qdeclarativetransitionmanager.cpp \ $$PWD/qdeclarativestateoperations.cpp \ @@ -37,8 +37,8 @@ HEADERS += \ $$PWD/qdeclarativeanimation_p_p.h \ $$PWD/qdeclarativesystempalette_p.h \ $$PWD/qdeclarativespringfollow_p.h \ - $$PWD/qdeclarativeeasefollow_p.h \ - $$PWD/qdeclarativeeasefollow_p_p.h \ + $$PWD/qdeclarativesmoothedanimation_p.h \ + $$PWD/qdeclarativesmoothedanimation_p_p.h \ $$PWD/qdeclarativestate_p.h\ $$PWD/qdeclarativestateoperations_p.h \ $$PWD/qdeclarativepropertychanges_p.h \ diff --git a/tests/auto/declarative/declarative.pro b/tests/auto/declarative/declarative.pro index 6c5a75f..bebc54e 100644 --- a/tests/auto/declarative/declarative.pro +++ b/tests/auto/declarative/declarative.pro @@ -13,7 +13,6 @@ SUBDIRS += \ qdeclarativedebugclient \ # Cover qdeclarativedebugservice \ # Cover qdeclarativedom \ # Cover - qdeclarativeeasefollow \ # Cover qdeclarativeecmascript \ # Cover qdeclarativeengine \ # Cover qdeclarativeerror \ # Cover @@ -47,6 +46,7 @@ SUBDIRS += \ qdeclarativepixmapcache \ # Cover qdeclarativepropertymap \ # Cover qdeclarativeqt \ # Cover + qdeclarativesmoothedanimation \ # Cover qdeclarativespringfollow \ # Cover qdeclarativestates \ # Cover qdeclarativesystempalette \ # Cover diff --git a/tests/auto/declarative/qdeclarativeeasefollow/data/easefollow1.qml b/tests/auto/declarative/qdeclarativeeasefollow/data/easefollow1.qml deleted file mode 100644 index cfece41..0000000 --- a/tests/auto/declarative/qdeclarativeeasefollow/data/easefollow1.qml +++ /dev/null @@ -1,3 +0,0 @@ -import Qt 4.6 - -SmoothedAnimation {} diff --git a/tests/auto/declarative/qdeclarativeeasefollow/data/easefollow2.qml b/tests/auto/declarative/qdeclarativeeasefollow/data/easefollow2.qml deleted file mode 100644 index 74a110d..0000000 --- a/tests/auto/declarative/qdeclarativeeasefollow/data/easefollow2.qml +++ /dev/null @@ -1,5 +0,0 @@ -import Qt 4.6 - -SmoothedAnimation { - to: 10; duration: 300; reversingMode: SmoothedAnimation.Immediate -} diff --git a/tests/auto/declarative/qdeclarativeeasefollow/data/easefollow3.qml b/tests/auto/declarative/qdeclarativeeasefollow/data/easefollow3.qml deleted file mode 100644 index 3111e82..0000000 --- a/tests/auto/declarative/qdeclarativeeasefollow/data/easefollow3.qml +++ /dev/null @@ -1,6 +0,0 @@ -import Qt 4.6 - -SmoothedAnimation { - to: 10; velocity: 250; reversingMode: SmoothedAnimation.Sync - maximumEasingTime: 150 -} diff --git a/tests/auto/declarative/qdeclarativeeasefollow/data/easefollowBehavior.qml b/tests/auto/declarative/qdeclarativeeasefollow/data/easefollowBehavior.qml deleted file mode 100644 index eb06344..0000000 --- a/tests/auto/declarative/qdeclarativeeasefollow/data/easefollowBehavior.qml +++ /dev/null @@ -1,23 +0,0 @@ -import Qt 4.6 - -Rectangle { - width: 400; height: 400; color: "blue" - - Rectangle { - id: rect1 - color: "red" - width: 60; height: 60; - x: 100; y: 100; - SmoothedAnimation on x { to: 200; velocity: 500 } - SmoothedAnimation on y { to: 200; velocity: 500 } - } - - Rectangle { - objectName: "theRect" - color: "green" - width: 60; height: 60; - x: rect1.x; y: rect1.y; - Behavior on x { SmoothedAnimation { objectName: "easeX"; velocity: 400 } } - Behavior on y { SmoothedAnimation { objectName: "easeY"; velocity: 400 } } - } - } diff --git a/tests/auto/declarative/qdeclarativeeasefollow/data/easefollowValueSource.qml b/tests/auto/declarative/qdeclarativeeasefollow/data/easefollowValueSource.qml deleted file mode 100644 index 9ae744c..0000000 --- a/tests/auto/declarative/qdeclarativeeasefollow/data/easefollowValueSource.qml +++ /dev/null @@ -1,13 +0,0 @@ -import Qt 4.6 - -Rectangle { - width: 300; height: 300; - Rectangle { - objectName: "theRect" - color: "red" - width: 60; height: 60; - x: 100; y: 100; - SmoothedAnimation on x { objectName: "easeX"; to: 200; velocity: 500 } - SmoothedAnimation on y { objectName: "easeY"; to: 200; duration: 250; velocity: 500 } - } -} diff --git a/tests/auto/declarative/qdeclarativeeasefollow/qdeclarativeeasefollow.pro b/tests/auto/declarative/qdeclarativeeasefollow/qdeclarativeeasefollow.pro deleted file mode 100644 index 71df4f4..0000000 --- a/tests/auto/declarative/qdeclarativeeasefollow/qdeclarativeeasefollow.pro +++ /dev/null @@ -1,8 +0,0 @@ -load(qttest_p4) -contains(QT_CONFIG,declarative): QT += declarative gui -macx:CONFIG -= app_bundle - -SOURCES += tst_qdeclarativeeasefollow.cpp - -# Define SRCDIR equal to test's source directory -DEFINES += SRCDIR=\\\"$$PWD\\\" diff --git a/tests/auto/declarative/qdeclarativeeasefollow/tst_qdeclarativeeasefollow.cpp b/tests/auto/declarative/qdeclarativeeasefollow/tst_qdeclarativeeasefollow.cpp deleted file mode 100644 index 401688b..0000000 --- a/tests/auto/declarative/qdeclarativeeasefollow/tst_qdeclarativeeasefollow.cpp +++ /dev/null @@ -1,207 +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 test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -** -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ -#include -#include -#include -#include -#include -#include -#include "../../../shared/util.h" - -class tst_qdeclarativeeasefollow : public QObject -{ - Q_OBJECT -public: - tst_qdeclarativeeasefollow(); - -private slots: - void defaultValues(); - void values(); - void disabled(); - void simpleAnimation(); - void valueSource(); - void behavior(); - -private: - QDeclarativeEngine engine; -}; - -tst_qdeclarativeeasefollow::tst_qdeclarativeeasefollow() -{ -} - -void tst_qdeclarativeeasefollow::defaultValues() -{ - QDeclarativeEngine engine; - QDeclarativeComponent c(&engine, QUrl::fromLocalFile(SRCDIR "/data/easefollow1.qml")); - QDeclarativeSmoothedAnimation *obj = qobject_cast(c.create()); - - QVERIFY(obj != 0); - - QCOMPARE(obj->to(), 0.); - QCOMPARE(obj->velocity(), 200.); - QCOMPARE(obj->duration(), -1); - QCOMPARE(obj->maximumEasingTime(), -1); - QCOMPARE(obj->reversingMode(), QDeclarativeSmoothedAnimation::Eased); - - delete obj; -} - -void tst_qdeclarativeeasefollow::values() -{ - QDeclarativeEngine engine; - QDeclarativeComponent c(&engine, QUrl::fromLocalFile(SRCDIR "/data/easefollow2.qml")); - QDeclarativeSmoothedAnimation *obj = qobject_cast(c.create()); - - QVERIFY(obj != 0); - - QCOMPARE(obj->to(), 10.); - QCOMPARE(obj->velocity(), 200.); - QCOMPARE(obj->duration(), 300); - QCOMPARE(obj->maximumEasingTime(), -1); - QCOMPARE(obj->reversingMode(), QDeclarativeSmoothedAnimation::Immediate); - - delete obj; -} - -void tst_qdeclarativeeasefollow::disabled() -{ - QDeclarativeEngine engine; - QDeclarativeComponent c(&engine, QUrl::fromLocalFile(SRCDIR "/data/easefollow3.qml")); - QDeclarativeSmoothedAnimation *obj = qobject_cast(c.create()); - - QVERIFY(obj != 0); - - QCOMPARE(obj->to(), 10.); - QCOMPARE(obj->velocity(), 250.); - QCOMPARE(obj->maximumEasingTime(), 150); - QCOMPARE(obj->reversingMode(), QDeclarativeSmoothedAnimation::Sync); - - delete obj; -} - -void tst_qdeclarativeeasefollow::simpleAnimation() -{ - QDeclarativeRectangle rect; - QDeclarativeSmoothedAnimation animation; - animation.setTarget(&rect); - animation.setProperty("x"); - animation.setTo(200); - animation.setDuration(250); - QVERIFY(animation.target() == &rect); - QVERIFY(animation.property() == "x"); - QVERIFY(animation.to() == 200); - animation.start(); - QVERIFY(animation.isRunning()); - QTest::qWait(animation.duration()); - QTRY_COMPARE(rect.x(), qreal(200)); - - rect.setX(0); - animation.start(); - animation.pause(); - QVERIFY(animation.isRunning()); - QVERIFY(animation.isPaused()); - animation.setCurrentTime(125); - QVERIFY(animation.currentTime() == 125); - QCOMPARE(rect.x(), qreal(100)); -} - -void tst_qdeclarativeeasefollow::valueSource() -{ - QDeclarativeEngine engine; - - QDeclarativeComponent c(&engine, QUrl::fromLocalFile(SRCDIR "/data/easefollowValueSource.qml")); - - QDeclarativeRectangle *rect = qobject_cast(c.create()); - QVERIFY(rect); - - QDeclarativeRectangle *theRect = rect->findChild("theRect"); - QVERIFY(theRect); - - QDeclarativeSmoothedAnimation *easeX = rect->findChild("easeX"); - QVERIFY(easeX); - QVERIFY(easeX->isRunning()); - - QDeclarativeSmoothedAnimation *easeY = rect->findChild("easeY"); - QVERIFY(easeY); - QVERIFY(easeY->isRunning()); - - // XXX get the proper duration - QTest::qWait(100); - - QTRY_VERIFY(!easeX->isRunning()); - QTRY_VERIFY(!easeY->isRunning()); - - QTRY_COMPARE(theRect->x(), qreal(200)); - QTRY_COMPARE(theRect->y(), qreal(200)); -} - -void tst_qdeclarativeeasefollow::behavior() -{ - QDeclarativeEngine engine; - - QDeclarativeComponent c(&engine, QUrl::fromLocalFile(SRCDIR "/data/easefollowBehavior.qml")); - - QDeclarativeRectangle *rect = qobject_cast(c.create()); - QVERIFY(rect); - - QDeclarativeRectangle *theRect = rect->findChild("theRect"); - QVERIFY(theRect); - - QDeclarativeSmoothedAnimation *easeX = rect->findChild("easeX"); - QVERIFY(easeX); - - QDeclarativeSmoothedAnimation *easeY = rect->findChild("easeY"); - QVERIFY(easeY); - - // XXX get the proper duration - QTest::qWait(400); - - QTRY_VERIFY(!easeX->isRunning()); - QTRY_VERIFY(!easeY->isRunning()); - - QTRY_COMPARE(theRect->x(), qreal(200)); - QTRY_COMPARE(theRect->y(), qreal(200)); -} - -QTEST_MAIN(tst_qdeclarativeeasefollow) - -#include "tst_qdeclarativeeasefollow.moc" diff --git a/tests/auto/declarative/qdeclarativesmoothedanimation/data/smoothedanimation1.qml b/tests/auto/declarative/qdeclarativesmoothedanimation/data/smoothedanimation1.qml new file mode 100644 index 0000000..cfece41 --- /dev/null +++ b/tests/auto/declarative/qdeclarativesmoothedanimation/data/smoothedanimation1.qml @@ -0,0 +1,3 @@ +import Qt 4.6 + +SmoothedAnimation {} diff --git a/tests/auto/declarative/qdeclarativesmoothedanimation/data/smoothedanimation2.qml b/tests/auto/declarative/qdeclarativesmoothedanimation/data/smoothedanimation2.qml new file mode 100644 index 0000000..74a110d --- /dev/null +++ b/tests/auto/declarative/qdeclarativesmoothedanimation/data/smoothedanimation2.qml @@ -0,0 +1,5 @@ +import Qt 4.6 + +SmoothedAnimation { + to: 10; duration: 300; reversingMode: SmoothedAnimation.Immediate +} diff --git a/tests/auto/declarative/qdeclarativesmoothedanimation/data/smoothedanimation3.qml b/tests/auto/declarative/qdeclarativesmoothedanimation/data/smoothedanimation3.qml new file mode 100644 index 0000000..3111e82 --- /dev/null +++ b/tests/auto/declarative/qdeclarativesmoothedanimation/data/smoothedanimation3.qml @@ -0,0 +1,6 @@ +import Qt 4.6 + +SmoothedAnimation { + to: 10; velocity: 250; reversingMode: SmoothedAnimation.Sync + maximumEasingTime: 150 +} diff --git a/tests/auto/declarative/qdeclarativesmoothedanimation/data/smoothedanimationBehavior.qml b/tests/auto/declarative/qdeclarativesmoothedanimation/data/smoothedanimationBehavior.qml new file mode 100644 index 0000000..eb06344 --- /dev/null +++ b/tests/auto/declarative/qdeclarativesmoothedanimation/data/smoothedanimationBehavior.qml @@ -0,0 +1,23 @@ +import Qt 4.6 + +Rectangle { + width: 400; height: 400; color: "blue" + + Rectangle { + id: rect1 + color: "red" + width: 60; height: 60; + x: 100; y: 100; + SmoothedAnimation on x { to: 200; velocity: 500 } + SmoothedAnimation on y { to: 200; velocity: 500 } + } + + Rectangle { + objectName: "theRect" + color: "green" + width: 60; height: 60; + x: rect1.x; y: rect1.y; + Behavior on x { SmoothedAnimation { objectName: "easeX"; velocity: 400 } } + Behavior on y { SmoothedAnimation { objectName: "easeY"; velocity: 400 } } + } + } diff --git a/tests/auto/declarative/qdeclarativesmoothedanimation/data/smoothedanimationValueSource.qml b/tests/auto/declarative/qdeclarativesmoothedanimation/data/smoothedanimationValueSource.qml new file mode 100644 index 0000000..9ae744c --- /dev/null +++ b/tests/auto/declarative/qdeclarativesmoothedanimation/data/smoothedanimationValueSource.qml @@ -0,0 +1,13 @@ +import Qt 4.6 + +Rectangle { + width: 300; height: 300; + Rectangle { + objectName: "theRect" + color: "red" + width: 60; height: 60; + x: 100; y: 100; + SmoothedAnimation on x { objectName: "easeX"; to: 200; velocity: 500 } + SmoothedAnimation on y { objectName: "easeY"; to: 200; duration: 250; velocity: 500 } + } +} diff --git a/tests/auto/declarative/qdeclarativesmoothedanimation/qdeclarativesmoothedanimation.pro b/tests/auto/declarative/qdeclarativesmoothedanimation/qdeclarativesmoothedanimation.pro new file mode 100644 index 0000000..b41b23a --- /dev/null +++ b/tests/auto/declarative/qdeclarativesmoothedanimation/qdeclarativesmoothedanimation.pro @@ -0,0 +1,8 @@ +load(qttest_p4) +contains(QT_CONFIG,declarative): QT += declarative gui +macx:CONFIG -= app_bundle + +SOURCES += tst_qdeclarativesmoothedanimation.cpp + +# Define SRCDIR equal to test's source directory +DEFINES += SRCDIR=\\\"$$PWD\\\" diff --git a/tests/auto/declarative/qdeclarativesmoothedanimation/tst_qdeclarativesmoothedanimation.cpp b/tests/auto/declarative/qdeclarativesmoothedanimation/tst_qdeclarativesmoothedanimation.cpp new file mode 100644 index 0000000..7cf318a --- /dev/null +++ b/tests/auto/declarative/qdeclarativesmoothedanimation/tst_qdeclarativesmoothedanimation.cpp @@ -0,0 +1,207 @@ +/**************************************************************************** +** +** 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 test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include +#include +#include +#include +#include +#include +#include "../../../shared/util.h" + +class tst_qdeclarativesmoothedanimation : public QObject +{ + Q_OBJECT +public: + tst_qdeclarativesmoothedanimation(); + +private slots: + void defaultValues(); + void values(); + void disabled(); + void simpleAnimation(); + void valueSource(); + void behavior(); + +private: + QDeclarativeEngine engine; +}; + +tst_qdeclarativesmoothedanimation::tst_qdeclarativesmoothedanimation() +{ +} + +void tst_qdeclarativesmoothedanimation::defaultValues() +{ + QDeclarativeEngine engine; + QDeclarativeComponent c(&engine, QUrl::fromLocalFile(SRCDIR "/data/smoothedanimation1.qml")); + QDeclarativeSmoothedAnimation *obj = qobject_cast(c.create()); + + QVERIFY(obj != 0); + + QCOMPARE(obj->to(), 0.); + QCOMPARE(obj->velocity(), 200.); + QCOMPARE(obj->duration(), -1); + QCOMPARE(obj->maximumEasingTime(), -1); + QCOMPARE(obj->reversingMode(), QDeclarativeSmoothedAnimation::Eased); + + delete obj; +} + +void tst_qdeclarativesmoothedanimation::values() +{ + QDeclarativeEngine engine; + QDeclarativeComponent c(&engine, QUrl::fromLocalFile(SRCDIR "/data/smoothedanimation2.qml")); + QDeclarativeSmoothedAnimation *obj = qobject_cast(c.create()); + + QVERIFY(obj != 0); + + QCOMPARE(obj->to(), 10.); + QCOMPARE(obj->velocity(), 200.); + QCOMPARE(obj->duration(), 300); + QCOMPARE(obj->maximumEasingTime(), -1); + QCOMPARE(obj->reversingMode(), QDeclarativeSmoothedAnimation::Immediate); + + delete obj; +} + +void tst_qdeclarativesmoothedanimation::disabled() +{ + QDeclarativeEngine engine; + QDeclarativeComponent c(&engine, QUrl::fromLocalFile(SRCDIR "/data/smoothedanimation3.qml")); + QDeclarativeSmoothedAnimation *obj = qobject_cast(c.create()); + + QVERIFY(obj != 0); + + QCOMPARE(obj->to(), 10.); + QCOMPARE(obj->velocity(), 250.); + QCOMPARE(obj->maximumEasingTime(), 150); + QCOMPARE(obj->reversingMode(), QDeclarativeSmoothedAnimation::Sync); + + delete obj; +} + +void tst_qdeclarativesmoothedanimation::simpleAnimation() +{ + QDeclarativeRectangle rect; + QDeclarativeSmoothedAnimation animation; + animation.setTarget(&rect); + animation.setProperty("x"); + animation.setTo(200); + animation.setDuration(250); + QVERIFY(animation.target() == &rect); + QVERIFY(animation.property() == "x"); + QVERIFY(animation.to() == 200); + animation.start(); + QVERIFY(animation.isRunning()); + QTest::qWait(animation.duration()); + QTRY_COMPARE(rect.x(), qreal(200)); + + rect.setX(0); + animation.start(); + animation.pause(); + QVERIFY(animation.isRunning()); + QVERIFY(animation.isPaused()); + animation.setCurrentTime(125); + QVERIFY(animation.currentTime() == 125); + QCOMPARE(rect.x(), qreal(100)); +} + +void tst_qdeclarativesmoothedanimation::valueSource() +{ + QDeclarativeEngine engine; + + QDeclarativeComponent c(&engine, QUrl::fromLocalFile(SRCDIR "/data/smoothedanimationValueSource.qml")); + + QDeclarativeRectangle *rect = qobject_cast(c.create()); + QVERIFY(rect); + + QDeclarativeRectangle *theRect = rect->findChild("theRect"); + QVERIFY(theRect); + + QDeclarativeSmoothedAnimation *easeX = rect->findChild("easeX"); + QVERIFY(easeX); + QVERIFY(easeX->isRunning()); + + QDeclarativeSmoothedAnimation *easeY = rect->findChild("easeY"); + QVERIFY(easeY); + QVERIFY(easeY->isRunning()); + + // XXX get the proper duration + QTest::qWait(100); + + QTRY_VERIFY(!easeX->isRunning()); + QTRY_VERIFY(!easeY->isRunning()); + + QTRY_COMPARE(theRect->x(), qreal(200)); + QTRY_COMPARE(theRect->y(), qreal(200)); +} + +void tst_qdeclarativesmoothedanimation::behavior() +{ + QDeclarativeEngine engine; + + QDeclarativeComponent c(&engine, QUrl::fromLocalFile(SRCDIR "/data/smoothedanimationBehavior.qml")); + + QDeclarativeRectangle *rect = qobject_cast(c.create()); + QVERIFY(rect); + + QDeclarativeRectangle *theRect = rect->findChild("theRect"); + QVERIFY(theRect); + + QDeclarativeSmoothedAnimation *easeX = rect->findChild("easeX"); + QVERIFY(easeX); + + QDeclarativeSmoothedAnimation *easeY = rect->findChild("easeY"); + QVERIFY(easeY); + + // XXX get the proper duration + QTest::qWait(400); + + QTRY_VERIFY(!easeX->isRunning()); + QTRY_VERIFY(!easeY->isRunning()); + + QTRY_COMPARE(theRect->x(), qreal(200)); + QTRY_COMPARE(theRect->y(), qreal(200)); +} + +QTEST_MAIN(tst_qdeclarativesmoothedanimation) + +#include "tst_qdeclarativesmoothedanimation.moc" diff --git a/tests/auto/declarative/qmlvisual/qdeclarativeeasefollow/data/easefollow.0.png b/tests/auto/declarative/qmlvisual/qdeclarativeeasefollow/data/easefollow.0.png deleted file mode 100644 index 21b6afb..0000000 Binary files a/tests/auto/declarative/qmlvisual/qdeclarativeeasefollow/data/easefollow.0.png and /dev/null differ diff --git a/tests/auto/declarative/qmlvisual/qdeclarativeeasefollow/data/easefollow.1.png b/tests/auto/declarative/qmlvisual/qdeclarativeeasefollow/data/easefollow.1.png deleted file mode 100644 index bb8a02b..0000000 Binary files a/tests/auto/declarative/qmlvisual/qdeclarativeeasefollow/data/easefollow.1.png and /dev/null differ diff --git a/tests/auto/declarative/qmlvisual/qdeclarativeeasefollow/data/easefollow.2.png b/tests/auto/declarative/qmlvisual/qdeclarativeeasefollow/data/easefollow.2.png deleted file mode 100644 index da60237..0000000 Binary files a/tests/auto/declarative/qmlvisual/qdeclarativeeasefollow/data/easefollow.2.png and /dev/null differ diff --git a/tests/auto/declarative/qmlvisual/qdeclarativeeasefollow/data/easefollow.3.png b/tests/auto/declarative/qmlvisual/qdeclarativeeasefollow/data/easefollow.3.png deleted file mode 100644 index 3e943e8..0000000 Binary files a/tests/auto/declarative/qmlvisual/qdeclarativeeasefollow/data/easefollow.3.png and /dev/null differ diff --git a/tests/auto/declarative/qmlvisual/qdeclarativeeasefollow/data/easefollow.4.png b/tests/auto/declarative/qmlvisual/qdeclarativeeasefollow/data/easefollow.4.png deleted file mode 100644 index 4fbaf26..0000000 Binary files a/tests/auto/declarative/qmlvisual/qdeclarativeeasefollow/data/easefollow.4.png and /dev/null differ diff --git a/tests/auto/declarative/qmlvisual/qdeclarativeeasefollow/data/easefollow.5.png b/tests/auto/declarative/qmlvisual/qdeclarativeeasefollow/data/easefollow.5.png deleted file mode 100644 index c10d196..0000000 Binary files a/tests/auto/declarative/qmlvisual/qdeclarativeeasefollow/data/easefollow.5.png and /dev/null differ diff --git a/tests/auto/declarative/qmlvisual/qdeclarativeeasefollow/data/easefollow.6.png b/tests/auto/declarative/qmlvisual/qdeclarativeeasefollow/data/easefollow.6.png deleted file mode 100644 index a672c06..0000000 Binary files a/tests/auto/declarative/qmlvisual/qdeclarativeeasefollow/data/easefollow.6.png and /dev/null differ diff --git a/tests/auto/declarative/qmlvisual/qdeclarativeeasefollow/data/easefollow.qml b/tests/auto/declarative/qmlvisual/qdeclarativeeasefollow/data/easefollow.qml deleted file mode 100644 index 029a2fc..0000000 --- a/tests/auto/declarative/qmlvisual/qdeclarativeeasefollow/data/easefollow.qml +++ /dev/null @@ -1,1807 +0,0 @@ -import Qt.VisualTest 4.6 - -VisualTest { - Frame { - msec: 0 - } - Frame { - msec: 16 - hash: "1f60efdb8704b92c9361daa468a25391" - } - Frame { - msec: 32 - hash: "3bb6a87617e0e5d4922e573eec975886" - } - Frame { - msec: 48 - hash: "268941737e6324d580890b151de621fb" - } - Frame { - msec: 64 - hash: "99c674eccc082d7f0982257a748d93e5" - } - Frame { - msec: 80 - hash: "2970467e8262c8a3f0b11be71245d048" - } - Frame { - msec: 96 - hash: "63cbd06d6bb035d27c18dba49238d8b2" - } - Frame { - msec: 112 - hash: "49f77bb3d323f882c0ec56e1f1040b3a" - } - Frame { - msec: 128 - hash: "40263c5f9b5d2236536163785f832b4d" - } - Frame { - msec: 144 - hash: "dc63b1c21a2027c4beb9c297a3677fbd" - } - Frame { - msec: 160 - hash: "4fab52ea29a819fec032f19dbcbef012" - } - Frame { - msec: 176 - hash: "60b48407a8f8ae2cce7d3e7c8b21991c" - } - Frame { - msec: 192 - hash: "6e542c681092a5ebeef0534fa2bd2d6c" - } - Frame { - msec: 208 - hash: "c7c6471969bbf81efdb86d1695548fc6" - } - Frame { - msec: 224 - hash: "b7f4ad9a49feb400894209c02b94478a" - } - Frame { - msec: 240 - hash: "3eb58b2f5233aead976183c13f241113" - } - Frame { - msec: 256 - hash: "54f2036c50c6d8079fc0cadc01385980" - } - Frame { - msec: 272 - hash: "f297659d75f6e724d72bd548821f4c9f" - } - Frame { - msec: 288 - hash: "112798f080336fc9c603a7e9097dd8aa" - } - Frame { - msec: 304 - hash: "c432e6ec2b53ca43cb7a7325d0cc379b" - } - Frame { - msec: 320 - hash: "4a6d3db3efd665ad7f372bf3f2508ed7" - } - Frame { - msec: 336 - hash: "0befa5dc4d2cc196fed0eb1a3aa75b8f" - } - Frame { - msec: 352 - hash: "a34d010b50d59c362b54e44d69c2df91" - } - Frame { - msec: 368 - hash: "cbdacced50186c87066ce1d46548b27e" - } - Frame { - msec: 384 - hash: "a4060010ae4d3c0973bda48d68f7bd0a" - } - Frame { - msec: 400 - hash: "47353437da587f732f986004c09884d0" - } - Frame { - msec: 416 - hash: "080c348145167bbec671a04da6f7564f" - } - Frame { - msec: 432 - hash: "69dead737c717a076ae3865680341fb4" - } - Frame { - msec: 448 - hash: "1efdc31c5c8fa72fc848877deb6caaa4" - } - Frame { - msec: 464 - hash: "28d7da1e933d0585d03acf4a529e7b42" - } - Frame { - msec: 480 - hash: "bf85534124bf025b7ede0d6c80b8e443" - } - Frame { - msec: 496 - hash: "cdbeb2d51541b1b1eff060efe993db91" - } - Frame { - msec: 512 - hash: "52ad56ae16c8ab523adda8edc512dd87" - } - Frame { - msec: 528 - hash: "61b1937f4c8dd2cb0ddd7031c5bfb3ab" - } - Frame { - msec: 544 - hash: "1b109baba71b16827f90da654af093a3" - } - Frame { - msec: 560 - hash: "d56621362802c8626868f36ba1e7db22" - } - Frame { - msec: 576 - hash: "ee5555ec3ad8760f43bbf5958a925936" - } - Frame { - msec: 592 - hash: "1ed2831144a453af1978605c0e42d17c" - } - Frame { - msec: 608 - hash: "c74d5cdb3395a702269dfa88c8c9d975" - } - Frame { - msec: 624 - hash: "ea98ddd9588cc23fd82a342ec2925ba8" - } - Frame { - msec: 640 - hash: "e76b94d6d57f1a510f7649eaab892562" - } - Frame { - msec: 656 - hash: "022f40b6fe9dbaf8019855234acb3461" - } - Frame { - msec: 672 - hash: "467da4f48aa6aeb113f0797facf157e8" - } - Frame { - msec: 688 - hash: "8df407aadd4d896eb6537e1555a0242f" - } - Frame { - msec: 704 - hash: "122e4671881e31f54e617729f4fbb3b0" - } - Frame { - msec: 720 - hash: "562718f101c3cd7525b890076413df5e" - } - Frame { - msec: 736 - hash: "07feae99ecf4b70eb094fd3e10deca56" - } - Frame { - msec: 752 - hash: "0980d133b1006cc07796023880415163" - } - Frame { - msec: 768 - hash: "7112b6ac97678b3b942c64c5108f0329" - } - Frame { - msec: 784 - hash: "bb9f893a9aaee60ab6c30918552828a4" - } - Frame { - msec: 800 - hash: "65d1f29437aaaea33676757276f1e434" - } - Frame { - msec: 816 - hash: "52adcf2509f3236ac8ef571708e77206" - } - Frame { - msec: 832 - hash: "22df5e7eda8a813531d0e0366cbfbf64" - } - Frame { - msec: 848 - hash: "fe9b7b7812dd2410b8ed2eb19aa78f4d" - } - Frame { - msec: 864 - hash: "141e22de4469f316b5ef5471f3c7bba0" - } - Frame { - msec: 880 - hash: "1125c0a105fc4a2cae36b798058ce23f" - } - Frame { - msec: 896 - hash: "8c17c5da2ae867fb0016a485ba9e4166" - } - Frame { - msec: 912 - hash: "d8da9fc7ec4dcefb894c5a6a71e9d001" - } - Frame { - msec: 928 - hash: "00ff642bea89fd89de394d78f8c5db33" - } - Frame { - msec: 944 - hash: "8549063d517a3ce1ffd44c56b3b6cf5e" - } - Frame { - msec: 960 - image: "easefollow.0.png" - } - Frame { - msec: 976 - hash: "95a642caa72bb31cc1e04ecc12d07cd0" - } - Frame { - msec: 992 - hash: "e65c823476bf920d0386f62ca831e6a0" - } - Frame { - msec: 1008 - hash: "91e8913dc693c91a674a10b5b088dd8f" - } - Frame { - msec: 1024 - hash: "1a469ffa0d530f72c78dc14783891c78" - } - Frame { - msec: 1040 - hash: "6e46a83d07f8bc034b421103ef0e4f8c" - } - Frame { - msec: 1056 - hash: "8ddacab411a8b73b6c9e69576fa1b003" - } - Frame { - msec: 1072 - hash: "41f419a85fe44efe27c9a526d83a1e9a" - } - Frame { - msec: 1088 - hash: "73d4ece31b258f9caf4556ce20a5be1f" - } - Frame { - msec: 1104 - hash: "ef3ebe0acb50386cf79b9f08fbba2fbc" - } - Frame { - msec: 1120 - hash: "c11a84d2fa80f28adb1466409812e987" - } - Frame { - msec: 1136 - hash: "2e9db854b02d28b38063ff2a8e821ed1" - } - Frame { - msec: 1152 - hash: "48e073c0e6b19aea8314629a2179af87" - } - Frame { - msec: 1168 - hash: "77e518b7428d93b67a8fb0d33d85ed97" - } - Frame { - msec: 1184 - hash: "1d18323af9c62e015513451883f8b39f" - } - Frame { - msec: 1200 - hash: "df49889ba157cdc1ca240d08d2760ad7" - } - Frame { - msec: 1216 - hash: "7b8cd2bcf0a4c38ab870f27894a43d2f" - } - Frame { - msec: 1232 - hash: "84f10e0c9fd57dd1799df7fc34c5ef01" - } - Frame { - msec: 1248 - hash: "ead4e609bc4a0755032b1648485b9625" - } - Frame { - msec: 1264 - hash: "9a9829c3bd4a3a4155383c37e21e8db8" - } - Frame { - msec: 1280 - hash: "5008917f60256abad867f32c1caf954d" - } - Frame { - msec: 1296 - hash: "c21455d66ed0754177af5ce44b7c7600" - } - Frame { - msec: 1312 - hash: "e8332f2586d80a2700b610e8fe5c72d9" - } - Frame { - msec: 1328 - hash: "0d0c8af138f98bae8a370ebec4a4796c" - } - Frame { - msec: 1344 - hash: "04065e8feeb900d18deeb941572f7f10" - } - Frame { - msec: 1360 - hash: "992a225b1f25bf5b21dd7f8a55dc4b70" - } - Frame { - msec: 1376 - hash: "8ef739d91ee2a4337cbfc3dc94ce9845" - } - Frame { - msec: 1392 - hash: "46744977a26b37ab65e65e1891ceafe7" - } - Frame { - msec: 1408 - hash: "1b4c0d79eeb8d6b2e30172f3664407b9" - } - Frame { - msec: 1424 - hash: "d572831ed34d14d1125570b8b8767bdb" - } - Frame { - msec: 1440 - hash: "8b785c756d11e0fc18959d0897a45673" - } - Frame { - msec: 1456 - hash: "164a71ffcea63ceb6c1ebeb8d0d07af1" - } - Frame { - msec: 1472 - hash: "e128dc12d5117eed9f7c0a16e8348ba2" - } - Frame { - msec: 1488 - hash: "4c7db5b12d83bf22b1c88ac06ca7c385" - } - Frame { - msec: 1504 - hash: "c7283df8dbd78121e17a5893e3ea4f3c" - } - Frame { - msec: 1520 - hash: "fea768e5bb43f6d86d88ced9f73915de" - } - Frame { - msec: 1536 - hash: "b99b54f8e75452c539bb4e7b6a36e944" - } - Frame { - msec: 1552 - hash: "b7274938d16f03b376ad9739e2e893f1" - } - Frame { - msec: 1568 - hash: "e61601942193add8c1c8ebf5c5319932" - } - Frame { - msec: 1584 - hash: "8fdc2181e0120391505706716ba7e5d7" - } - Frame { - msec: 1600 - hash: "66f737ed28453da5175d6b5e807c374d" - } - Frame { - msec: 1616 - hash: "2e00a7895d61edbe794f0a8000871b30" - } - Frame { - msec: 1632 - hash: "1a279fc6b7c4105eccc4e3bc99481bef" - } - Frame { - msec: 1648 - hash: "bc1dea4d23ca9bc29b72a8c2bde4787b" - } - Frame { - msec: 1664 - hash: "8ef40e0be5fb82b32b365b3d4b85421d" - } - Frame { - msec: 1680 - hash: "ee37c68bf38d5eed4e3e9a31306f6801" - } - Frame { - msec: 1696 - hash: "303d760c87a7a833606c8e9f46cb5fc0" - } - Frame { - msec: 1712 - hash: "cc2563b47c58efd39bec6b4e0f2995bb" - } - Frame { - msec: 1728 - hash: "33f7daf09497510475283d6dc7c51228" - } - Frame { - msec: 1744 - hash: "5b5e2de9934c80bd49e0eb7afd85151d" - } - Frame { - msec: 1760 - hash: "5e6bf706336789ca6b60a82998b70113" - } - Frame { - msec: 1776 - hash: "b4d4a860f49bfb88dd2079862b40b7ec" - } - Frame { - msec: 1792 - hash: "07b571fa55327487e34a592c778beb67" - } - Frame { - msec: 1808 - hash: "cb5b349a536cf75a83734181b3eab92b" - } - Frame { - msec: 1824 - hash: "ce903bb58c5c86f2955e68412893aedf" - } - Frame { - msec: 1840 - hash: "ffa89e879558c83ed538812a93e2fe29" - } - Frame { - msec: 1856 - hash: "562aa66bf537853be82a654542c8b80e" - } - Frame { - msec: 1872 - hash: "dc45dac0cc20220bcc81210fb5506ee2" - } - Frame { - msec: 1888 - hash: "3b429eb827df0800a1ad8b906ea32ef9" - } - Frame { - msec: 1904 - hash: "d6ebaf12515d9e24cdbf6d75080c0b28" - } - Frame { - msec: 1920 - image: "easefollow.1.png" - } - Frame { - msec: 1936 - hash: "9f6d26224055c809dc2f3490cd0ff880" - } - Frame { - msec: 1952 - hash: "5630cc8f0b401f7d81bdceaaae5cce68" - } - Frame { - msec: 1968 - hash: "dafda60467e5e2b99c41543dd191ac2d" - } - Frame { - msec: 1984 - hash: "e053cb07a734278cd111d612883c165e" - } - Frame { - msec: 2000 - hash: "63870f3e99c11707004dab9439d61389" - } - Frame { - msec: 2016 - hash: "14c311a6fab45f828c3a19535ea9edc8" - } - Frame { - msec: 2032 - hash: "13e614446cbfcbfd2a7ecc5f0e8688df" - } - Frame { - msec: 2048 - hash: "173c97f59da05b9347180a4824e60c06" - } - Frame { - msec: 2064 - hash: "932e2a9bbcb7dc5befca8f63d8fa3c95" - } - Frame { - msec: 2080 - hash: "4b8f232ffe0cbc7f900de5737c9f95be" - } - Frame { - msec: 2096 - hash: "9686d294d4e931a5eed0e6b5bda63377" - } - Frame { - msec: 2112 - hash: "969c569d92e3ec51dfbdd20d64432224" - } - Frame { - msec: 2128 - hash: "0cef3550cca9fb5611b836098c517dd1" - } - Frame { - msec: 2144 - hash: "6728080a09aa5d48462a3abb8e285e8a" - } - Frame { - msec: 2160 - hash: "4b904dc671b7fc72db0b6e52543e96bd" - } - Frame { - msec: 2176 - hash: "38232f89dffc9b16db6ea60b02f8d1be" - } - Frame { - msec: 2192 - hash: "6b41f2a0f950eddad217a03e137f9a9b" - } - Frame { - msec: 2208 - hash: "be576ea74c2c404da46fcf1d22de6df9" - } - Frame { - msec: 2224 - hash: "3f44bad4b51ceff2944337064a5efa91" - } - Frame { - msec: 2240 - hash: "e1ab98ac1366e9fd8af62a6a26878c73" - } - Frame { - msec: 2256 - hash: "bd131e1725a54b3dbbb86a29ca8a56a9" - } - Frame { - msec: 2272 - hash: "4d3e8af70f228643803f780c4e36f1a6" - } - Frame { - msec: 2288 - hash: "853a5ab4271af7a7638454cfa883aa33" - } - Frame { - msec: 2304 - hash: "ede9260157000f346900153ce2409278" - } - Frame { - msec: 2320 - hash: "b2b16d8ce1ba89f0d9558ac387e25c3d" - } - Frame { - msec: 2336 - hash: "387d338910453637c5cf80fa35528e56" - } - Frame { - msec: 2352 - hash: "26deabf9cdd994455f2a8802eb0e04dc" - } - Frame { - msec: 2368 - hash: "13939659a315dae1b81e3ea166102edf" - } - Frame { - msec: 2384 - hash: "be92b55bb7562372401b25a9167abb2b" - } - Frame { - msec: 2400 - hash: "ee7bf60d7ee97b7de5e909b9af88df80" - } - Frame { - msec: 2416 - hash: "434313a3bcd1d7582b0d89b9a145ef09" - } - Frame { - msec: 2432 - hash: "0857ca59a283897e3df62b9633488f83" - } - Frame { - msec: 2448 - hash: "76718fc7e3d21b54930bc8307a57733a" - } - Frame { - msec: 2464 - hash: "93a91588b38129053a462b920fd686e3" - } - Frame { - msec: 2480 - hash: "2a2486c52fde915696fd8cbd3682e8db" - } - Frame { - msec: 2496 - hash: "b1f4ab6cc5fb4a3a1b4885f2d1b29277" - } - Frame { - msec: 2512 - hash: "4258afce8a85a2e9ead149e34b43d8fc" - } - Frame { - msec: 2528 - hash: "6672c71b98e13d51ebb523aed9036a72" - } - Frame { - msec: 2544 - hash: "eaa39af7eb78948f433e3b44a9454317" - } - Frame { - msec: 2560 - hash: "0a766bc97bea67d4b848c703eaa6777a" - } - Frame { - msec: 2576 - hash: "0b461ec1885ede1dd96b71cf38bfd3d6" - } - Frame { - msec: 2592 - hash: "15efc929370a3864529080e30db1026a" - } - Frame { - msec: 2608 - hash: "e1529e30ff1e4ea1b092a88e85f2f1f6" - } - Frame { - msec: 2624 - hash: "f29bd9dbf7317e94b885da63f0cb7374" - } - Frame { - msec: 2640 - hash: "e5294e087e2ce0d7d936c0129b6c37ae" - } - Frame { - msec: 2656 - hash: "9c63129e774b391cc398cf5da5c9339c" - } - Frame { - msec: 2672 - hash: "4371d85854419d4b00671176bb7c5a2b" - } - Frame { - msec: 2688 - hash: "dd10b3f50e2fdc56c75f00321634b1cc" - } - Frame { - msec: 2704 - hash: "aac6256b21152a5f1f8c576b667d275e" - } - Frame { - msec: 2720 - hash: "c937c44037b2228590d334df4d56a86f" - } - Frame { - msec: 2736 - hash: "f6c714db51cbd1bdb737afe612c33f9c" - } - Frame { - msec: 2752 - hash: "0bba45af79f3201bc7cf042d5c648f73" - } - Frame { - msec: 2768 - hash: "941b08ddbafea3bd46262c060b1e290b" - } - Frame { - msec: 2784 - hash: "d898918dc2023de239b4ab38f7420960" - } - Frame { - msec: 2800 - hash: "d1a16dc2282329113093d06862e7a871" - } - Frame { - msec: 2816 - hash: "bba5359475f643fbeee240e71e843d4c" - } - Frame { - msec: 2832 - hash: "03cf861f4b6bc767e723e47e95c2448b" - } - Frame { - msec: 2848 - hash: "a64bf158c6199b88bc2db3b741d342f0" - } - Frame { - msec: 2864 - hash: "cf0fe7cb42ba842f1c28c1211adb768d" - } - Frame { - msec: 2880 - image: "easefollow.2.png" - } - Frame { - msec: 2896 - hash: "9b3c6414e4ef5a452a5c92bb0b893fc3" - } - Frame { - msec: 2912 - hash: "7cc7ddec3ac2d8cac33c0b0f80a7544d" - } - Frame { - msec: 2928 - hash: "7dd4e7d606e953c872c57fad786d64aa" - } - Frame { - msec: 2944 - hash: "117cc903a39d99ca22f6556095e6f883" - } - Frame { - msec: 2960 - hash: "c6c9304fd65fee1909473bdb21ac7806" - } - Frame { - msec: 2976 - hash: "8e704fe81c040f49c4d80e7dcc46084d" - } - Frame { - msec: 2992 - hash: "d202d5c0a058e1e088fdd280e59f17bb" - } - Frame { - msec: 3008 - hash: "90c072dea32c056f8bd6d010df681929" - } - Frame { - msec: 3024 - hash: "80b4e99f1b47e64084e295a2a3e1121e" - } - Frame { - msec: 3040 - hash: "41d6307075ec9ae9e92d227921f71289" - } - Frame { - msec: 3056 - hash: "f33de23cf4a5c4881310c6866261d387" - } - Frame { - msec: 3072 - hash: "441faa0a1fc95d66b27479dfc1e40188" - } - Frame { - msec: 3088 - hash: "2314b5f6ba3864abd5e87bc87bd621b0" - } - Frame { - msec: 3104 - hash: "e71e3b0ad953258ceef3101e38283fdb" - } - Frame { - msec: 3120 - hash: "890c3b0e727f136bf1ccc486531c9677" - } - Frame { - msec: 3136 - hash: "2a0d23e6dcc6475c323dbf8eb36e8094" - } - Frame { - msec: 3152 - hash: "692682e82347936f87a66484b428e959" - } - Frame { - msec: 3168 - hash: "cf4005c08789762ad21be1a1d78755c9" - } - Frame { - msec: 3184 - hash: "566184563091626bb20ae679e3ce3b91" - } - Frame { - msec: 3200 - hash: "f88a24ad3bbc2699924bb9a7ff6490b3" - } - Frame { - msec: 3216 - hash: "23f3f63d07b2bdc2b82ff4e8606a634d" - } - Frame { - msec: 3232 - hash: "fe121c71ce469ec6f0bf957eb2f0447b" - } - Frame { - msec: 3248 - hash: "ba217690a33c701afe11842aa8105cbb" - } - Frame { - msec: 3264 - hash: "e5c7c1323108f13ba26f5198cc62c137" - } - Frame { - msec: 3280 - hash: "664f76d3d0008b56be2790c470befc91" - } - Frame { - msec: 3296 - hash: "b3f54070ba64b983ccd2a15941ef4c35" - } - Frame { - msec: 3312 - hash: "8a0ba2ae36ad3811778f3a3bc55743f5" - } - Frame { - msec: 3328 - hash: "bfdc71733ca45a2ba2e8abf751554a62" - } - Frame { - msec: 3344 - hash: "686e4d7bb5ae148d37fc2a1f6004a33a" - } - Frame { - msec: 3360 - hash: "29c553d9fe42fdbbd019d0ead61dffa0" - } - Frame { - msec: 3376 - hash: "bfa2b72c6554a2ed80a3b86f2cbed986" - } - Frame { - msec: 3392 - hash: "074ff90417a947f0a04926d5675d073b" - } - Frame { - msec: 3408 - hash: "6f56f9e0aa40149156ca71d6f8d4476a" - } - Frame { - msec: 3424 - hash: "950ce749bbf572021de2dd1688cb87e6" - } - Frame { - msec: 3440 - hash: "2d0903bd71862dc6f28bd702d955ae99" - } - Frame { - msec: 3456 - hash: "2733adae56728f1b744a4086ecb98052" - } - Frame { - msec: 3472 - hash: "779859d739e799bba15beeb97d18e682" - } - Frame { - msec: 3488 - hash: "9074386cfabe136b8839637e5cd58f57" - } - Frame { - msec: 3504 - hash: "fa5bcbf20c6ad0a218f23d98961229a1" - } - Frame { - msec: 3520 - hash: "5406c94da1717eaa5eb0010564216059" - } - Frame { - msec: 3536 - hash: "27d0a3c3a33c04df843bebd72ef79824" - } - Frame { - msec: 3552 - hash: "270df9c99c2679071b854b3d82337f79" - } - Frame { - msec: 3568 - hash: "5b3945505443a67e7a91f66fe42b4fe3" - } - Frame { - msec: 3584 - hash: "9a2f8565c354cb366725368ed323ccf4" - } - Frame { - msec: 3600 - hash: "6702cb7ccd61c008b511932d7bd5d107" - } - Frame { - msec: 3616 - hash: "f6b86c3a1cc88357f588b6dae11aae30" - } - Frame { - msec: 3632 - hash: "b10c23937f420db72af8abaf126f71c2" - } - Frame { - msec: 3648 - hash: "7d6b0810ffc6e488c8168e19bccb7358" - } - Frame { - msec: 3664 - hash: "c01ef69ec46391909619434e9d9dd0ce" - } - Frame { - msec: 3680 - hash: "a046464fccb0c5ba1f63f8b569821a44" - } - Frame { - msec: 3696 - hash: "8763c526924d882438f9aa9bfb4fe87d" - } - Frame { - msec: 3712 - hash: "dede7a62d6e5c10e8f30caa075bd8dfd" - } - Frame { - msec: 3728 - hash: "3b408e5c986f5bb01d8c3949876b792f" - } - Frame { - msec: 3744 - hash: "0a458f3b17cdd3ea85522779c9346af9" - } - Frame { - msec: 3760 - hash: "fef521f0301cce90af88d37e6d441ec8" - } - Frame { - msec: 3776 - hash: "3d083e0822242b3b37c6839ca91a1f68" - } - Frame { - msec: 3792 - hash: "f8fe013a717e6e61830137bdc78a8b40" - } - Frame { - msec: 3808 - hash: "0ae80ad65dd194043500fa50b5a547a6" - } - Frame { - msec: 3824 - hash: "a53c67fa32ef971eaea202fa5d8a6ad6" - } - Frame { - msec: 3840 - image: "easefollow.3.png" - } - Frame { - msec: 3856 - hash: "41f86bbf0658b127f01e8d46d7ec941b" - } - Frame { - msec: 3872 - hash: "d20f21df127565f9eb87c5d759a638d9" - } - Frame { - msec: 3888 - hash: "85ff94f03cea3e111807e90d062c1367" - } - Frame { - msec: 3904 - hash: "aa637850fe5f05a71ac4c7d31dbb36ee" - } - Frame { - msec: 3920 - hash: "c86a67096c5e62bb73b785cdf6a5b6b1" - } - Frame { - msec: 3936 - hash: "9d53537f2c50a0016bf7bb522b2ec3d8" - } - Frame { - msec: 3952 - hash: "b48630c27c27785ddce568a85d4dc58f" - } - Frame { - msec: 3968 - hash: "01c1bdb6e261cc509f26712b13eeb554" - } - Frame { - msec: 3984 - hash: "af8a44284695fd999acd5944434f0372" - } - Frame { - msec: 4000 - hash: "b156d9d6d5163f007ac4a309d8927ae9" - } - Frame { - msec: 4016 - hash: "2df3715416c3c005f04b66fe1258c0d8" - } - Frame { - msec: 4032 - hash: "96b4a7c6b8542b50fc345b54d38ec82a" - } - Frame { - msec: 4048 - hash: "7e62e757fafa06833444c3a7e1d96ce4" - } - Frame { - msec: 4064 - hash: "5222a8f9366c7d974d0687d05d229069" - } - Frame { - msec: 4080 - hash: "ec96169f4633c3bddfd582feeb8e9ad4" - } - Frame { - msec: 4096 - hash: "cb10db893d1e1cb2a370507dc5679985" - } - Frame { - msec: 4112 - hash: "d7e346c2ac77796bde639bd829b72e85" - } - Frame { - msec: 4128 - hash: "ba5bea8857e4fb444bedd3873563e7db" - } - Frame { - msec: 4144 - hash: "05556fba5d1714f70fd6c2bfb43d213b" - } - Frame { - msec: 4160 - hash: "aeeabf35f9759f045a670a9b9f90dc68" - } - Frame { - msec: 4176 - hash: "131bd453f4c7726e5fdd546252700e2e" - } - Frame { - msec: 4192 - hash: "7c5c3b5bb7a4082e6b9b43640e29f4e2" - } - Frame { - msec: 4208 - hash: "07515e21b7a7895f333e4a8bbd2202eb" - } - Frame { - msec: 4224 - hash: "6cf136f223ac6edd39ba6ed9b4445884" - } - Frame { - msec: 4240 - hash: "84264f5745add8a922101735ed8def84" - } - Frame { - msec: 4256 - hash: "660863d1e4b361f2e5445b417be0d2ad" - } - Frame { - msec: 4272 - hash: "7ceb86f4b16546370d72164d0ca3147c" - } - Frame { - msec: 4288 - hash: "a13e97da9722545ad87ac3c5eb92c497" - } - Frame { - msec: 4304 - hash: "5896b5307cbd609d2062d3607786d40c" - } - Frame { - msec: 4320 - hash: "c8c511115394116e4544c67f615ea5d5" - } - Frame { - msec: 4336 - hash: "59ca5fdf12a735e5c292901b54acccb2" - } - Frame { - msec: 4352 - hash: "155cce2738d34e0eac86f5eb63d638f0" - } - Frame { - msec: 4368 - hash: "83a840c3ae7dbd9a05c17fdd8be07d7a" - } - Frame { - msec: 4384 - hash: "800a15de28b14d88f0ad58fc3f4a2520" - } - Frame { - msec: 4400 - hash: "c8381439a3cd3f9e7f80061023723a6e" - } - Frame { - msec: 4416 - hash: "e3d63000db4b9458b202dece49d1bdba" - } - Frame { - msec: 4432 - hash: "c943e56781695798f3c221f8ab09681a" - } - Frame { - msec: 4448 - hash: "1137ee66d7fbf5a84c33f5ffff15b3dd" - } - Frame { - msec: 4464 - hash: "5a98013cc4462aad18cad8d941f77aa0" - } - Frame { - msec: 4480 - hash: "d0b3748fb49a13c0ad9a68b0e2914921" - } - Frame { - msec: 4496 - hash: "12113f71f9117670acbd7877edded7e0" - } - Frame { - msec: 4512 - hash: "22983424da08cdae7a9c6a8905b37736" - } - Frame { - msec: 4528 - hash: "b2db5618a025cefb2650124c81880c49" - } - Frame { - msec: 4544 - hash: "84fb5e7edc5b42163a83e0cd362b3a46" - } - Frame { - msec: 4560 - hash: "39d6f1ed0f60a0c366c22e1442c455ac" - } - Frame { - msec: 4576 - hash: "702367f6e4aaa2a862e57f9e02a08758" - } - Frame { - msec: 4592 - hash: "ecc75293bc156c560d55cb7d278a4e58" - } - Frame { - msec: 4608 - hash: "e68af8e97ce65376fd7904e599440c92" - } - Frame { - msec: 4624 - hash: "75fe9f766d6cf636cd72d8879a461439" - } - Frame { - msec: 4640 - hash: "162aef147ef4bbb0cd92bd70e4f37f62" - } - Frame { - msec: 4656 - hash: "d879aae8949976c7bad4d97f1e5b5549" - } - Frame { - msec: 4672 - hash: "8a983d7228190721f988de2d72cb3aa2" - } - Frame { - msec: 4688 - hash: "a4f3c63fde664d128cd35b129a4f9a23" - } - Frame { - msec: 4704 - hash: "115fb5f3c9b7f1c28ab379596faba91c" - } - Frame { - msec: 4720 - hash: "ea9600c4d6c77a3b32e59401aa84fe96" - } - Frame { - msec: 4736 - hash: "bd6531fdd9cfd46af2df73bacb31f4c5" - } - Frame { - msec: 4752 - hash: "33bdcf1df50eab5e7963c649fbd32226" - } - Frame { - msec: 4768 - hash: "236e88fb72369a55f9eba4b50712ae85" - } - Frame { - msec: 4784 - hash: "5eb3c14a6296fb3a1c58603b2fc937c8" - } - Frame { - msec: 4800 - image: "easefollow.4.png" - } - Frame { - msec: 4816 - hash: "31d11a1ce6422524241c77603fe53e61" - } - Frame { - msec: 4832 - hash: "44e8b9947026c10b922c84883dd8e889" - } - Frame { - msec: 4848 - hash: "d049e4f7c4bc1849398859a4d630c1b3" - } - Frame { - msec: 4864 - hash: "e83b4757898e4eeef74be8213619fbfa" - } - Frame { - msec: 4880 - hash: "d08f40615f2d5abc6236e856a67575dd" - } - Frame { - msec: 4896 - hash: "d9cb26bf1b8bbafb2aed8f74bd454077" - } - Frame { - msec: 4912 - hash: "aa321b94a6cc53b2ebac80e834c0a908" - } - Frame { - msec: 4928 - hash: "48da37164be156b67a4b3b14e50f2375" - } - Frame { - msec: 4944 - hash: "f522ce7728a4a9e7fad86c72f29bd8f9" - } - Frame { - msec: 4960 - hash: "9bc1d16b4bda596702a3d8a3fad8a5c5" - } - Frame { - msec: 4976 - hash: "5275dccf18745dec6c59b846de17d9ef" - } - Frame { - msec: 4992 - hash: "4eb6babc177b96f69b148d52f56d82d7" - } - Frame { - msec: 5008 - hash: "ccdfb454070ac04c4fe4f3513c52f8c8" - } - Frame { - msec: 5024 - hash: "07f6adad6e8ff4f0eff92c758636a951" - } - Frame { - msec: 5040 - hash: "241e0ad9218d49be477509e008e45548" - } - Frame { - msec: 5056 - hash: "151a482e821779da8a61063f1cc73f8c" - } - Frame { - msec: 5072 - hash: "1499d207c5a3a9bc7bbb84d9c5e35578" - } - Frame { - msec: 5088 - hash: "c253753f653157a5058ef071f16b8bbb" - } - Frame { - msec: 5104 - hash: "ec9fea5a870724a106b952edef7fb466" - } - Frame { - msec: 5120 - hash: "99b673f8ed049d31a2aecabcc46d841d" - } - Frame { - msec: 5136 - hash: "61e77fea693ea55aafbdc94c40c3ab33" - } - Frame { - msec: 5152 - hash: "53e44a3732ee6858d5bd596b4c5d5305" - } - Frame { - msec: 5168 - hash: "5b25d3894a56dc4f4a0aa8f88cb69e23" - } - Frame { - msec: 5184 - hash: "5683ad02f1b9126f4e4ff6b03044fdc6" - } - Frame { - msec: 5200 - hash: "0a3ec255575ec1b70e0b10cf59c7c5fd" - } - Frame { - msec: 5216 - hash: "0f5f46fe3fdf42d4651891f13c8afc7e" - } - Frame { - msec: 5232 - hash: "b6955407245c73e356a460d99dad77be" - } - Frame { - msec: 5248 - hash: "6018b53414921943b37c33fa04a29697" - } - Frame { - msec: 5264 - hash: "ff184d349ce0b648f8c1fce91ae997f6" - } - Frame { - msec: 5280 - hash: "9c112a3a785d970593887eeab72fa7fe" - } - Frame { - msec: 5296 - hash: "00384fb20d4c6cd6236d519d2d734cc3" - } - Frame { - msec: 5312 - hash: "601ea99400e5f50ee9a5a4b74b6f3017" - } - Frame { - msec: 5328 - hash: "9afed04bf7eca24d9b6d31ac84ae59c2" - } - Frame { - msec: 5344 - hash: "1983319c8043bfe403513af7ccb5b924" - } - Frame { - msec: 5360 - hash: "b0244e4e1b61202ede78405415c22bca" - } - Frame { - msec: 5376 - hash: "ec5516b1aaeace8784b04649c51ab40b" - } - Frame { - msec: 5392 - hash: "8ff7d2001594abb588f769bab15406d7" - } - Frame { - msec: 5408 - hash: "64d5fd96a1726aa5276f9b508566676f" - } - Frame { - msec: 5424 - hash: "ab49497a6c825038354f076bdbbbc235" - } - Frame { - msec: 5440 - hash: "6b821e43be932800b20af58a7b5a1ff7" - } - Frame { - msec: 5456 - hash: "683a2902300f930e2a81a82dc37c583b" - } - Frame { - msec: 5472 - hash: "86d7946d7fbb66369ccbf26430939225" - } - Frame { - msec: 5488 - hash: "fb38f5fb6555fc14e95a47c595a6ea0c" - } - Frame { - msec: 5504 - hash: "3878f685d9fa3299e9ffe78c22595387" - } - Frame { - msec: 5520 - hash: "b48840a68ff007901b02332c7177f315" - } - Frame { - msec: 5536 - hash: "9d847abc99220b04aceef12e5c09aac0" - } - Frame { - msec: 5552 - hash: "9893ac89fda64d96ec4140c3c87e17a5" - } - Frame { - msec: 5568 - hash: "cd94e1c36e6be9877cd9c12df42bd968" - } - Frame { - msec: 5584 - hash: "c1ce5e53b74af022dc103ad74ff5f1af" - } - Frame { - msec: 5600 - hash: "b3630e08eac02a9578a00b01baabaaba" - } - Frame { - msec: 5616 - hash: "0eb9241aa1f9526c1e24ba76d630805c" - } - Frame { - msec: 5632 - hash: "1b532ae7f9253469467522d4ca66c47b" - } - Frame { - msec: 5648 - hash: "7e6e49079ed6330da2e337a5e4ffd730" - } - Frame { - msec: 5664 - hash: "0391d668f4b906b244a5f5c1713573c2" - } - Frame { - msec: 5680 - hash: "8070fa3280d0d64bf976d4a276359c4c" - } - Frame { - msec: 5696 - hash: "f7d0d36a2d40c798f56ac7ecc1effca6" - } - Frame { - msec: 5712 - hash: "9f8e35ee5080e811c670c480a9c2bd9f" - } - Frame { - msec: 5728 - hash: "c7fea75a43a59a11aa504df32afcdaf8" - } - Frame { - msec: 5744 - hash: "7e549a93ffc6ddcc3d8111f10c05b29e" - } - Frame { - msec: 5760 - image: "easefollow.5.png" - } - Frame { - msec: 5776 - hash: "92d298262f610a2dafa095e3d67c80af" - } - Frame { - msec: 5792 - hash: "db8826b0b2feece0999863b8827a6234" - } - Frame { - msec: 5808 - hash: "12c7050e8094bb39212aed0163666d1a" - } - Frame { - msec: 5824 - hash: "69531beace5c749bf90160a4b25f736a" - } - Frame { - msec: 5840 - hash: "ce873e4dbc8853183b54d59991b2e030" - } - Frame { - msec: 5856 - hash: "fa1078973634578d69527402b11fb7e0" - } - Frame { - msec: 5872 - hash: "1e3b3db590567c0afd1913101192cda9" - } - Frame { - msec: 5888 - hash: "7b9e097018278b784973a546da3d401a" - } - Frame { - msec: 5904 - hash: "a7b0667093888480de6697280aeea9ba" - } - Frame { - msec: 5920 - hash: "e381f2422ead86575abf643b0b0c9797" - } - Frame { - msec: 5936 - hash: "44b08f5a0de2a6955e02f67753f409c8" - } - Frame { - msec: 5952 - hash: "db04665e58448ecc7f95baa3e4ea79a5" - } - Frame { - msec: 5968 - hash: "0e4aae728d8d543538a9446c41e18e91" - } - Frame { - msec: 5984 - hash: "e3cd1bbb1d9963e5c74d36e526a871b0" - } - Frame { - msec: 6000 - hash: "bcd893a0e200ddda4e1468c159018865" - } - Frame { - msec: 6016 - hash: "9c5293356aa6312f909e655e9bcf961b" - } - Frame { - msec: 6032 - hash: "0bab7b9166f6af554d4fa0badeec739e" - } - Frame { - msec: 6048 - hash: "e74996581f0aaeced118c5cbfd977d90" - } - Frame { - msec: 6064 - hash: "5d128eb20a2a23da8c2d9a35293e5769" - } - Frame { - msec: 6080 - hash: "ebbbc343698287faf7ffa7526a726b54" - } - Frame { - msec: 6096 - hash: "d812172192cc19590f9a2d7dbf970439" - } - Frame { - msec: 6112 - hash: "60263addb1b4b5ac43f8199b8ed77e40" - } - Frame { - msec: 6128 - hash: "702a1ff2876eaaa59359811bb6437c5b" - } - Frame { - msec: 6144 - hash: "8f81dc43decce5094ee7a089f0009730" - } - Frame { - msec: 6160 - hash: "efda5dd9edd83a0da089d0b28806c6b6" - } - Frame { - msec: 6176 - hash: "7274a33a7a5272d7abdaf41f4b2bf664" - } - Frame { - msec: 6192 - hash: "0cc80077476e721a3da85c17cc56a65e" - } - Frame { - msec: 6208 - hash: "e65a534f0e7e70520a9c2cfa09ee8159" - } - Frame { - msec: 6224 - hash: "b05b514c63bd8998785382e6a9cbd849" - } - Frame { - msec: 6240 - hash: "10a04d641e0cc65c120d8bcf2f3e54c8" - } - Frame { - msec: 6256 - hash: "68418e2206a496dd15a05b50fec6f87e" - } - Frame { - msec: 6272 - hash: "6549e0989e1c86e3a7eb0dcc8dd31380" - } - Frame { - msec: 6288 - hash: "bd0193c2cbc8958f674f4ec52a693b72" - } - Frame { - msec: 6304 - hash: "746440b45a3688dbd32b34c57454e956" - } - Frame { - msec: 6320 - hash: "6b54ee8af30be2178e8b3afab5dcb4c7" - } - Frame { - msec: 6336 - hash: "ba2fbad3fe2fe25ec0c0c542659168dc" - } - Frame { - msec: 6352 - hash: "84bd72703bd8200f8f090783d06ae451" - } - Frame { - msec: 6368 - hash: "17c9fb063280c2ee4cb4a13273bbb199" - } - Frame { - msec: 6384 - hash: "df28fd55719f5c2d164596d02c2faff2" - } - Frame { - msec: 6400 - hash: "c2e280e78e892200d40022d17ce695b7" - } - Frame { - msec: 6416 - hash: "c657caa0c5158e178ec5df80bbad6bcb" - } - Frame { - msec: 6432 - hash: "d91f4f6ec6503fe8280f9b02dd11e64a" - } - Frame { - msec: 6448 - hash: "0fb9400cdca9dbd4035fbf8af9952360" - } - Frame { - msec: 6464 - hash: "cac0e1b4aa094306b95f90ede4705391" - } - Frame { - msec: 6480 - hash: "e60a4bb14300a937a767effee931c60f" - } - Frame { - msec: 6496 - hash: "8b461397e3f210ee7e9305dcab2af2db" - } - Frame { - msec: 6512 - hash: "6ce9ec0942dd06c9f73929a7e176852c" - } - Frame { - msec: 6528 - hash: "da36e254635eea854a6552ba008117f9" - } - Frame { - msec: 6544 - hash: "0bec6402b5eb09d05ce8e9ff5253ea8d" - } - Frame { - msec: 6560 - hash: "72f6610527d395ca590eda166ef6bc4e" - } - Frame { - msec: 6576 - hash: "622ae3fd47adb2432e2a40d3c5539393" - } - Frame { - msec: 6592 - hash: "0b18c49e2bbf9370216e06b555faf183" - } - Frame { - msec: 6608 - hash: "0c090bb975fb883301b52479fd6f5fdf" - } - Frame { - msec: 6624 - hash: "c4205d7ecb7327426d9591e77247acab" - } - Frame { - msec: 6640 - hash: "f0e0075243e4b8aa97056248fe6033ed" - } - Frame { - msec: 6656 - hash: "47f99b40a8764ee9d9e429061fb7acb2" - } - Frame { - msec: 6672 - hash: "49e8c1e974b0716570d85109b53817a5" - } - Frame { - msec: 6688 - hash: "72f981bad831b6ed858009527902f734" - } - Frame { - msec: 6704 - hash: "e959a0493b06369a429f90f66cb65977" - } - Frame { - msec: 6720 - image: "easefollow.6.png" - } - Frame { - msec: 6736 - hash: "93470d983282f24425558f47ad705154" - } - Frame { - msec: 6752 - hash: "cdccbe1a7c7abd4a6a6ee754ed0c9759" - } - Frame { - msec: 6768 - hash: "0e1b7b5332a9fcdb492db5314a2a0267" - } - Frame { - msec: 6784 - hash: "1e1ffe3439aab51d0b325474e7d8dc28" - } - Frame { - msec: 6800 - hash: "e8e7e9b5871caf77f15678616d6c9c8a" - } - Frame { - msec: 6816 - hash: "9771fff3b7752154d093c038bea73d28" - } - Frame { - msec: 6832 - hash: "1af851ea214cbddb0e3a743084a5cf6b" - } - Frame { - msec: 6848 - hash: "1566182a7e29bbb738705a90c4909617" - } - Frame { - msec: 6864 - hash: "feed650e1d948fe622234d212fb745f2" - } - Frame { - msec: 6880 - hash: "3cd3d063275b91f9680717421c118ba4" - } - Frame { - msec: 6896 - hash: "c1f088801334762cd499e7cc70e1e59a" - } - Frame { - msec: 6912 - hash: "e8f8d153e7a027a5092a9209411d97f7" - } - Frame { - msec: 6928 - hash: "f11747c3533b4b2fc77a64ca0cace8b0" - } - Frame { - msec: 6944 - hash: "21618c67a2a8bbce86fc872060ad40e8" - } - Frame { - msec: 6960 - hash: "02da96335db74b87ceefe91b1dfe72e6" - } - Frame { - msec: 6976 - hash: "2b2e4143143ead8dea5865fd782f1775" - } - Frame { - msec: 6992 - hash: "13e710900b05e26cdb030b1e2b2be715" - } - Frame { - msec: 7008 - hash: "29e8995d17aac4d02034debcbb9fcb98" - } - Frame { - msec: 7024 - hash: "1099db1b3e4c69e84c6ab1b7c311bf1e" - } - Frame { - msec: 7040 - hash: "cc7cb720043334f1eeb385dce4389dc2" - } - Frame { - msec: 7056 - hash: "34c7a62c1bc7261e2fd31c40068b37a7" - } - Frame { - msec: 7072 - hash: "7fafbe05cbcaa21893e3aa0f1fcfb5a0" - } - Key { - type: 6 - key: 16777249 - modifiers: 67108864 - text: "" - autorep: false - count: 1 - } - Frame { - msec: 7088 - hash: "5b26c8cf047706633795a8ed3e703a89" - } - Frame { - msec: 7104 - hash: "e0774bf9e74d0cde81c5cb216a9258fc" - } - Frame { - msec: 7120 - hash: "0870262f643245e13f4fba79fd575897" - } - Frame { - msec: 7136 - hash: "8faf0d050bb435ade8af5012c1a6b0dc" - } - Frame { - msec: 7152 - hash: "382c037895cc39a6870db57b5016c01f" - } - Frame { - msec: 7168 - hash: "f1f5a2cbc103ab1bee9f537fa8266e03" - } -} diff --git a/tests/auto/declarative/qmlvisual/qdeclarativeeasefollow/easefollow.qml b/tests/auto/declarative/qmlvisual/qdeclarativeeasefollow/easefollow.qml deleted file mode 100644 index ee94857..0000000 --- a/tests/auto/declarative/qmlvisual/qdeclarativeeasefollow/easefollow.qml +++ /dev/null @@ -1,45 +0,0 @@ -import Qt 4.6 - -Rectangle { - width: 800; height: 240; color: "gray" - - Rectangle { - id: rect - width: 50; height: 20; y: 30; color: "black" - SequentialAnimation on x { - loops: Animation.Infinite - NumberAnimation { from: 50; to: 700; duration: 2000 } - NumberAnimation { from: 700; to: 50; duration: 2000 } - } - } - - Rectangle { - width: 50; height: 20; y: 60; color: "red" - x: rect.x - Behavior on x { SmoothedAnimation { velocity: 400 } } - } - - Rectangle { - width: 50; height: 20; y: 90; color: "yellow" - x: rect.x - Behavior on x { SmoothedAnimation { velocity: 300; reversingMode: SmoothedAnimation.Immediate } } - } - - Rectangle { - width: 50; height: 20; y: 120; color: "green" - x: rect.x - Behavior on x { SmoothedAnimation { reversingMode: SmoothedAnimation.Sync } } - } - - Rectangle { - width: 50; height: 20; y: 150; color: "purple" - x: rect.x - Behavior on x { SmoothedAnimation { maximumEasingTime: 200 } } - } - - Rectangle { - width: 50; height: 20; y: 180; color: "blue" - x: rect.x - Behavior on x { SmoothedAnimation { duration: 300 } } - } -} diff --git a/tests/auto/declarative/qmlvisual/qdeclarativesmoothedanimation/data/easefollow.0.png b/tests/auto/declarative/qmlvisual/qdeclarativesmoothedanimation/data/easefollow.0.png new file mode 100644 index 0000000..21b6afb Binary files /dev/null and b/tests/auto/declarative/qmlvisual/qdeclarativesmoothedanimation/data/easefollow.0.png differ diff --git a/tests/auto/declarative/qmlvisual/qdeclarativesmoothedanimation/data/easefollow.1.png b/tests/auto/declarative/qmlvisual/qdeclarativesmoothedanimation/data/easefollow.1.png new file mode 100644 index 0000000..bb8a02b Binary files /dev/null and b/tests/auto/declarative/qmlvisual/qdeclarativesmoothedanimation/data/easefollow.1.png differ diff --git a/tests/auto/declarative/qmlvisual/qdeclarativesmoothedanimation/data/easefollow.2.png b/tests/auto/declarative/qmlvisual/qdeclarativesmoothedanimation/data/easefollow.2.png new file mode 100644 index 0000000..da60237 Binary files /dev/null and b/tests/auto/declarative/qmlvisual/qdeclarativesmoothedanimation/data/easefollow.2.png differ diff --git a/tests/auto/declarative/qmlvisual/qdeclarativesmoothedanimation/data/easefollow.3.png b/tests/auto/declarative/qmlvisual/qdeclarativesmoothedanimation/data/easefollow.3.png new file mode 100644 index 0000000..3e943e8 Binary files /dev/null and b/tests/auto/declarative/qmlvisual/qdeclarativesmoothedanimation/data/easefollow.3.png differ diff --git a/tests/auto/declarative/qmlvisual/qdeclarativesmoothedanimation/data/easefollow.4.png b/tests/auto/declarative/qmlvisual/qdeclarativesmoothedanimation/data/easefollow.4.png new file mode 100644 index 0000000..4fbaf26 Binary files /dev/null and b/tests/auto/declarative/qmlvisual/qdeclarativesmoothedanimation/data/easefollow.4.png differ diff --git a/tests/auto/declarative/qmlvisual/qdeclarativesmoothedanimation/data/easefollow.5.png b/tests/auto/declarative/qmlvisual/qdeclarativesmoothedanimation/data/easefollow.5.png new file mode 100644 index 0000000..c10d196 Binary files /dev/null and b/tests/auto/declarative/qmlvisual/qdeclarativesmoothedanimation/data/easefollow.5.png differ diff --git a/tests/auto/declarative/qmlvisual/qdeclarativesmoothedanimation/data/easefollow.6.png b/tests/auto/declarative/qmlvisual/qdeclarativesmoothedanimation/data/easefollow.6.png new file mode 100644 index 0000000..a672c06 Binary files /dev/null and b/tests/auto/declarative/qmlvisual/qdeclarativesmoothedanimation/data/easefollow.6.png differ diff --git a/tests/auto/declarative/qmlvisual/qdeclarativesmoothedanimation/data/easefollow.qml b/tests/auto/declarative/qmlvisual/qdeclarativesmoothedanimation/data/easefollow.qml new file mode 100644 index 0000000..029a2fc --- /dev/null +++ b/tests/auto/declarative/qmlvisual/qdeclarativesmoothedanimation/data/easefollow.qml @@ -0,0 +1,1807 @@ +import Qt.VisualTest 4.6 + +VisualTest { + Frame { + msec: 0 + } + Frame { + msec: 16 + hash: "1f60efdb8704b92c9361daa468a25391" + } + Frame { + msec: 32 + hash: "3bb6a87617e0e5d4922e573eec975886" + } + Frame { + msec: 48 + hash: "268941737e6324d580890b151de621fb" + } + Frame { + msec: 64 + hash: "99c674eccc082d7f0982257a748d93e5" + } + Frame { + msec: 80 + hash: "2970467e8262c8a3f0b11be71245d048" + } + Frame { + msec: 96 + hash: "63cbd06d6bb035d27c18dba49238d8b2" + } + Frame { + msec: 112 + hash: "49f77bb3d323f882c0ec56e1f1040b3a" + } + Frame { + msec: 128 + hash: "40263c5f9b5d2236536163785f832b4d" + } + Frame { + msec: 144 + hash: "dc63b1c21a2027c4beb9c297a3677fbd" + } + Frame { + msec: 160 + hash: "4fab52ea29a819fec032f19dbcbef012" + } + Frame { + msec: 176 + hash: "60b48407a8f8ae2cce7d3e7c8b21991c" + } + Frame { + msec: 192 + hash: "6e542c681092a5ebeef0534fa2bd2d6c" + } + Frame { + msec: 208 + hash: "c7c6471969bbf81efdb86d1695548fc6" + } + Frame { + msec: 224 + hash: "b7f4ad9a49feb400894209c02b94478a" + } + Frame { + msec: 240 + hash: "3eb58b2f5233aead976183c13f241113" + } + Frame { + msec: 256 + hash: "54f2036c50c6d8079fc0cadc01385980" + } + Frame { + msec: 272 + hash: "f297659d75f6e724d72bd548821f4c9f" + } + Frame { + msec: 288 + hash: "112798f080336fc9c603a7e9097dd8aa" + } + Frame { + msec: 304 + hash: "c432e6ec2b53ca43cb7a7325d0cc379b" + } + Frame { + msec: 320 + hash: "4a6d3db3efd665ad7f372bf3f2508ed7" + } + Frame { + msec: 336 + hash: "0befa5dc4d2cc196fed0eb1a3aa75b8f" + } + Frame { + msec: 352 + hash: "a34d010b50d59c362b54e44d69c2df91" + } + Frame { + msec: 368 + hash: "cbdacced50186c87066ce1d46548b27e" + } + Frame { + msec: 384 + hash: "a4060010ae4d3c0973bda48d68f7bd0a" + } + Frame { + msec: 400 + hash: "47353437da587f732f986004c09884d0" + } + Frame { + msec: 416 + hash: "080c348145167bbec671a04da6f7564f" + } + Frame { + msec: 432 + hash: "69dead737c717a076ae3865680341fb4" + } + Frame { + msec: 448 + hash: "1efdc31c5c8fa72fc848877deb6caaa4" + } + Frame { + msec: 464 + hash: "28d7da1e933d0585d03acf4a529e7b42" + } + Frame { + msec: 480 + hash: "bf85534124bf025b7ede0d6c80b8e443" + } + Frame { + msec: 496 + hash: "cdbeb2d51541b1b1eff060efe993db91" + } + Frame { + msec: 512 + hash: "52ad56ae16c8ab523adda8edc512dd87" + } + Frame { + msec: 528 + hash: "61b1937f4c8dd2cb0ddd7031c5bfb3ab" + } + Frame { + msec: 544 + hash: "1b109baba71b16827f90da654af093a3" + } + Frame { + msec: 560 + hash: "d56621362802c8626868f36ba1e7db22" + } + Frame { + msec: 576 + hash: "ee5555ec3ad8760f43bbf5958a925936" + } + Frame { + msec: 592 + hash: "1ed2831144a453af1978605c0e42d17c" + } + Frame { + msec: 608 + hash: "c74d5cdb3395a702269dfa88c8c9d975" + } + Frame { + msec: 624 + hash: "ea98ddd9588cc23fd82a342ec2925ba8" + } + Frame { + msec: 640 + hash: "e76b94d6d57f1a510f7649eaab892562" + } + Frame { + msec: 656 + hash: "022f40b6fe9dbaf8019855234acb3461" + } + Frame { + msec: 672 + hash: "467da4f48aa6aeb113f0797facf157e8" + } + Frame { + msec: 688 + hash: "8df407aadd4d896eb6537e1555a0242f" + } + Frame { + msec: 704 + hash: "122e4671881e31f54e617729f4fbb3b0" + } + Frame { + msec: 720 + hash: "562718f101c3cd7525b890076413df5e" + } + Frame { + msec: 736 + hash: "07feae99ecf4b70eb094fd3e10deca56" + } + Frame { + msec: 752 + hash: "0980d133b1006cc07796023880415163" + } + Frame { + msec: 768 + hash: "7112b6ac97678b3b942c64c5108f0329" + } + Frame { + msec: 784 + hash: "bb9f893a9aaee60ab6c30918552828a4" + } + Frame { + msec: 800 + hash: "65d1f29437aaaea33676757276f1e434" + } + Frame { + msec: 816 + hash: "52adcf2509f3236ac8ef571708e77206" + } + Frame { + msec: 832 + hash: "22df5e7eda8a813531d0e0366cbfbf64" + } + Frame { + msec: 848 + hash: "fe9b7b7812dd2410b8ed2eb19aa78f4d" + } + Frame { + msec: 864 + hash: "141e22de4469f316b5ef5471f3c7bba0" + } + Frame { + msec: 880 + hash: "1125c0a105fc4a2cae36b798058ce23f" + } + Frame { + msec: 896 + hash: "8c17c5da2ae867fb0016a485ba9e4166" + } + Frame { + msec: 912 + hash: "d8da9fc7ec4dcefb894c5a6a71e9d001" + } + Frame { + msec: 928 + hash: "00ff642bea89fd89de394d78f8c5db33" + } + Frame { + msec: 944 + hash: "8549063d517a3ce1ffd44c56b3b6cf5e" + } + Frame { + msec: 960 + image: "easefollow.0.png" + } + Frame { + msec: 976 + hash: "95a642caa72bb31cc1e04ecc12d07cd0" + } + Frame { + msec: 992 + hash: "e65c823476bf920d0386f62ca831e6a0" + } + Frame { + msec: 1008 + hash: "91e8913dc693c91a674a10b5b088dd8f" + } + Frame { + msec: 1024 + hash: "1a469ffa0d530f72c78dc14783891c78" + } + Frame { + msec: 1040 + hash: "6e46a83d07f8bc034b421103ef0e4f8c" + } + Frame { + msec: 1056 + hash: "8ddacab411a8b73b6c9e69576fa1b003" + } + Frame { + msec: 1072 + hash: "41f419a85fe44efe27c9a526d83a1e9a" + } + Frame { + msec: 1088 + hash: "73d4ece31b258f9caf4556ce20a5be1f" + } + Frame { + msec: 1104 + hash: "ef3ebe0acb50386cf79b9f08fbba2fbc" + } + Frame { + msec: 1120 + hash: "c11a84d2fa80f28adb1466409812e987" + } + Frame { + msec: 1136 + hash: "2e9db854b02d28b38063ff2a8e821ed1" + } + Frame { + msec: 1152 + hash: "48e073c0e6b19aea8314629a2179af87" + } + Frame { + msec: 1168 + hash: "77e518b7428d93b67a8fb0d33d85ed97" + } + Frame { + msec: 1184 + hash: "1d18323af9c62e015513451883f8b39f" + } + Frame { + msec: 1200 + hash: "df49889ba157cdc1ca240d08d2760ad7" + } + Frame { + msec: 1216 + hash: "7b8cd2bcf0a4c38ab870f27894a43d2f" + } + Frame { + msec: 1232 + hash: "84f10e0c9fd57dd1799df7fc34c5ef01" + } + Frame { + msec: 1248 + hash: "ead4e609bc4a0755032b1648485b9625" + } + Frame { + msec: 1264 + hash: "9a9829c3bd4a3a4155383c37e21e8db8" + } + Frame { + msec: 1280 + hash: "5008917f60256abad867f32c1caf954d" + } + Frame { + msec: 1296 + hash: "c21455d66ed0754177af5ce44b7c7600" + } + Frame { + msec: 1312 + hash: "e8332f2586d80a2700b610e8fe5c72d9" + } + Frame { + msec: 1328 + hash: "0d0c8af138f98bae8a370ebec4a4796c" + } + Frame { + msec: 1344 + hash: "04065e8feeb900d18deeb941572f7f10" + } + Frame { + msec: 1360 + hash: "992a225b1f25bf5b21dd7f8a55dc4b70" + } + Frame { + msec: 1376 + hash: "8ef739d91ee2a4337cbfc3dc94ce9845" + } + Frame { + msec: 1392 + hash: "46744977a26b37ab65e65e1891ceafe7" + } + Frame { + msec: 1408 + hash: "1b4c0d79eeb8d6b2e30172f3664407b9" + } + Frame { + msec: 1424 + hash: "d572831ed34d14d1125570b8b8767bdb" + } + Frame { + msec: 1440 + hash: "8b785c756d11e0fc18959d0897a45673" + } + Frame { + msec: 1456 + hash: "164a71ffcea63ceb6c1ebeb8d0d07af1" + } + Frame { + msec: 1472 + hash: "e128dc12d5117eed9f7c0a16e8348ba2" + } + Frame { + msec: 1488 + hash: "4c7db5b12d83bf22b1c88ac06ca7c385" + } + Frame { + msec: 1504 + hash: "c7283df8dbd78121e17a5893e3ea4f3c" + } + Frame { + msec: 1520 + hash: "fea768e5bb43f6d86d88ced9f73915de" + } + Frame { + msec: 1536 + hash: "b99b54f8e75452c539bb4e7b6a36e944" + } + Frame { + msec: 1552 + hash: "b7274938d16f03b376ad9739e2e893f1" + } + Frame { + msec: 1568 + hash: "e61601942193add8c1c8ebf5c5319932" + } + Frame { + msec: 1584 + hash: "8fdc2181e0120391505706716ba7e5d7" + } + Frame { + msec: 1600 + hash: "66f737ed28453da5175d6b5e807c374d" + } + Frame { + msec: 1616 + hash: "2e00a7895d61edbe794f0a8000871b30" + } + Frame { + msec: 1632 + hash: "1a279fc6b7c4105eccc4e3bc99481bef" + } + Frame { + msec: 1648 + hash: "bc1dea4d23ca9bc29b72a8c2bde4787b" + } + Frame { + msec: 1664 + hash: "8ef40e0be5fb82b32b365b3d4b85421d" + } + Frame { + msec: 1680 + hash: "ee37c68bf38d5eed4e3e9a31306f6801" + } + Frame { + msec: 1696 + hash: "303d760c87a7a833606c8e9f46cb5fc0" + } + Frame { + msec: 1712 + hash: "cc2563b47c58efd39bec6b4e0f2995bb" + } + Frame { + msec: 1728 + hash: "33f7daf09497510475283d6dc7c51228" + } + Frame { + msec: 1744 + hash: "5b5e2de9934c80bd49e0eb7afd85151d" + } + Frame { + msec: 1760 + hash: "5e6bf706336789ca6b60a82998b70113" + } + Frame { + msec: 1776 + hash: "b4d4a860f49bfb88dd2079862b40b7ec" + } + Frame { + msec: 1792 + hash: "07b571fa55327487e34a592c778beb67" + } + Frame { + msec: 1808 + hash: "cb5b349a536cf75a83734181b3eab92b" + } + Frame { + msec: 1824 + hash: "ce903bb58c5c86f2955e68412893aedf" + } + Frame { + msec: 1840 + hash: "ffa89e879558c83ed538812a93e2fe29" + } + Frame { + msec: 1856 + hash: "562aa66bf537853be82a654542c8b80e" + } + Frame { + msec: 1872 + hash: "dc45dac0cc20220bcc81210fb5506ee2" + } + Frame { + msec: 1888 + hash: "3b429eb827df0800a1ad8b906ea32ef9" + } + Frame { + msec: 1904 + hash: "d6ebaf12515d9e24cdbf6d75080c0b28" + } + Frame { + msec: 1920 + image: "easefollow.1.png" + } + Frame { + msec: 1936 + hash: "9f6d26224055c809dc2f3490cd0ff880" + } + Frame { + msec: 1952 + hash: "5630cc8f0b401f7d81bdceaaae5cce68" + } + Frame { + msec: 1968 + hash: "dafda60467e5e2b99c41543dd191ac2d" + } + Frame { + msec: 1984 + hash: "e053cb07a734278cd111d612883c165e" + } + Frame { + msec: 2000 + hash: "63870f3e99c11707004dab9439d61389" + } + Frame { + msec: 2016 + hash: "14c311a6fab45f828c3a19535ea9edc8" + } + Frame { + msec: 2032 + hash: "13e614446cbfcbfd2a7ecc5f0e8688df" + } + Frame { + msec: 2048 + hash: "173c97f59da05b9347180a4824e60c06" + } + Frame { + msec: 2064 + hash: "932e2a9bbcb7dc5befca8f63d8fa3c95" + } + Frame { + msec: 2080 + hash: "4b8f232ffe0cbc7f900de5737c9f95be" + } + Frame { + msec: 2096 + hash: "9686d294d4e931a5eed0e6b5bda63377" + } + Frame { + msec: 2112 + hash: "969c569d92e3ec51dfbdd20d64432224" + } + Frame { + msec: 2128 + hash: "0cef3550cca9fb5611b836098c517dd1" + } + Frame { + msec: 2144 + hash: "6728080a09aa5d48462a3abb8e285e8a" + } + Frame { + msec: 2160 + hash: "4b904dc671b7fc72db0b6e52543e96bd" + } + Frame { + msec: 2176 + hash: "38232f89dffc9b16db6ea60b02f8d1be" + } + Frame { + msec: 2192 + hash: "6b41f2a0f950eddad217a03e137f9a9b" + } + Frame { + msec: 2208 + hash: "be576ea74c2c404da46fcf1d22de6df9" + } + Frame { + msec: 2224 + hash: "3f44bad4b51ceff2944337064a5efa91" + } + Frame { + msec: 2240 + hash: "e1ab98ac1366e9fd8af62a6a26878c73" + } + Frame { + msec: 2256 + hash: "bd131e1725a54b3dbbb86a29ca8a56a9" + } + Frame { + msec: 2272 + hash: "4d3e8af70f228643803f780c4e36f1a6" + } + Frame { + msec: 2288 + hash: "853a5ab4271af7a7638454cfa883aa33" + } + Frame { + msec: 2304 + hash: "ede9260157000f346900153ce2409278" + } + Frame { + msec: 2320 + hash: "b2b16d8ce1ba89f0d9558ac387e25c3d" + } + Frame { + msec: 2336 + hash: "387d338910453637c5cf80fa35528e56" + } + Frame { + msec: 2352 + hash: "26deabf9cdd994455f2a8802eb0e04dc" + } + Frame { + msec: 2368 + hash: "13939659a315dae1b81e3ea166102edf" + } + Frame { + msec: 2384 + hash: "be92b55bb7562372401b25a9167abb2b" + } + Frame { + msec: 2400 + hash: "ee7bf60d7ee97b7de5e909b9af88df80" + } + Frame { + msec: 2416 + hash: "434313a3bcd1d7582b0d89b9a145ef09" + } + Frame { + msec: 2432 + hash: "0857ca59a283897e3df62b9633488f83" + } + Frame { + msec: 2448 + hash: "76718fc7e3d21b54930bc8307a57733a" + } + Frame { + msec: 2464 + hash: "93a91588b38129053a462b920fd686e3" + } + Frame { + msec: 2480 + hash: "2a2486c52fde915696fd8cbd3682e8db" + } + Frame { + msec: 2496 + hash: "b1f4ab6cc5fb4a3a1b4885f2d1b29277" + } + Frame { + msec: 2512 + hash: "4258afce8a85a2e9ead149e34b43d8fc" + } + Frame { + msec: 2528 + hash: "6672c71b98e13d51ebb523aed9036a72" + } + Frame { + msec: 2544 + hash: "eaa39af7eb78948f433e3b44a9454317" + } + Frame { + msec: 2560 + hash: "0a766bc97bea67d4b848c703eaa6777a" + } + Frame { + msec: 2576 + hash: "0b461ec1885ede1dd96b71cf38bfd3d6" + } + Frame { + msec: 2592 + hash: "15efc929370a3864529080e30db1026a" + } + Frame { + msec: 2608 + hash: "e1529e30ff1e4ea1b092a88e85f2f1f6" + } + Frame { + msec: 2624 + hash: "f29bd9dbf7317e94b885da63f0cb7374" + } + Frame { + msec: 2640 + hash: "e5294e087e2ce0d7d936c0129b6c37ae" + } + Frame { + msec: 2656 + hash: "9c63129e774b391cc398cf5da5c9339c" + } + Frame { + msec: 2672 + hash: "4371d85854419d4b00671176bb7c5a2b" + } + Frame { + msec: 2688 + hash: "dd10b3f50e2fdc56c75f00321634b1cc" + } + Frame { + msec: 2704 + hash: "aac6256b21152a5f1f8c576b667d275e" + } + Frame { + msec: 2720 + hash: "c937c44037b2228590d334df4d56a86f" + } + Frame { + msec: 2736 + hash: "f6c714db51cbd1bdb737afe612c33f9c" + } + Frame { + msec: 2752 + hash: "0bba45af79f3201bc7cf042d5c648f73" + } + Frame { + msec: 2768 + hash: "941b08ddbafea3bd46262c060b1e290b" + } + Frame { + msec: 2784 + hash: "d898918dc2023de239b4ab38f7420960" + } + Frame { + msec: 2800 + hash: "d1a16dc2282329113093d06862e7a871" + } + Frame { + msec: 2816 + hash: "bba5359475f643fbeee240e71e843d4c" + } + Frame { + msec: 2832 + hash: "03cf861f4b6bc767e723e47e95c2448b" + } + Frame { + msec: 2848 + hash: "a64bf158c6199b88bc2db3b741d342f0" + } + Frame { + msec: 2864 + hash: "cf0fe7cb42ba842f1c28c1211adb768d" + } + Frame { + msec: 2880 + image: "easefollow.2.png" + } + Frame { + msec: 2896 + hash: "9b3c6414e4ef5a452a5c92bb0b893fc3" + } + Frame { + msec: 2912 + hash: "7cc7ddec3ac2d8cac33c0b0f80a7544d" + } + Frame { + msec: 2928 + hash: "7dd4e7d606e953c872c57fad786d64aa" + } + Frame { + msec: 2944 + hash: "117cc903a39d99ca22f6556095e6f883" + } + Frame { + msec: 2960 + hash: "c6c9304fd65fee1909473bdb21ac7806" + } + Frame { + msec: 2976 + hash: "8e704fe81c040f49c4d80e7dcc46084d" + } + Frame { + msec: 2992 + hash: "d202d5c0a058e1e088fdd280e59f17bb" + } + Frame { + msec: 3008 + hash: "90c072dea32c056f8bd6d010df681929" + } + Frame { + msec: 3024 + hash: "80b4e99f1b47e64084e295a2a3e1121e" + } + Frame { + msec: 3040 + hash: "41d6307075ec9ae9e92d227921f71289" + } + Frame { + msec: 3056 + hash: "f33de23cf4a5c4881310c6866261d387" + } + Frame { + msec: 3072 + hash: "441faa0a1fc95d66b27479dfc1e40188" + } + Frame { + msec: 3088 + hash: "2314b5f6ba3864abd5e87bc87bd621b0" + } + Frame { + msec: 3104 + hash: "e71e3b0ad953258ceef3101e38283fdb" + } + Frame { + msec: 3120 + hash: "890c3b0e727f136bf1ccc486531c9677" + } + Frame { + msec: 3136 + hash: "2a0d23e6dcc6475c323dbf8eb36e8094" + } + Frame { + msec: 3152 + hash: "692682e82347936f87a66484b428e959" + } + Frame { + msec: 3168 + hash: "cf4005c08789762ad21be1a1d78755c9" + } + Frame { + msec: 3184 + hash: "566184563091626bb20ae679e3ce3b91" + } + Frame { + msec: 3200 + hash: "f88a24ad3bbc2699924bb9a7ff6490b3" + } + Frame { + msec: 3216 + hash: "23f3f63d07b2bdc2b82ff4e8606a634d" + } + Frame { + msec: 3232 + hash: "fe121c71ce469ec6f0bf957eb2f0447b" + } + Frame { + msec: 3248 + hash: "ba217690a33c701afe11842aa8105cbb" + } + Frame { + msec: 3264 + hash: "e5c7c1323108f13ba26f5198cc62c137" + } + Frame { + msec: 3280 + hash: "664f76d3d0008b56be2790c470befc91" + } + Frame { + msec: 3296 + hash: "b3f54070ba64b983ccd2a15941ef4c35" + } + Frame { + msec: 3312 + hash: "8a0ba2ae36ad3811778f3a3bc55743f5" + } + Frame { + msec: 3328 + hash: "bfdc71733ca45a2ba2e8abf751554a62" + } + Frame { + msec: 3344 + hash: "686e4d7bb5ae148d37fc2a1f6004a33a" + } + Frame { + msec: 3360 + hash: "29c553d9fe42fdbbd019d0ead61dffa0" + } + Frame { + msec: 3376 + hash: "bfa2b72c6554a2ed80a3b86f2cbed986" + } + Frame { + msec: 3392 + hash: "074ff90417a947f0a04926d5675d073b" + } + Frame { + msec: 3408 + hash: "6f56f9e0aa40149156ca71d6f8d4476a" + } + Frame { + msec: 3424 + hash: "950ce749bbf572021de2dd1688cb87e6" + } + Frame { + msec: 3440 + hash: "2d0903bd71862dc6f28bd702d955ae99" + } + Frame { + msec: 3456 + hash: "2733adae56728f1b744a4086ecb98052" + } + Frame { + msec: 3472 + hash: "779859d739e799bba15beeb97d18e682" + } + Frame { + msec: 3488 + hash: "9074386cfabe136b8839637e5cd58f57" + } + Frame { + msec: 3504 + hash: "fa5bcbf20c6ad0a218f23d98961229a1" + } + Frame { + msec: 3520 + hash: "5406c94da1717eaa5eb0010564216059" + } + Frame { + msec: 3536 + hash: "27d0a3c3a33c04df843bebd72ef79824" + } + Frame { + msec: 3552 + hash: "270df9c99c2679071b854b3d82337f79" + } + Frame { + msec: 3568 + hash: "5b3945505443a67e7a91f66fe42b4fe3" + } + Frame { + msec: 3584 + hash: "9a2f8565c354cb366725368ed323ccf4" + } + Frame { + msec: 3600 + hash: "6702cb7ccd61c008b511932d7bd5d107" + } + Frame { + msec: 3616 + hash: "f6b86c3a1cc88357f588b6dae11aae30" + } + Frame { + msec: 3632 + hash: "b10c23937f420db72af8abaf126f71c2" + } + Frame { + msec: 3648 + hash: "7d6b0810ffc6e488c8168e19bccb7358" + } + Frame { + msec: 3664 + hash: "c01ef69ec46391909619434e9d9dd0ce" + } + Frame { + msec: 3680 + hash: "a046464fccb0c5ba1f63f8b569821a44" + } + Frame { + msec: 3696 + hash: "8763c526924d882438f9aa9bfb4fe87d" + } + Frame { + msec: 3712 + hash: "dede7a62d6e5c10e8f30caa075bd8dfd" + } + Frame { + msec: 3728 + hash: "3b408e5c986f5bb01d8c3949876b792f" + } + Frame { + msec: 3744 + hash: "0a458f3b17cdd3ea85522779c9346af9" + } + Frame { + msec: 3760 + hash: "fef521f0301cce90af88d37e6d441ec8" + } + Frame { + msec: 3776 + hash: "3d083e0822242b3b37c6839ca91a1f68" + } + Frame { + msec: 3792 + hash: "f8fe013a717e6e61830137bdc78a8b40" + } + Frame { + msec: 3808 + hash: "0ae80ad65dd194043500fa50b5a547a6" + } + Frame { + msec: 3824 + hash: "a53c67fa32ef971eaea202fa5d8a6ad6" + } + Frame { + msec: 3840 + image: "easefollow.3.png" + } + Frame { + msec: 3856 + hash: "41f86bbf0658b127f01e8d46d7ec941b" + } + Frame { + msec: 3872 + hash: "d20f21df127565f9eb87c5d759a638d9" + } + Frame { + msec: 3888 + hash: "85ff94f03cea3e111807e90d062c1367" + } + Frame { + msec: 3904 + hash: "aa637850fe5f05a71ac4c7d31dbb36ee" + } + Frame { + msec: 3920 + hash: "c86a67096c5e62bb73b785cdf6a5b6b1" + } + Frame { + msec: 3936 + hash: "9d53537f2c50a0016bf7bb522b2ec3d8" + } + Frame { + msec: 3952 + hash: "b48630c27c27785ddce568a85d4dc58f" + } + Frame { + msec: 3968 + hash: "01c1bdb6e261cc509f26712b13eeb554" + } + Frame { + msec: 3984 + hash: "af8a44284695fd999acd5944434f0372" + } + Frame { + msec: 4000 + hash: "b156d9d6d5163f007ac4a309d8927ae9" + } + Frame { + msec: 4016 + hash: "2df3715416c3c005f04b66fe1258c0d8" + } + Frame { + msec: 4032 + hash: "96b4a7c6b8542b50fc345b54d38ec82a" + } + Frame { + msec: 4048 + hash: "7e62e757fafa06833444c3a7e1d96ce4" + } + Frame { + msec: 4064 + hash: "5222a8f9366c7d974d0687d05d229069" + } + Frame { + msec: 4080 + hash: "ec96169f4633c3bddfd582feeb8e9ad4" + } + Frame { + msec: 4096 + hash: "cb10db893d1e1cb2a370507dc5679985" + } + Frame { + msec: 4112 + hash: "d7e346c2ac77796bde639bd829b72e85" + } + Frame { + msec: 4128 + hash: "ba5bea8857e4fb444bedd3873563e7db" + } + Frame { + msec: 4144 + hash: "05556fba5d1714f70fd6c2bfb43d213b" + } + Frame { + msec: 4160 + hash: "aeeabf35f9759f045a670a9b9f90dc68" + } + Frame { + msec: 4176 + hash: "131bd453f4c7726e5fdd546252700e2e" + } + Frame { + msec: 4192 + hash: "7c5c3b5bb7a4082e6b9b43640e29f4e2" + } + Frame { + msec: 4208 + hash: "07515e21b7a7895f333e4a8bbd2202eb" + } + Frame { + msec: 4224 + hash: "6cf136f223ac6edd39ba6ed9b4445884" + } + Frame { + msec: 4240 + hash: "84264f5745add8a922101735ed8def84" + } + Frame { + msec: 4256 + hash: "660863d1e4b361f2e5445b417be0d2ad" + } + Frame { + msec: 4272 + hash: "7ceb86f4b16546370d72164d0ca3147c" + } + Frame { + msec: 4288 + hash: "a13e97da9722545ad87ac3c5eb92c497" + } + Frame { + msec: 4304 + hash: "5896b5307cbd609d2062d3607786d40c" + } + Frame { + msec: 4320 + hash: "c8c511115394116e4544c67f615ea5d5" + } + Frame { + msec: 4336 + hash: "59ca5fdf12a735e5c292901b54acccb2" + } + Frame { + msec: 4352 + hash: "155cce2738d34e0eac86f5eb63d638f0" + } + Frame { + msec: 4368 + hash: "83a840c3ae7dbd9a05c17fdd8be07d7a" + } + Frame { + msec: 4384 + hash: "800a15de28b14d88f0ad58fc3f4a2520" + } + Frame { + msec: 4400 + hash: "c8381439a3cd3f9e7f80061023723a6e" + } + Frame { + msec: 4416 + hash: "e3d63000db4b9458b202dece49d1bdba" + } + Frame { + msec: 4432 + hash: "c943e56781695798f3c221f8ab09681a" + } + Frame { + msec: 4448 + hash: "1137ee66d7fbf5a84c33f5ffff15b3dd" + } + Frame { + msec: 4464 + hash: "5a98013cc4462aad18cad8d941f77aa0" + } + Frame { + msec: 4480 + hash: "d0b3748fb49a13c0ad9a68b0e2914921" + } + Frame { + msec: 4496 + hash: "12113f71f9117670acbd7877edded7e0" + } + Frame { + msec: 4512 + hash: "22983424da08cdae7a9c6a8905b37736" + } + Frame { + msec: 4528 + hash: "b2db5618a025cefb2650124c81880c49" + } + Frame { + msec: 4544 + hash: "84fb5e7edc5b42163a83e0cd362b3a46" + } + Frame { + msec: 4560 + hash: "39d6f1ed0f60a0c366c22e1442c455ac" + } + Frame { + msec: 4576 + hash: "702367f6e4aaa2a862e57f9e02a08758" + } + Frame { + msec: 4592 + hash: "ecc75293bc156c560d55cb7d278a4e58" + } + Frame { + msec: 4608 + hash: "e68af8e97ce65376fd7904e599440c92" + } + Frame { + msec: 4624 + hash: "75fe9f766d6cf636cd72d8879a461439" + } + Frame { + msec: 4640 + hash: "162aef147ef4bbb0cd92bd70e4f37f62" + } + Frame { + msec: 4656 + hash: "d879aae8949976c7bad4d97f1e5b5549" + } + Frame { + msec: 4672 + hash: "8a983d7228190721f988de2d72cb3aa2" + } + Frame { + msec: 4688 + hash: "a4f3c63fde664d128cd35b129a4f9a23" + } + Frame { + msec: 4704 + hash: "115fb5f3c9b7f1c28ab379596faba91c" + } + Frame { + msec: 4720 + hash: "ea9600c4d6c77a3b32e59401aa84fe96" + } + Frame { + msec: 4736 + hash: "bd6531fdd9cfd46af2df73bacb31f4c5" + } + Frame { + msec: 4752 + hash: "33bdcf1df50eab5e7963c649fbd32226" + } + Frame { + msec: 4768 + hash: "236e88fb72369a55f9eba4b50712ae85" + } + Frame { + msec: 4784 + hash: "5eb3c14a6296fb3a1c58603b2fc937c8" + } + Frame { + msec: 4800 + image: "easefollow.4.png" + } + Frame { + msec: 4816 + hash: "31d11a1ce6422524241c77603fe53e61" + } + Frame { + msec: 4832 + hash: "44e8b9947026c10b922c84883dd8e889" + } + Frame { + msec: 4848 + hash: "d049e4f7c4bc1849398859a4d630c1b3" + } + Frame { + msec: 4864 + hash: "e83b4757898e4eeef74be8213619fbfa" + } + Frame { + msec: 4880 + hash: "d08f40615f2d5abc6236e856a67575dd" + } + Frame { + msec: 4896 + hash: "d9cb26bf1b8bbafb2aed8f74bd454077" + } + Frame { + msec: 4912 + hash: "aa321b94a6cc53b2ebac80e834c0a908" + } + Frame { + msec: 4928 + hash: "48da37164be156b67a4b3b14e50f2375" + } + Frame { + msec: 4944 + hash: "f522ce7728a4a9e7fad86c72f29bd8f9" + } + Frame { + msec: 4960 + hash: "9bc1d16b4bda596702a3d8a3fad8a5c5" + } + Frame { + msec: 4976 + hash: "5275dccf18745dec6c59b846de17d9ef" + } + Frame { + msec: 4992 + hash: "4eb6babc177b96f69b148d52f56d82d7" + } + Frame { + msec: 5008 + hash: "ccdfb454070ac04c4fe4f3513c52f8c8" + } + Frame { + msec: 5024 + hash: "07f6adad6e8ff4f0eff92c758636a951" + } + Frame { + msec: 5040 + hash: "241e0ad9218d49be477509e008e45548" + } + Frame { + msec: 5056 + hash: "151a482e821779da8a61063f1cc73f8c" + } + Frame { + msec: 5072 + hash: "1499d207c5a3a9bc7bbb84d9c5e35578" + } + Frame { + msec: 5088 + hash: "c253753f653157a5058ef071f16b8bbb" + } + Frame { + msec: 5104 + hash: "ec9fea5a870724a106b952edef7fb466" + } + Frame { + msec: 5120 + hash: "99b673f8ed049d31a2aecabcc46d841d" + } + Frame { + msec: 5136 + hash: "61e77fea693ea55aafbdc94c40c3ab33" + } + Frame { + msec: 5152 + hash: "53e44a3732ee6858d5bd596b4c5d5305" + } + Frame { + msec: 5168 + hash: "5b25d3894a56dc4f4a0aa8f88cb69e23" + } + Frame { + msec: 5184 + hash: "5683ad02f1b9126f4e4ff6b03044fdc6" + } + Frame { + msec: 5200 + hash: "0a3ec255575ec1b70e0b10cf59c7c5fd" + } + Frame { + msec: 5216 + hash: "0f5f46fe3fdf42d4651891f13c8afc7e" + } + Frame { + msec: 5232 + hash: "b6955407245c73e356a460d99dad77be" + } + Frame { + msec: 5248 + hash: "6018b53414921943b37c33fa04a29697" + } + Frame { + msec: 5264 + hash: "ff184d349ce0b648f8c1fce91ae997f6" + } + Frame { + msec: 5280 + hash: "9c112a3a785d970593887eeab72fa7fe" + } + Frame { + msec: 5296 + hash: "00384fb20d4c6cd6236d519d2d734cc3" + } + Frame { + msec: 5312 + hash: "601ea99400e5f50ee9a5a4b74b6f3017" + } + Frame { + msec: 5328 + hash: "9afed04bf7eca24d9b6d31ac84ae59c2" + } + Frame { + msec: 5344 + hash: "1983319c8043bfe403513af7ccb5b924" + } + Frame { + msec: 5360 + hash: "b0244e4e1b61202ede78405415c22bca" + } + Frame { + msec: 5376 + hash: "ec5516b1aaeace8784b04649c51ab40b" + } + Frame { + msec: 5392 + hash: "8ff7d2001594abb588f769bab15406d7" + } + Frame { + msec: 5408 + hash: "64d5fd96a1726aa5276f9b508566676f" + } + Frame { + msec: 5424 + hash: "ab49497a6c825038354f076bdbbbc235" + } + Frame { + msec: 5440 + hash: "6b821e43be932800b20af58a7b5a1ff7" + } + Frame { + msec: 5456 + hash: "683a2902300f930e2a81a82dc37c583b" + } + Frame { + msec: 5472 + hash: "86d7946d7fbb66369ccbf26430939225" + } + Frame { + msec: 5488 + hash: "fb38f5fb6555fc14e95a47c595a6ea0c" + } + Frame { + msec: 5504 + hash: "3878f685d9fa3299e9ffe78c22595387" + } + Frame { + msec: 5520 + hash: "b48840a68ff007901b02332c7177f315" + } + Frame { + msec: 5536 + hash: "9d847abc99220b04aceef12e5c09aac0" + } + Frame { + msec: 5552 + hash: "9893ac89fda64d96ec4140c3c87e17a5" + } + Frame { + msec: 5568 + hash: "cd94e1c36e6be9877cd9c12df42bd968" + } + Frame { + msec: 5584 + hash: "c1ce5e53b74af022dc103ad74ff5f1af" + } + Frame { + msec: 5600 + hash: "b3630e08eac02a9578a00b01baabaaba" + } + Frame { + msec: 5616 + hash: "0eb9241aa1f9526c1e24ba76d630805c" + } + Frame { + msec: 5632 + hash: "1b532ae7f9253469467522d4ca66c47b" + } + Frame { + msec: 5648 + hash: "7e6e49079ed6330da2e337a5e4ffd730" + } + Frame { + msec: 5664 + hash: "0391d668f4b906b244a5f5c1713573c2" + } + Frame { + msec: 5680 + hash: "8070fa3280d0d64bf976d4a276359c4c" + } + Frame { + msec: 5696 + hash: "f7d0d36a2d40c798f56ac7ecc1effca6" + } + Frame { + msec: 5712 + hash: "9f8e35ee5080e811c670c480a9c2bd9f" + } + Frame { + msec: 5728 + hash: "c7fea75a43a59a11aa504df32afcdaf8" + } + Frame { + msec: 5744 + hash: "7e549a93ffc6ddcc3d8111f10c05b29e" + } + Frame { + msec: 5760 + image: "easefollow.5.png" + } + Frame { + msec: 5776 + hash: "92d298262f610a2dafa095e3d67c80af" + } + Frame { + msec: 5792 + hash: "db8826b0b2feece0999863b8827a6234" + } + Frame { + msec: 5808 + hash: "12c7050e8094bb39212aed0163666d1a" + } + Frame { + msec: 5824 + hash: "69531beace5c749bf90160a4b25f736a" + } + Frame { + msec: 5840 + hash: "ce873e4dbc8853183b54d59991b2e030" + } + Frame { + msec: 5856 + hash: "fa1078973634578d69527402b11fb7e0" + } + Frame { + msec: 5872 + hash: "1e3b3db590567c0afd1913101192cda9" + } + Frame { + msec: 5888 + hash: "7b9e097018278b784973a546da3d401a" + } + Frame { + msec: 5904 + hash: "a7b0667093888480de6697280aeea9ba" + } + Frame { + msec: 5920 + hash: "e381f2422ead86575abf643b0b0c9797" + } + Frame { + msec: 5936 + hash: "44b08f5a0de2a6955e02f67753f409c8" + } + Frame { + msec: 5952 + hash: "db04665e58448ecc7f95baa3e4ea79a5" + } + Frame { + msec: 5968 + hash: "0e4aae728d8d543538a9446c41e18e91" + } + Frame { + msec: 5984 + hash: "e3cd1bbb1d9963e5c74d36e526a871b0" + } + Frame { + msec: 6000 + hash: "bcd893a0e200ddda4e1468c159018865" + } + Frame { + msec: 6016 + hash: "9c5293356aa6312f909e655e9bcf961b" + } + Frame { + msec: 6032 + hash: "0bab7b9166f6af554d4fa0badeec739e" + } + Frame { + msec: 6048 + hash: "e74996581f0aaeced118c5cbfd977d90" + } + Frame { + msec: 6064 + hash: "5d128eb20a2a23da8c2d9a35293e5769" + } + Frame { + msec: 6080 + hash: "ebbbc343698287faf7ffa7526a726b54" + } + Frame { + msec: 6096 + hash: "d812172192cc19590f9a2d7dbf970439" + } + Frame { + msec: 6112 + hash: "60263addb1b4b5ac43f8199b8ed77e40" + } + Frame { + msec: 6128 + hash: "702a1ff2876eaaa59359811bb6437c5b" + } + Frame { + msec: 6144 + hash: "8f81dc43decce5094ee7a089f0009730" + } + Frame { + msec: 6160 + hash: "efda5dd9edd83a0da089d0b28806c6b6" + } + Frame { + msec: 6176 + hash: "7274a33a7a5272d7abdaf41f4b2bf664" + } + Frame { + msec: 6192 + hash: "0cc80077476e721a3da85c17cc56a65e" + } + Frame { + msec: 6208 + hash: "e65a534f0e7e70520a9c2cfa09ee8159" + } + Frame { + msec: 6224 + hash: "b05b514c63bd8998785382e6a9cbd849" + } + Frame { + msec: 6240 + hash: "10a04d641e0cc65c120d8bcf2f3e54c8" + } + Frame { + msec: 6256 + hash: "68418e2206a496dd15a05b50fec6f87e" + } + Frame { + msec: 6272 + hash: "6549e0989e1c86e3a7eb0dcc8dd31380" + } + Frame { + msec: 6288 + hash: "bd0193c2cbc8958f674f4ec52a693b72" + } + Frame { + msec: 6304 + hash: "746440b45a3688dbd32b34c57454e956" + } + Frame { + msec: 6320 + hash: "6b54ee8af30be2178e8b3afab5dcb4c7" + } + Frame { + msec: 6336 + hash: "ba2fbad3fe2fe25ec0c0c542659168dc" + } + Frame { + msec: 6352 + hash: "84bd72703bd8200f8f090783d06ae451" + } + Frame { + msec: 6368 + hash: "17c9fb063280c2ee4cb4a13273bbb199" + } + Frame { + msec: 6384 + hash: "df28fd55719f5c2d164596d02c2faff2" + } + Frame { + msec: 6400 + hash: "c2e280e78e892200d40022d17ce695b7" + } + Frame { + msec: 6416 + hash: "c657caa0c5158e178ec5df80bbad6bcb" + } + Frame { + msec: 6432 + hash: "d91f4f6ec6503fe8280f9b02dd11e64a" + } + Frame { + msec: 6448 + hash: "0fb9400cdca9dbd4035fbf8af9952360" + } + Frame { + msec: 6464 + hash: "cac0e1b4aa094306b95f90ede4705391" + } + Frame { + msec: 6480 + hash: "e60a4bb14300a937a767effee931c60f" + } + Frame { + msec: 6496 + hash: "8b461397e3f210ee7e9305dcab2af2db" + } + Frame { + msec: 6512 + hash: "6ce9ec0942dd06c9f73929a7e176852c" + } + Frame { + msec: 6528 + hash: "da36e254635eea854a6552ba008117f9" + } + Frame { + msec: 6544 + hash: "0bec6402b5eb09d05ce8e9ff5253ea8d" + } + Frame { + msec: 6560 + hash: "72f6610527d395ca590eda166ef6bc4e" + } + Frame { + msec: 6576 + hash: "622ae3fd47adb2432e2a40d3c5539393" + } + Frame { + msec: 6592 + hash: "0b18c49e2bbf9370216e06b555faf183" + } + Frame { + msec: 6608 + hash: "0c090bb975fb883301b52479fd6f5fdf" + } + Frame { + msec: 6624 + hash: "c4205d7ecb7327426d9591e77247acab" + } + Frame { + msec: 6640 + hash: "f0e0075243e4b8aa97056248fe6033ed" + } + Frame { + msec: 6656 + hash: "47f99b40a8764ee9d9e429061fb7acb2" + } + Frame { + msec: 6672 + hash: "49e8c1e974b0716570d85109b53817a5" + } + Frame { + msec: 6688 + hash: "72f981bad831b6ed858009527902f734" + } + Frame { + msec: 6704 + hash: "e959a0493b06369a429f90f66cb65977" + } + Frame { + msec: 6720 + image: "easefollow.6.png" + } + Frame { + msec: 6736 + hash: "93470d983282f24425558f47ad705154" + } + Frame { + msec: 6752 + hash: "cdccbe1a7c7abd4a6a6ee754ed0c9759" + } + Frame { + msec: 6768 + hash: "0e1b7b5332a9fcdb492db5314a2a0267" + } + Frame { + msec: 6784 + hash: "1e1ffe3439aab51d0b325474e7d8dc28" + } + Frame { + msec: 6800 + hash: "e8e7e9b5871caf77f15678616d6c9c8a" + } + Frame { + msec: 6816 + hash: "9771fff3b7752154d093c038bea73d28" + } + Frame { + msec: 6832 + hash: "1af851ea214cbddb0e3a743084a5cf6b" + } + Frame { + msec: 6848 + hash: "1566182a7e29bbb738705a90c4909617" + } + Frame { + msec: 6864 + hash: "feed650e1d948fe622234d212fb745f2" + } + Frame { + msec: 6880 + hash: "3cd3d063275b91f9680717421c118ba4" + } + Frame { + msec: 6896 + hash: "c1f088801334762cd499e7cc70e1e59a" + } + Frame { + msec: 6912 + hash: "e8f8d153e7a027a5092a9209411d97f7" + } + Frame { + msec: 6928 + hash: "f11747c3533b4b2fc77a64ca0cace8b0" + } + Frame { + msec: 6944 + hash: "21618c67a2a8bbce86fc872060ad40e8" + } + Frame { + msec: 6960 + hash: "02da96335db74b87ceefe91b1dfe72e6" + } + Frame { + msec: 6976 + hash: "2b2e4143143ead8dea5865fd782f1775" + } + Frame { + msec: 6992 + hash: "13e710900b05e26cdb030b1e2b2be715" + } + Frame { + msec: 7008 + hash: "29e8995d17aac4d02034debcbb9fcb98" + } + Frame { + msec: 7024 + hash: "1099db1b3e4c69e84c6ab1b7c311bf1e" + } + Frame { + msec: 7040 + hash: "cc7cb720043334f1eeb385dce4389dc2" + } + Frame { + msec: 7056 + hash: "34c7a62c1bc7261e2fd31c40068b37a7" + } + Frame { + msec: 7072 + hash: "7fafbe05cbcaa21893e3aa0f1fcfb5a0" + } + Key { + type: 6 + key: 16777249 + modifiers: 67108864 + text: "" + autorep: false + count: 1 + } + Frame { + msec: 7088 + hash: "5b26c8cf047706633795a8ed3e703a89" + } + Frame { + msec: 7104 + hash: "e0774bf9e74d0cde81c5cb216a9258fc" + } + Frame { + msec: 7120 + hash: "0870262f643245e13f4fba79fd575897" + } + Frame { + msec: 7136 + hash: "8faf0d050bb435ade8af5012c1a6b0dc" + } + Frame { + msec: 7152 + hash: "382c037895cc39a6870db57b5016c01f" + } + Frame { + msec: 7168 + hash: "f1f5a2cbc103ab1bee9f537fa8266e03" + } +} diff --git a/tests/auto/declarative/qmlvisual/qdeclarativesmoothedanimation/smoothedanimation.qml b/tests/auto/declarative/qmlvisual/qdeclarativesmoothedanimation/smoothedanimation.qml new file mode 100644 index 0000000..ee94857 --- /dev/null +++ b/tests/auto/declarative/qmlvisual/qdeclarativesmoothedanimation/smoothedanimation.qml @@ -0,0 +1,45 @@ +import Qt 4.6 + +Rectangle { + width: 800; height: 240; color: "gray" + + Rectangle { + id: rect + width: 50; height: 20; y: 30; color: "black" + SequentialAnimation on x { + loops: Animation.Infinite + NumberAnimation { from: 50; to: 700; duration: 2000 } + NumberAnimation { from: 700; to: 50; duration: 2000 } + } + } + + Rectangle { + width: 50; height: 20; y: 60; color: "red" + x: rect.x + Behavior on x { SmoothedAnimation { velocity: 400 } } + } + + Rectangle { + width: 50; height: 20; y: 90; color: "yellow" + x: rect.x + Behavior on x { SmoothedAnimation { velocity: 300; reversingMode: SmoothedAnimation.Immediate } } + } + + Rectangle { + width: 50; height: 20; y: 120; color: "green" + x: rect.x + Behavior on x { SmoothedAnimation { reversingMode: SmoothedAnimation.Sync } } + } + + Rectangle { + width: 50; height: 20; y: 150; color: "purple" + x: rect.x + Behavior on x { SmoothedAnimation { maximumEasingTime: 200 } } + } + + Rectangle { + width: 50; height: 20; y: 180; color: "blue" + x: rect.x + Behavior on x { SmoothedAnimation { duration: 300 } } + } +} -- cgit v0.12 From 444c52937410a0581a8bb93c9bee2245a84fe24c Mon Sep 17 00:00:00 2001 From: Leonardo Sobral Cunha Date: Mon, 29 Mar 2010 15:44:09 +1000 Subject: Fixes PathView compile warnings --- src/declarative/graphicsitems/qdeclarativepathview.cpp | 2 +- src/declarative/graphicsitems/qdeclarativepathview_p_p.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/declarative/graphicsitems/qdeclarativepathview.cpp b/src/declarative/graphicsitems/qdeclarativepathview.cpp index c2cfbb1..71f85ae 100644 --- a/src/declarative/graphicsitems/qdeclarativepathview.cpp +++ b/src/declarative/graphicsitems/qdeclarativepathview.cpp @@ -1193,7 +1193,7 @@ void QDeclarativePathView::itemsRemoved(int modelIndex, int count) emit countChanged(); } -void QDeclarativePathView::itemsMoved(int from, int to, int count) +void QDeclarativePathView::itemsMoved(int /*from*/, int /*to*/, int /*count*/) { Q_D(QDeclarativePathView); if (!d->isValid() || !isComponentComplete()) diff --git a/src/declarative/graphicsitems/qdeclarativepathview_p_p.h b/src/declarative/graphicsitems/qdeclarativepathview_p_p.h index 26ec4e5..6470893 100644 --- a/src/declarative/graphicsitems/qdeclarativepathview_p_p.h +++ b/src/declarative/graphicsitems/qdeclarativepathview_p_p.h @@ -79,9 +79,9 @@ public: , stealMouse(false), ownModel(false), interactive(true), haveHighlightRange(true) , autoHighlight(true), highlightUp(false), dragMargin(0), deceleration(100) , moveOffset(this, &QDeclarativePathViewPrivate::setOffset) - , moveHighlight(this, &QDeclarativePathViewPrivate::setHighlightPosition) , firstIndex(-1), pathItems(-1), requestedIndex(-1) , moveReason(Other), attType(0), highlightComponent(0), highlightItem(0) + , moveHighlight(this, &QDeclarativePathViewPrivate::setHighlightPosition) , highlightPosition(0) , highlightRangeStart(0), highlightRangeEnd(0) , highlightRangeMode(QDeclarativePathView::StrictlyEnforceRange) -- cgit v0.12 From 859304f5a8d9169a3f2f30e013d460b0e93c118f Mon Sep 17 00:00:00 2001 From: Martin Jones Date: Tue, 30 Mar 2010 15:45:18 +1000 Subject: Make visual tests run on windows --- tests/auto/declarative/qmlvisual/tst_qmlvisual.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/auto/declarative/qmlvisual/tst_qmlvisual.cpp b/tests/auto/declarative/qmlvisual/tst_qmlvisual.cpp index 8f1a406..2794ab8 100644 --- a/tests/auto/declarative/qmlvisual/tst_qmlvisual.cpp +++ b/tests/auto/declarative/qmlvisual/tst_qmlvisual.cpp @@ -106,7 +106,6 @@ void tst_qmlvisual::visual_data() files << QT_TEST_SOURCE_DIR "/animation/reanchor/reanchor.qml"; } - foreach (const QString &file, files) { QString testdata = toTestScript(file); if (testdata.isEmpty()) @@ -141,6 +140,8 @@ QString tst_qmlvisual::toTestScript(const QString &file, Mode mode) int index = file.lastIndexOf(QDir::separator()); if (index == -1) + index = file.lastIndexOf('/'); + if (index == -1) return QString(); const char* platformsuffix=0; // platforms with different fonts -- cgit v0.12 From ff983ee8257b79143911ca58ebedc49b1660a0c4 Mon Sep 17 00:00:00 2001 From: Martin Jones Date: Tue, 30 Mar 2010 16:03:29 +1000 Subject: Make qmlpixmapcache thread shutdown cleaner Change to Thiago's method: QThread::quit() is *not* thread-safe, so we mustn't call it from outside the QThread that the QThread holds. Unlike other QObjects, this method and some others must not be called from the thread they have affinity to. So add a hack to call it in the auxiliary thread. Do that by connecting a dummy QObject's destroyed() signal to the quit() slot in a DirectConnection, then move the object to the thread. When we call deleteLater(), this will cause the thread's event loop to delete the object, which in turn calls quit() in the actual thread. Reviewed-by: Thiago Macieira --- src/declarative/util/qdeclarativepixmapcache.cpp | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/src/declarative/util/qdeclarativepixmapcache.cpp b/src/declarative/util/qdeclarativepixmapcache.cpp index a9c30f8..1da929e 100644 --- a/src/declarative/util/qdeclarativepixmapcache.cpp +++ b/src/declarative/util/qdeclarativepixmapcache.cpp @@ -114,7 +114,7 @@ private: QList cancelled; QDeclarativeEngine *engine; QDeclarativeImageRequestHandler *handler; - QWaitCondition started; + QObject *eventLoopQuitHack; QMutex mutex; static QHash readers; @@ -370,6 +370,9 @@ void QDeclarativeImageRequestHandler::networkRequestDone() QDeclarativeImageReader::QDeclarativeImageReader(QDeclarativeEngine *eng) : QThread(eng), engine(eng), handler(0) { + eventLoopQuitHack = new QObject; + eventLoopQuitHack->moveToThread(this); + connect(eventLoopQuitHack, SIGNAL(destroyed(QObject*)), SLOT(quit()), Qt::DirectConnection); start(QThread::IdlePriority); } @@ -379,15 +382,8 @@ QDeclarativeImageReader::~QDeclarativeImageReader() readers.remove(engine); readerMutex.unlock(); - if (isRunning()) { - quit(); - while (!wait(100)) { - // It is possible to for the quit to happen before exec() - // Need to wait until the event loop starts so that we - // can stop it. Particularly likely with an idle thread. - quit(); - } - } + eventLoopQuitHack->deleteLater(); + wait(); } QDeclarativeImageReader *QDeclarativeImageReader::instance(QDeclarativeEngine *engine) @@ -396,7 +392,6 @@ QDeclarativeImageReader *QDeclarativeImageReader::instance(QDeclarativeEngine *e QDeclarativeImageReader *reader = readers.value(engine); if (!reader) { reader = new QDeclarativeImageReader(engine); - reader->started.wait(&readerMutex); readers.insert(engine, reader); } readerMutex.unlock(); @@ -433,7 +428,6 @@ void QDeclarativeImageReader::run() { readerMutex.lock(); handler = new QDeclarativeImageRequestHandler(this, engine); - started.wakeAll(); readerMutex.unlock(); exec(); -- cgit v0.12 From 2661be1bacdd83d1b3e6207c519c2699edfdc1d0 Mon Sep 17 00:00:00 2001 From: Bea Lam Date: Tue, 30 Mar 2010 15:25:01 +1000 Subject: WorkerScript was receiving events after deletion and trying to process these events. --- src/declarative/qml/qdeclarativeworkerscript.cpp | 6 +++++- .../qdeclarativelistmodel/tst_qdeclarativelistmodel.cpp | 11 ++++------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/declarative/qml/qdeclarativeworkerscript.cpp b/src/declarative/qml/qdeclarativeworkerscript.cpp index a7ed358..628681f 100644 --- a/src/declarative/qml/qdeclarativeworkerscript.cpp +++ b/src/declarative/qml/qdeclarativeworkerscript.cpp @@ -437,8 +437,12 @@ QDeclarativeWorkerScriptEngine::QDeclarativeWorkerScriptEngine(QDeclarativeEngin QDeclarativeWorkerScriptEngine::~QDeclarativeWorkerScriptEngine() { + d->m_lock.lock(); qDeleteAll(d->workers); - delete d; d = 0; + d->workers.clear(); + d->m_lock.unlock(); + + d->deleteLater(); } QDeclarativeWorkerScriptEnginePrivate::WorkerScript::WorkerScript() diff --git a/tests/auto/declarative/qdeclarativelistmodel/tst_qdeclarativelistmodel.cpp b/tests/auto/declarative/qdeclarativelistmodel/tst_qdeclarativelistmodel.cpp index fcb453c..12000d0 100644 --- a/tests/auto/declarative/qdeclarativelistmodel/tst_qdeclarativelistmodel.cpp +++ b/tests/auto/declarative/qdeclarativelistmodel/tst_qdeclarativelistmodel.cpp @@ -193,7 +193,7 @@ void tst_QDeclarativeListModel::dynamic_data() QTest::newRow("clear1") << "{append({'foo':456});clear();count}" << 0 << ""; QTest::newRow("clear2") << "{append({'foo':123});append({'foo':456});clear();count}" << 0 << ""; - QTest::newRow("clear2") << "{append({'foo':123});clear();get(0).foo}" << 0 << "QML ListModel (unknown location) get: index 0 out of range"; + QTest::newRow("clear3") << "{append({'foo':123});clear();get(0).foo}" << 0 << "QML ListModel (unknown location) get: index 0 out of range"; QTest::newRow("remove1") << "{append({'foo':123});remove(0);count}" << 0 << ""; QTest::newRow("remove2a") << "{append({'foo':123});append({'foo':456});remove(0);count}" << 1 << ""; @@ -290,8 +290,6 @@ void tst_QDeclarativeListModel::dynamic_worker_data() void tst_QDeclarativeListModel::dynamic_worker() { - QSKIP("", SkipAll); - QFETCH(QString, script); QFETCH(int, result); QFETCH(QString, warning); @@ -324,6 +322,7 @@ void tst_QDeclarativeListModel::dynamic_worker() // changes are reflected in the list model in the main thread if (QByteArray(QTest::currentDataTag()).startsWith("nested")) QTest::ignoreMessage(QtWarningMsg, "QML ListModel (unknown location) Cannot add nested list values when modifying or after modification from a worker script"); + QVERIFY(QMetaObject::invokeMethod(item, "evalExpressionViaWorker", Q_ARG(QVariant, operations.mid(0, operations.length()-1)))); waitForWorker(item); @@ -342,7 +341,6 @@ void tst_QDeclarativeListModel::dynamic_worker() void tst_QDeclarativeListModel::convertNestedToFlat_fail() { - QSKIP("", SkipAll); // If a model has nested data, it cannot be used at all from a worker script QFETCH(QString, script); @@ -368,7 +366,7 @@ void tst_QDeclarativeListModel::convertNestedToFlat_fail() delete item; QTest::ignoreMessage(QtWarningMsg, "QThread: Destroyed while thread is still running"); - qApp->processEvents(); + qApp->processEvents(); } void tst_QDeclarativeListModel::convertNestedToFlat_fail_data() @@ -387,7 +385,6 @@ void tst_QDeclarativeListModel::convertNestedToFlat_fail_data() void tst_QDeclarativeListModel::convertNestedToFlat_ok() { - QSKIP("", SkipAll); // If a model only has plain data, it can be modified from a worker script. However, // once the model is used from a worker script, it no longer accepts nested data @@ -429,7 +426,7 @@ void tst_QDeclarativeListModel::convertNestedToFlat_ok() delete item; QTest::ignoreMessage(QtWarningMsg, "QThread: Destroyed while thread is still running"); - qApp->processEvents(); + qApp->processEvents(); } void tst_QDeclarativeListModel::convertNestedToFlat_ok_data() -- cgit v0.12 From 8c4f8e259d60c98361d20f495e3af252bcef24a0 Mon Sep 17 00:00:00 2001 From: Justin McPherson Date: Tue, 30 Mar 2010 16:11:03 +1000 Subject: Fix typo in phonon/symbian. Reviewed-by: Dmytro Poplavskiy --- src/3rdparty/phonon/phonon/factory.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/3rdparty/phonon/phonon/factory.cpp b/src/3rdparty/phonon/phonon/factory.cpp index 24be0f3..2785dff 100644 --- a/src/3rdparty/phonon/phonon/factory.cpp +++ b/src/3rdparty/phonon/phonon/factory.cpp @@ -143,7 +143,7 @@ bool FactoryPrivate::createBackend() * sophisticated, so we make sure the Helix backend is attempted * to be loaded first, and the MMF backend is used for backup. */ { - const int helix = plugins.indexof(QLatin1String("hxphonon")); + const int helix = plugins.indexOf(QLatin1String("hxphonon")); if (helix != -1) plugins.move(helix, 0); } -- cgit v0.12 From 1190f901cbcc62ab50c66bf0a7c41bfba923da7f Mon Sep 17 00:00:00 2001 From: Leonardo Sobral Cunha Date: Tue, 30 Mar 2010 16:31:26 +1000 Subject: Update QmlChanges for SmoothedAnimation --- src/declarative/QmlChanges.txt | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src/declarative/QmlChanges.txt b/src/declarative/QmlChanges.txt index 847f1f5..c86bdc6 100644 --- a/src/declarative/QmlChanges.txt +++ b/src/declarative/QmlChanges.txt @@ -32,6 +32,39 @@ syntax has been introduced: Item { Behavior on x {}; NumberAnimation on y {} } Only the syntax has changed, the behavior is identical. + +EaseFollow changed to SmoothedAnimation +--------------------------------------- +EaseFollow was renamed to SmoothedAnimation and now it inherits from +NumberAnimaton and as a consequence SmoothedAnimation can be used inside +Behaviors, as PropertySourceValues or in state transitions, like any other animation. + +The old EaseFollow properties changed to comply with the other declarative +animations ('source' changed to 'to'), so now 'to' changes are not +automatically 'followed' anymore. + +If you want to follow an hypothetical rect1, you should do now: + +     Rectangle { +         color: "green" +         width: 60; height: 60; +         x: rect1.x - 5; y: rect1.y - 5; +         Behavior on x { SmoothedAnimation { velocity: 200 } } +         Behavior on y { SmoothedAnimation { velocity: 200 } } +     } + +instead of the old automatic source changed tracking: + +     Rectangle { +         color: "green" +         width: 60; height: 60; +         EaseFollow on x { source: rect1.x - 5; velocity: 200 } +         EaseFollow on y { source: rect1.y - 5; velocity: 200 } +    } + +This is a syntax and behavior change. + + Script element removed ---------------------- Inline Script{} blocks have been deprecated, and will soon be removed entirely. -- cgit v0.12 From b9b305f6c7bc960101bfd883ca6e3df889483481 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Tue, 30 Mar 2010 16:37:28 +1000 Subject: Correctly construct boolean JSValue's Task-number: QTBUG-9205 --- src/script/bridge/qscriptdeclarativeclass.cpp | 12 +++++++++--- .../qdeclarativeecmascript/data/strictlyEquals.qml | 17 +++++++++++++++++ .../tst_qdeclarativeecmascript.cpp | 21 +++++++++++++++++++++ 3 files changed, 47 insertions(+), 3 deletions(-) create mode 100644 tests/auto/declarative/qdeclarativeecmascript/data/strictlyEquals.qml diff --git a/src/script/bridge/qscriptdeclarativeclass.cpp b/src/script/bridge/qscriptdeclarativeclass.cpp index acfb2a4..0f450ca 100644 --- a/src/script/bridge/qscriptdeclarativeclass.cpp +++ b/src/script/bridge/qscriptdeclarativeclass.cpp @@ -70,9 +70,12 @@ QScriptDeclarativeClass::Value::Value(QScriptContext *ctxt, uint value) new (this) JSC::JSValue(QScriptEnginePrivate::frameForContext(ctxt), value); } -QScriptDeclarativeClass::Value::Value(QScriptContext *ctxt, bool value) +QScriptDeclarativeClass::Value::Value(QScriptContext *, bool value) { - new (this) JSC::JSValue(QScriptEnginePrivate::frameForContext(ctxt), value); + if (value) + new (this) JSC::JSValue(JSC::JSValue::JSTrue); + else + new (this) JSC::JSValue(JSC::JSValue::JSFalse); } QScriptDeclarativeClass::Value::Value(QScriptContext *ctxt, double value) @@ -107,7 +110,10 @@ QScriptDeclarativeClass::Value::Value(QScriptEngine *eng, uint value) QScriptDeclarativeClass::Value::Value(QScriptEngine *eng, bool value) { - new (this) JSC::JSValue(QScriptEnginePrivate::get(eng)->currentFrame, value); + if (value) + new (this) JSC::JSValue(JSC::JSValue::JSTrue); + else + new (this) JSC::JSValue(JSC::JSValue::JSFalse); } QScriptDeclarativeClass::Value::Value(QScriptEngine *eng, double value) diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/strictlyEquals.qml b/tests/auto/declarative/qdeclarativeecmascript/data/strictlyEquals.qml new file mode 100644 index 0000000..b9e455d --- /dev/null +++ b/tests/auto/declarative/qdeclarativeecmascript/data/strictlyEquals.qml @@ -0,0 +1,17 @@ +import Qt 4.6 + +QtObject { + property bool test1: (a === true) + property bool test2: !(a === false) + property bool test3: (b === 11.2) + property bool test4: !(b === 9) + property bool test5: (c === 9) + property bool test6: !(c === 13) + property bool test7: (d === "Hello world") + property bool test8: !(d === "Hi") + + property bool a: true + property real b: 11.2 + property int c: 9 + property string d: "Hello world" +} diff --git a/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp b/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp index 2791722c..b218d30 100644 --- a/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp +++ b/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp @@ -128,6 +128,7 @@ private slots: void scriptDisconnect(); void ownership(); void qlistqobjectMethods(); + void strictlyEquals(); void bug1(); void dynamicCreationCrash(); @@ -2005,6 +2006,26 @@ void tst_qdeclarativeecmascript::qlistqobjectMethods() delete object; } +// QTBUG-9205 +void tst_qdeclarativeecmascript::strictlyEquals() +{ + QDeclarativeComponent component(&engine, TEST_FILE("strictlyEquals.qml")); + + QObject *object = component.create(); + QVERIFY(object != 0); + + QCOMPARE(object->property("test1").toBool(), true); + QCOMPARE(object->property("test2").toBool(), true); + QCOMPARE(object->property("test3").toBool(), true); + QCOMPARE(object->property("test4").toBool(), true); + QCOMPARE(object->property("test5").toBool(), true); + QCOMPARE(object->property("test6").toBool(), true); + QCOMPARE(object->property("test7").toBool(), true); + QCOMPARE(object->property("test8").toBool(), true); + + delete object; +} + QTEST_MAIN(tst_qdeclarativeecmascript) #include "tst_qdeclarativeecmascript.moc" -- cgit v0.12