summaryrefslogtreecommitdiffstats
path: root/src/3rdparty/phonon/gstreamer
diff options
context:
space:
mode:
authorQt Continuous Integration System <qt-info@nokia.com>2010-03-29 02:44:55 (GMT)
committerQt Continuous Integration System <qt-info@nokia.com>2010-03-29 02:44:55 (GMT)
commit17388e0ca41bd123003fd3703bad8616491b562c (patch)
treee07c08070bb5f23fdd5f1cf1b4d42d13f07765a5 /src/3rdparty/phonon/gstreamer
parent4fb6cae4dd0c6a90008780df606abb8a9e73cb2c (diff)
parent1f802e16e6ab59dbf5ce450e2d6ef4db10dd7bb8 (diff)
downloadQt-17388e0ca41bd123003fd3703bad8616491b562c.zip
Qt-17388e0ca41bd123003fd3703bad8616491b562c.tar.gz
Qt-17388e0ca41bd123003fd3703bad8616491b562c.tar.bz2
Merge branch '4.7' of scm.dev.nokia.troll.no:qt/qt-multimedia-staging into 4.7-integration
* '4.7' of scm.dev.nokia.troll.no:qt/qt-multimedia-staging: Remove references to evr based renderer from .pro. Phonon core; compile fixes after merge. Phonon qt7; Compile fixes after merge. Phonon; complete integration. Update Phonon CMakeLists.txt. Update Phonon qt7 backend to 4.4.0. Update Phonon ds9 backend to 4.4.0. Update Phonon GStreamer backend to 4.4.0. Update Phonon core to 4.4.0
Diffstat (limited to 'src/3rdparty/phonon/gstreamer')
-rw-r--r--src/3rdparty/phonon/gstreamer/CMakeLists.txt18
-rw-r--r--src/3rdparty/phonon/gstreamer/ConfigureChecks.cmake7
-rw-r--r--src/3rdparty/phonon/gstreamer/audiodataoutput.cpp143
-rw-r--r--src/3rdparty/phonon/gstreamer/audiodataoutput.h84
-rw-r--r--src/3rdparty/phonon/gstreamer/audiooutput.cpp16
-rw-r--r--src/3rdparty/phonon/gstreamer/backend.cpp73
-rw-r--r--src/3rdparty/phonon/gstreamer/backend.h1
-rw-r--r--src/3rdparty/phonon/gstreamer/devicemanager.cpp70
-rw-r--r--src/3rdparty/phonon/gstreamer/devicemanager.h6
-rw-r--r--src/3rdparty/phonon/gstreamer/effectmanager.cpp2
-rw-r--r--src/3rdparty/phonon/gstreamer/glrenderer.cpp2
-rw-r--r--src/3rdparty/phonon/gstreamer/gsthelper.cpp2
-rw-r--r--src/3rdparty/phonon/gstreamer/gstreamer.desktop57
-rw-r--r--src/3rdparty/phonon/gstreamer/medianode.cpp4
-rw-r--r--src/3rdparty/phonon/gstreamer/mediaobject.cpp296
-rw-r--r--src/3rdparty/phonon/gstreamer/mediaobject.h12
-rw-r--r--src/3rdparty/phonon/gstreamer/qwidgetvideosink.h1
-rw-r--r--src/3rdparty/phonon/gstreamer/videowidget.h1
-rw-r--r--src/3rdparty/phonon/gstreamer/x11renderer.cpp3
19 files changed, 654 insertions, 144 deletions
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 <kretz@kde.org>
+ Copyright (C) 2009 Martin Sandsmark <sandsmark@samfundet.no>
+
+ 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 <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "audiodataoutput.h"
+#include "gsthelper.h"
+#include "medianode.h"
+#include "mediaobject.h"
+#include <QtCore/QVector>
+#include <QtCore/QMap>
+#include <phonon/audiooutput.h>
+
+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<Phonon::AudioDataOutput::Channel, QVector<float> > FloatMap;
+typedef QMap<Phonon::AudioDataOutput::Channel, QVector<qint16> > IntMap;
+
+inline void AudioDataOutput::convertAndEmit(const QVector<qint16> &leftBuffer, const QVector<qint16> &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<AudioDataOutput*>(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<gint16*>(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; i<size; i++) {
+ // 8 bit? interleaved? yay for lacking documentation!
+ that->m_pendingData.append(data[i]);
+ }
+
+ while (that->m_pendingData.size() > that->m_dataSize * that->m_channels) {
+ if (that->m_channels == 1) {
+ QVector<qint16> 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<qint16> left(that->m_dataSize), right(that->m_dataSize);
+ for (int i=0; i<that->m_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 <kretz@kde.org>
+ Copyright (C) 2009 Martin Sandsmark <sandsmark@samfundet.no>
+
+ 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 <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef Phonon_GSTREAMER_AUDIODATAOUTPUT_H
+#define Phonon_GSTREAMER_AUDIODATAOUTPUT_H
+
+#include "abstractaudiooutput.h"
+#include "backend.h"
+#include "medianode.h"
+#include <phonon/audiodataoutput.h>
+#include <phonon/audiodataoutputinterface.h>
+
+namespace Phonon
+{
+namespace Gstreamer
+{
+ /**
+ * \author Martin Sandsmark <sandsmark@samfundet.no>
+ */
+ 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<Phonon::AudioDataOutput::Channel, QVector<qint16> > &data);
+ void dataReady(const QMap<Phonon::AudioDataOutput::Channel, QVector<float> > &data);
+ void endOfMedia(int remainingSamples);
+
+ private:
+ void convertAndEmit(const QVector<qint16>&, const QVector<qint16>&);
+
+ GstElement *m_queue;
+ int m_dataSize;
+ QVector<qint16> 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<AudioDevice> deviceList = m_backend->deviceManager()->audioOutputDevices();
- int deviceIdx = -1;
- for (int i=0; i<deviceList.size(); i++) {
- if (deviceList.at(i).id == newDevice) {
- deviceIdx = i;
- break;
- }
- }
-
- if (m_audioSink && deviceIdx >= 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..729a1d3 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 <gst/interfaces/propertyprobe.h>
+#include <phonon/pulsesupport.h>
#include <QtCore/QSet>
#include <QtCore/QVariant>
@@ -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:
@@ -214,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;
@@ -234,16 +240,28 @@ 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);
+ }
}
}
}
}
}
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 +311,11 @@ QHash<QByteArray, QVariant> Backend::objectDescriptionProperties(ObjectDescripti
switch (type) {
case Phonon::AudioOutputDeviceType: {
- QList<AudioDevice> 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 +444,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<QPointer<AudioOutput> > 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<QByteArray> 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<AudioDevice> 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 <AudioDevice> 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 0203028..106884f 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 <cmath>
#include <gst/interfaces/propertyprobe.h>
+#include <gst/pbutils/install-plugins.h>
#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*>("GstCaps*");
qRegisterMetaType<State>("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<QString> keys = newTags.keys();
+ for (QList<QString>::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<QString> values = newTags.values(key);
+ for (QList<QString>::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 <QtCore/QByteArray>
#include <QtCore/QEvent>
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 <gst/gst.h>
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());
}