Changeset 846 for trunk/src/3rdparty/phonon/gstreamer
- Timestamp:
- May 5, 2011, 5:36:53 AM (14 years ago)
- Location:
- trunk
- Files:
-
- 18 edited
- 2 copied
Legend:
- Unmodified
- Added
- Removed
-
trunk
- Property svn:mergeinfo changed
/branches/vendor/nokia/qt/4.7.2 (added) merged: 845 /branches/vendor/nokia/qt/current merged: 844 /branches/vendor/nokia/qt/4.6.3 removed
- Property svn:mergeinfo changed
-
trunk/src/3rdparty/phonon/gstreamer/CMakeLists.txt
r561 r846 20 20 include_directories( 21 21 ${CMAKE_CURRENT_BINARY_DIR} 22 ${GSTREAMER_INCLUDE_DIR} 22 ${GSTREAMER_INCLUDE_DIR} 23 23 ${GLIB2_INCLUDE_DIR} 24 24 ${LIBXML2_INCLUDE_DIR} … … 35 35 set(phonon_gstreamer_SRCS 36 36 audiooutput.cpp 37 artssink.cpp38 37 backend.cpp 39 38 devicemanager.cpp … … 51 50 audioeffect.cpp 52 51 abstractrenderer.cpp 53 x11renderer.cpp54 52 widgetrenderer.cpp 55 53 glrenderer.cpp 56 54 volumefadereffect.cpp 55 audiodataoutput.cpp 57 56 ) 58 57 59 find_package(Alsa) 60 macro_ensure_version("0.10.22" ${GSTREAMER_VERSION} GSTREAMER_HAS_NONBLOCKING_ALSASINK) 58 if(NOT WIN32) 59 set(phonon_gstreamer_SRCS 60 ${phonon_gstreamer_SRCS} 61 artssink.cpp 62 x11renderer.cpp) 63 macro_optional_find_package(Alsa) 64 macro_ensure_version("0.10.22" ${GSTREAMER_VERSION} GSTREAMER_HAS_NONBLOCKING_ALSASINK) 65 endif(NOT WIN32) 61 66 if(ALSA_FOUND AND NOT GSTREAMER_HAS_NONBLOCKING_ALSASINK) 62 67 add_definitions(-DUSE_ALSASINK2) … … 79 84 target_link_libraries(phonon_gstreamer ${ASOUND_LIBRARY}) 80 85 endif(ALSA_FOUND) 86 if(USE_INSTALL_PLUGIN) 87 target_link_libraries(phonon_gstreamer ${GSTREAMER_PLUGIN_PBUTILS_LIBRARIES}) 88 endif(USE_INSTALL_PLUGIN) 81 89 82 90 install(TARGETS phonon_gstreamer DESTINATION ${PLUGIN_INSTALL_DIR}/plugins/phonon_backend) -
trunk/src/3rdparty/phonon/gstreamer/ConfigureChecks.cmake
r2 r846 18 18 macro_optional_find_package(GStreamerPlugins) 19 19 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") 20 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") 20 21 21 22 macro_optional_find_package(GLIB2) … … 31 32 macro_log_feature(OPENGL_FOUND "OpenGL" "OpenGL support is required to compile the gstreamer backend for Phonon" "" FALSE) 32 33 33 if (GSTREAMER_FOUND AND GSTREAMER_PLUGIN_VIDEO_LIBRARIES AND G LIB2_FOUND AND GOBJECT_FOUND AND LIBXML2_FOUND AND OPENGL_FOUND)34 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) 34 35 set(BUILD_PHONON_GSTREAMER TRUE) 35 else (GSTREAMER_FOUND AND GSTREAMER_PLUGIN_VIDEO_LIBRARIES AND G LIB2_FOUND AND GOBJECT_FOUND AND LIBXML2_FOUND AND OPENGL_FOUND)36 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) 36 37 set(BUILD_PHONON_GSTREAMER FALSE) 37 endif (GSTREAMER_FOUND AND GSTREAMER_PLUGIN_VIDEO_LIBRARIES AND G LIB2_FOUND AND GOBJECT_FOUND AND LIBXML2_FOUND AND OPENGL_FOUND)38 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) -
trunk/src/3rdparty/phonon/gstreamer/audiooutput.cpp
r561 r846 126 126 { 127 127 m_backend->logMessage(Q_FUNC_INFO + QString::number(newDevice), Backend::Info, this); 128 128 129 if (newDevice == m_device) 129 130 return true; … … 136 137 137 138 bool success = false; 138 const QList<AudioDevice> deviceList = m_backend->deviceManager()->audioOutputDevices(); 139 int deviceIdx = -1; 140 for (int i=0; i<deviceList.size(); i++) { 141 if (deviceList.at(i).id == newDevice) { 142 deviceIdx = i; 143 break; 144 } 145 } 146 147 if (m_audioSink && deviceIdx >= 0) { 139 if (m_audioSink && newDevice >= 0) { 148 140 // Save previous state 149 141 GstState oldState = GST_STATE(m_audioSink); 150 142 const QByteArray oldDeviceValue = GstHelper::property(m_audioSink, "device"); 151 const QByteArray deviceId = deviceList.at(deviceIdx).gstId;143 const QByteArray deviceId = m_backend->deviceManager()->gstId(newDevice); 152 144 m_device = newDevice; 153 145 … … 171 163 } 172 164 173 // Note the stopped state should not really be nec cessary, but seems to be required to165 // Note the stopped state should not really be necessary, but seems to be required to 174 166 // properly reset after changing the audio state 175 167 if (root()) { -
trunk/src/3rdparty/phonon/gstreamer/backend.cpp
r561 r846 19 19 #include "backend.h" 20 20 #include "audiooutput.h" 21 #include "audiodataoutput.h" 21 22 #include "audioeffect.h" 22 23 #include "mediaobject.h" … … 27 28 #include "volumefadereffect.h" 28 29 #include <gst/interfaces/propertyprobe.h> 30 #include <phonon/pulsesupport.h> 29 31 30 32 #include <QtCore/QSet> … … 50 52 , m_isValid(false) 51 53 { 54 // Initialise PulseAudio support 55 PulseSupport *pulse = PulseSupport::getInstance(); 56 pulse->enable(); 57 connect(pulse, SIGNAL(objectDescriptionChanged(ObjectDescriptionType)), SIGNAL(objectDescriptionChanged(ObjectDescriptionType))); 58 52 59 // In order to support reloading, we only set the app name once... 53 60 static bool first = true; … … 56 63 g_set_application_name(qApp->applicationName().toUtf8()); 57 64 } 58 59 65 GError *err = 0; 60 66 bool wasInit = gst_init_check(0, 0, &err); //init gstreamer: must be called before any gst-related functions … … 93 99 Backend::~Backend() 94 100 { 101 delete m_effectManager; 102 delete m_deviceManager; 103 PulseSupport::shutdown(); 95 104 } 96 105 … … 120 129 return new MediaObject(this, parent); 121 130 122 case AudioOutputClass: { 123 AudioOutput *ao = new AudioOutput(this, parent); 124 m_audioOutputs.append(ao); 125 return ao; 126 } 131 case AudioOutputClass: 132 return new AudioOutput(this, parent); 133 127 134 #ifndef QT_NO_PHONON_EFFECT 128 135 case EffectClass: … … 130 137 #endif //QT_NO_PHONON_EFFECT 131 138 case AudioDataOutputClass: 132 logMessage("createObject() : AudioDataOutput not implemented"); 133 break; 139 return new AudioDataOutput(this, parent); 134 140 135 141 #ifndef QT_NO_PHONON_VIDEO … … 215 221 QString klass = gst_element_factory_get_klass(GST_ELEMENT_FACTORY(feature)); 216 222 217 if (klass == QLatin1String("Codec/Decoder") || 218 klass == QLatin1String("Codec/Decoder/Audio") || 219 klass == QLatin1String("Codec/Decoder/Video") || 220 klass == QLatin1String("Codec/Demuxer") || 221 klass == QLatin1String("Codec/Demuxer/Audio") || 222 klass == QLatin1String("Codec/Demuxer/Video") || 223 klass == QLatin1String("Codec/Parser") || 224 klass == QLatin1String("Codec/Parser/Audio") || 223 if (klass == QLatin1String("Codec/Decoder") || 224 klass == QLatin1String("Codec/Decoder/Audio") || 225 klass == QLatin1String("Codec/Decoder/Video") || 226 klass == QLatin1String("Codec/Demuxer") || 227 klass == QLatin1String("Codec/Demuxer/Audio") || 228 klass == QLatin1String("Codec/Demuxer/Video") || 229 klass == QLatin1String("Codec/Parser") || 230 klass == QLatin1String("Codec/Parser/Audio") || 225 231 klass == QLatin1String("Codec/Parser/Video")) { 226 232 … … 235 241 236 242 if (caps) { 237 const GstStructure* capsStruct = gst_caps_get_structure (caps, 0); 238 QString mime = QString::fromUtf8(gst_structure_get_name (capsStruct)); 239 if (!availableMimeTypes.contains(mime)) 240 availableMimeTypes.append(mime); 243 for (unsigned int struct_idx = 0; struct_idx < gst_caps_get_size (caps); struct_idx++) { 244 245 const GstStructure* capsStruct = gst_caps_get_structure (caps, struct_idx); 246 QString mime = QString::fromUtf8(gst_structure_get_name (capsStruct)); 247 if (!availableMimeTypes.contains(mime)) 248 availableMimeTypes.append(mime); 249 } 241 250 } 242 251 } … … 245 254 } 246 255 g_list_free(factoryList); 256 if (availableMimeTypes.contains("audio/x-vorbis") 257 && availableMimeTypes.contains("application/x-ogm-audio")) { 258 if (!availableMimeTypes.contains("audio/x-vorbis+ogg")) 259 availableMimeTypes.append("audio/x-vorbis+ogg"); 260 if (!availableMimeTypes.contains("application/ogg")) /* *.ogg */ 261 availableMimeTypes.append("application/ogg"); 262 if (!availableMimeTypes.contains("audio/ogg")) /* *.oga */ 263 availableMimeTypes.append("audio/ogg"); 264 } 247 265 availableMimeTypes.sort(); 248 266 return availableMimeTypes; … … 294 312 switch (type) { 295 313 case Phonon::AudioOutputDeviceType: { 296 QList<AudioDevice> audioDevices = deviceManager()->audioOutputDevices(); 297 foreach(const AudioDevice &device, audioDevices) { 298 if (device.id == index) { 299 ret.insert("name", device.gstId); 300 ret.insert("description", device.description); 301 ret.insert("icon", QLatin1String("audio-card")); 302 break; 303 } 314 AudioDevice* ad; 315 if ((ad = deviceManager()->audioDevice(index))) { 316 ret.insert("name", ad->gstId); 317 ret.insert("description", ad->description); 318 ret.insert("icon", ad->icon); 304 319 } 305 320 } … … 430 445 /** 431 446 * Returns a debuglevel that is determined by the 432 * PHONON_GST REAMER_DEBUG environment variable.447 * PHONON_GST_DEBUG environment variable. 433 448 * 434 449 * Warning - important warnings -
trunk/src/3rdparty/phonon/gstreamer/backend.h
r2 r846 87 87 private: 88 88 static gboolean busCall(GstBus *bus, GstMessage *msg, gpointer data); 89 QList<QPointer<AudioOutput> > m_audioOutputs;90 89 91 90 DeviceManager *m_deviceManager; -
trunk/src/3rdparty/phonon/gstreamer/devicemanager.cpp
r561 r846 25 25 #include "x11renderer.h" 26 26 #include "artssink.h" 27 #include "pulsesupport.h" 27 28 28 29 #ifdef USE_ALSASINK2 … … 45 46 : gstId(gstId) 46 47 { 47 //get an id 48 static int counter = 0; 49 id = counter++; 48 // This should never be called when PulseAudio is active. 49 Q_ASSERT(!PulseSupport::getInstance()->isActive()); 50 51 id = manager->allocateDeviceId(); 52 icon = "audio-card"; 53 50 54 //get name from device 51 55 if (gstId == "default") { … … 72 76 : QObject(backend) 73 77 , m_backend(backend) 74 { 75 m_audioSink = qgetenv("PHONON_GST_AUDIOSINK"); 76 m_videoSinkWidget = qgetenv("PHONON_GST_VIDEOMODE"); 77 78 #ifndef QT_NO_SETTINGS 78 , m_audioDeviceCounter(0) 79 { 79 80 QSettings settings(QLatin1String("Trolltech")); 80 81 settings.beginGroup(QLatin1String("Qt")); 81 82 83 PulseSupport *pulse = PulseSupport::getInstance(); 84 m_audioSink = qgetenv("PHONON_GST_AUDIOSINK"); 82 85 if (m_audioSink.isEmpty()) { 83 86 m_audioSink = settings.value(QLatin1String("audiosink"), "Auto").toByteArray().toLower(); 84 } 85 87 if (m_audioSink == "auto" && pulse->isActive()) 88 m_audioSink = "pulsesink"; 89 } 90 if ("pulsesink" != m_audioSink) 91 pulse->enable(false); 92 93 m_videoSinkWidget = qgetenv("PHONON_GST_VIDEOMODE"); 86 94 if (m_videoSinkWidget.isEmpty()) { 87 95 m_videoSinkWidget = settings.value(QLatin1String("videomode"), "Auto").toByteArray().toLower(); 88 96 } 89 #endif //QT_NO_SETTINGS90 97 91 98 if (m_backend->isValid()) … … 272 279 #endif //QT_NO_PHONON_VIDEO 273 280 274 /* 275 * Returns a positive device id or -1 if device 276 * does not exist 281 /** 282 * Allocate a device id for a new audio device 283 */ 284 int DeviceManager::allocateDeviceId() 285 { 286 return m_audioDeviceCounter++; 287 } 288 289 290 /** 291 * Returns a positive device id or -1 if device does not exist 277 292 * 278 293 * The gstId is typically in the format hw:1,0 … … 289 304 290 305 /** 291 * Get a human-readable description from a device id 292 */ 293 QByteArray DeviceManager::deviceDescription(int id) const 306 * Returns a gstId or "default" if device does not exist 307 * 308 * The gstId is typically in the format hw:1,0 309 */ 310 const QByteArray DeviceManager::gstId(int deviceId) 311 { 312 if (!PulseSupport::getInstance()->isActive()) { 313 AudioDevice *ad = audioDevice(deviceId); 314 if (ad) 315 return QByteArray(ad->gstId); 316 } 317 return QByteArray("default"); 318 } 319 320 /** 321 * Get the AudioDevice for a given device id 322 */ 323 AudioDevice* DeviceManager::audioDevice(int id) 294 324 { 295 325 for (int i = 0 ; i < m_audioDeviceList.size() ; ++i) { 296 if (m_audioDeviceList[i].id == id) { 297 return m_audioDeviceList[i].description; 298 } 299 } 300 return QByteArray(); 326 if (m_audioDeviceList[i].id == id) 327 return &m_audioDeviceList[i]; 328 } 329 return NULL; 301 330 } 302 331 … … 312 341 313 342 if (audioSink) { 314 list = GstHelper::extractProperties(audioSink, "device"); 315 list.prepend("default"); 343 if (!PulseSupport::getInstance()->isActive()) { 344 // If we're using pulse, the PulseSupport class takes care of things for us. 345 list = GstHelper::extractProperties(audioSink, "device"); 346 list.prepend("default"); 347 } 316 348 317 349 for (int i = 0 ; i < list.size() ; ++i) { -
trunk/src/3rdparty/phonon/gstreamer/devicemanager.h
r2 r846 43 43 QByteArray gstId; 44 44 QByteArray description; 45 QString icon; 45 46 }; 46 47 … … 52 53 const QList<AudioDevice> audioOutputDevices() const; 53 54 GstPad *requestPad(int device) const; 55 int allocateDeviceId(); 54 56 int deviceId(const QByteArray &gstId) const; 55 QByteArray deviceDescription(int id) const; 57 const QByteArray gstId(int id); 58 AudioDevice* audioDevice(int id); 56 59 GstElement *createGNOMEAudioSink(Category category); 57 60 GstElement *createAudioSink(Category category = NoCategory); … … 69 72 Backend *m_backend; 70 73 QList <AudioDevice> m_audioDeviceList; 74 int m_audioDeviceCounter; 71 75 QTimer m_devicePollTimer; 72 76 QByteArray m_audioSink; -
trunk/src/3rdparty/phonon/gstreamer/effectmanager.cpp
r2 r846 55 55 // "equalizer-nbands" not really useful at the moment 56 56 57 // These plugins simply don t work or have major stability issues:57 // These plugins simply don't work or have major stability issues: 58 58 // "iir" Does not seem to do much at the moment 59 59 // "audioinvert" Only works for some streams, should be invesigated -
trunk/src/3rdparty/phonon/gstreamer/glrenderer.cpp
r2 r846 267 267 setPalette(palette); 268 268 setAutoFillBackground(true); 269 // Videowidget al lways have this property to allow hiding the mouse cursor269 // Videowidget always have this property to allow hiding the mouse cursor 270 270 setMouseTracking(true); 271 271 } … … 305 305 const QRectF r = drawFrameRect(); 306 306 307 const float v_array[] = { r.left(), r.top(), r.right(), r.top(), r.right(), r.bottom(), r.left(), r.bottom() };307 const float v_array[] = { float(r.left()), float(r.top()), float(r.right()), float(r.top()), float(r.right()), float(r.bottom()), float(r.left()), float(r.bottom()) }; 308 308 309 309 glActiveTexture(GL_TEXTURE0); -
trunk/src/3rdparty/phonon/gstreamer/gsthelper.cpp
r2 r846 122 122 GstElement *playbin = 0; 123 123 //init playbin and add to our pipeline 124 playbin = gst_element_factory_make("playbin ", NULL);124 playbin = gst_element_factory_make("playbin2", NULL); 125 125 126 126 //Create an identity element to redirect sound -
trunk/src/3rdparty/phonon/gstreamer/gstreamer.desktop
r2 r846 11 11 12 12 Name=GStreamer 13 Name[bg]=GStreamer 14 Name[ca]=GStreamer 15 Name[ca@valencia]=GStreamer 16 Name[cs]=GStreamer 17 Name[da]=GStreamer 18 Name[de]=GStreamer 19 Name[el]=GStreamer 20 Name[en_GB]=GStreamer 21 Name[es]=GStreamer 22 Name[et]=GStreamer 23 Name[eu]=GStreamer 24 Name[fi]=GStreamer 25 Name[fr]=GStreamer 26 Name[ga]=GStreamer 27 Name[gl]=GStreamer 28 Name[hsb]=GStreamer 29 Name[hu]=GStreamer 30 Name[id]=GStreamer 31 Name[is]=GStreamer 32 Name[it]=GStreamer 33 Name[ja]=GStreamer 34 Name[ko]=GStreamer 35 Name[ku]=GStreamer 36 Name[lt]=GStreamer 37 Name[lv]=GStreamer 38 Name[nb]=GStreamer 39 Name[nds]=GStreamer 40 Name[nl]=GStreamer 41 Name[nn]=GStreamer 13 42 Name[pa]=àšà©àšžàšà©àš°àš®àš° 43 Name[pl]=GStreamer 44 Name[pt]=GStreamer 45 Name[pt_BR]=GStreamer 46 Name[ru]=GStreamer 47 Name[se]=GStreamer 48 Name[sk]=GStreamer 49 Name[sl]=GStreamer 14 50 Name[sr]=ÐÑÑÑÐžÐŒÐµÑ 51 Name[sr@ijekavian]=ÐÑÑÑÐžÐŒÐµÑ 52 Name[sr@ijekavianlatin]=GStreamer 53 Name[sr@latin]=GStreamer 15 54 Name[sv]=Gstreamer 55 Name[tr]=GStreamer 56 Name[uk]=GStreamer 16 57 Name[x-test]=xxGStreamerxx 58 Name[zh_CN]=GStreamer 59 Name[zh_TW]=GStreamer 17 60 18 61 Comment=Phonon GStreamer backend 19 62 Comment[bg]=Phonon GStreamer 20 63 Comment[ca]=Dorsal GStreamer del Phonon 64 Comment[ca@valencia]=Dorsal GStreamer del Phonon 65 Comment[cs]=Phonon GStreamer backend 21 66 Comment[da]=GStreamer-backend til Phonon 22 67 Comment[de]=Phonon-Treiber fÃŒr GStreamer … … 24 69 ÏοÏÏήÏÎ¹ÎŸÎ·Ï GStreamer ÏÎ¿Ï 25 70 Phonon 71 Comment[en_GB]=Phonon GStreamer backend 26 72 Comment[es]=Motor GStreamer para Phonon 27 73 Comment[et]=Phononi GStreameri taustaprogramm 74 Comment[eu]=Phonon GStreamer backend 75 Comment[fi]=Phonon GStreamer-taustaohjelma 28 76 Comment[fr]=SystÚme de gestion GStreamer pour Phonon 29 77 Comment[ga]=Inneall GStreamer le haghaidh Phonon 30 78 Comment[gl]=Infraestrutura de GStreamer para Phonon 79 Comment[hsb]=Phonon GStreamer backend 80 Comment[hu]=Phonon GStreamer modul 81 Comment[id]=Phonon GStreamer backend 31 82 Comment[is]=Phonon GStreamer bakendi 32 83 Comment[it]=Motore Gstreamer di Phonon … … 34 85 Comment[ko]=Phonon GStreamer ë°±ìë 35 86 Comment[ku]=Binesaza Phonon GStreamer 87 Comment[lt]=Phonon GStreamer galinÄ sÄ 88 saja 36 89 Comment[lv]=Phonon GStreamer aizmugure 90 Comment[nb]=Phonon-motor for GStreamer 37 91 Comment[nds]=Phonon-HÃŒlpprogramm GStreamer 38 92 Comment[nl]=GStreamer-backend (Phonon) … … 42 96 Comment[pt]=Infra-estrutura do GStreamer para o Phonon 43 97 Comment[pt_BR]=Infraestrutura Phonon GStreamer 98 Comment[ru]=ÐÐµÑ 99 аМОзЌ GStreamer ÐŽÐ»Ñ Phonon 100 Comment[se]=Phonon GStreamer duogášmohtor 44 101 Comment[sk]=GStreamer podsystém 45 102 Comment[sl]=Phononova hrbtenica GStreamer 46 103 Comment[sr]=ÐÑÑÑÐžÐŒÐµÑ ÐºÐ°ÐŸ пПзаЎОМа ЀПМПМа 104 Comment[sr@ijekavian]=ÐÑÑÑÐžÐŒÐµÑ ÐºÐ°ÐŸ пПзаЎОМа ЀПМПМа 105 Comment[sr@ijekavianlatin]=GStreamer kao pozadina Phonona 47 106 Comment[sr@latin]=GStreamer kao pozadina Phonona 48 107 Comment[sv]=Phonon Gstreamer-grÀnssnitt -
trunk/src/3rdparty/phonon/gstreamer/medianode.cpp
r2 r846 199 199 // potential deadlock. Hence we force the pipeline into ready state 200 200 // before any nodes are disconnected. 201 gst_element_set_state(root()->pipeline(), GST_STATE_READY); 202 203 Q_ASSERT(sink->root()); //sink has to have a root since it is onnected201 gst_element_set_state(root()->pipeline(), GST_STATE_READY); 202 203 Q_ASSERT(sink->root()); //sink has to have a root since it is connected 204 204 205 205 if (sink->description() & (AudioSink)) { -
trunk/src/3rdparty/phonon/gstreamer/mediaobject.cpp
r561 r846 17 17 #include <cmath> 18 18 #include <gst/interfaces/propertyprobe.h> 19 #include <gst/pbutils/install-plugins.h> 19 20 #include "common.h" 20 21 #include "mediaobject.h" … … 54 55 , m_prefinishMark(0) 55 56 , m_transitionTime(0) 57 , m_isStream(false) 56 58 , m_posAtSeek(-1) 57 59 , m_prefinishMarkReachedNotEmitted(true) … … 80 82 , m_availableTitles(0) 81 83 , m_currentTitle(1) 84 , m_pendingTitle(1) 82 85 { 83 86 qRegisterMetaType<GstCaps*>("GstCaps*"); … … 96 99 connect(m_tickTimer, SIGNAL(timeout()), SLOT(emitTick())); 97 100 } 98 connect(this, SIGNAL(stateChanged(Phonon::State, Phonon::State)),99 this, SLOT(notifyStateChange(Phonon::State, Phonon::State)));101 connect(this, SIGNAL(stateChanged(Phonon::State, Phonon::State)), 102 this, SLOT(notifyStateChange(Phonon::State, Phonon::State))); 100 103 101 104 } … … 137 140 } 138 141 142 void 143 pluginInstallationDone( GstInstallPluginsReturn res, gpointer userData ) 144 { 145 // Nothing inside yet 146 Q_UNUSED(res); 147 Q_UNUSED(userData); 148 } 149 139 150 void MediaObject::saveState() 140 151 { … … 196 207 bool canPlay = (m_hasAudio || m_videoStreamFound); 197 208 Phonon::ErrorType error = canPlay ? Phonon::NormalError : Phonon::FatalError; 209 #ifdef PLUGIN_INSTALL_API 210 GstInstallPluginsContext *ctx = gst_install_plugins_context_new (); 211 gchar *details[2]; 212 details[0] = m_missingCodecs[0].toLocal8Bit().data(); 213 details[1] = NULL; 214 GstInstallPluginsReturn status; 215 216 status = gst_install_plugins_async( details, ctx, pluginInstallationDone, NULL ); 217 gst_install_plugins_context_free ( ctx ); 218 219 if ( status != GST_INSTALL_PLUGINS_STARTED_OK ) 220 { 221 if( status == GST_INSTALL_PLUGINS_HELPER_MISSING ) 222 setError(tr("Missing codec helper script assistant."), Phonon::FatalError ); 223 else 224 setError(tr("Plugin codec installation failed for codec: %0") 225 .arg(m_missingCodecs[0].split("|")[3]), error); 226 } 227 m_missingCodecs.clear(); 228 #else 229 QString codecs = m_missingCodecs.join(", "); 230 198 231 if (error == Phonon::NormalError && m_hasVideo && !m_videoStreamFound) { 199 232 m_hasVideo = false; 200 233 emit hasVideoChanged(false); 201 234 } 202 QString codecs = m_missingCodecs.join(", "); 203 setError(QString(tr("A required codec is missing. You need to install the following codec(s) to play this content: %0")).arg(codecs), error); 235 setError(tr("A required codec is missing. You need to install the following codec(s) to play this content: %0").arg(codecs), error); 204 236 m_missingCodecs.clear(); 237 #endif 205 238 } 206 239 } … … 249 282 250 283 } 251 media->addMissingCodecName(value); 284 285 #ifdef PLUGIN_INSTALL_API 286 QString plugins = QString("gstreamer|0.10|%0|%1|decoder-%2") 287 .arg( qApp->applicationName() ) 288 .arg( value ) 289 .arg( QString::fromUtf8(gst_caps_to_string (caps) ) ); 290 media->addMissingCodecName( plugins ); 291 #else 292 media->addMissingCodecName( value ); 293 #endif 252 294 } 253 295 … … 310 352 // Note that the notify::caps _must_ be installed after linking to work with Dapper 311 353 m_capsHandler = g_signal_connect(pad, "notify::caps", G_CALLBACK(notifyVideoCaps), this); 312 354 313 355 if (!m_loading && !m_hasVideo) { 314 356 m_hasVideo = m_videoStreamFound; … … 369 411 370 412 // Create a new datasource based on the input URL 371 QByteArray encoded_cstr_url = url.toEncoded(); 413 // add the 'file' scheme if it's missing; the double '/' is needed! 414 QByteArray encoded_cstr_url = (url.scheme() == QLatin1String("") ? 415 "file://" + url.toEncoded() : 416 url.toEncoded()); 372 417 m_datasource = gst_element_make_from_uri(GST_URI_SRC, encoded_cstr_url.constData(), (const char*)NULL); 373 418 if (!m_datasource) … … 389 434 m_backend->logMessage(QString("new device speed : 2X"), Backend::Info, this); 390 435 } 436 } 437 438 /* make HTTP sources send extra headers so we get icecast 439 * metadata in case the stream is an icecast stream */ 440 if (encoded_cstr_url.startsWith("http://") 441 && g_object_class_find_property (G_OBJECT_GET_CLASS (m_datasource), "iradio-mode")) { 442 g_object_set (m_datasource, "iradio-mode", TRUE, NULL); 443 m_isStream = true; 391 444 } 392 445 … … 443 496 gst_object_sink (GST_OBJECT (m_pipeline)); 444 497 445 m_decodebin = gst_element_factory_make ("decodebin ", NULL);498 m_decodebin = gst_element_factory_make ("decodebin2", NULL); 446 499 g_signal_connect (m_decodebin, "new-decoded-pad", G_CALLBACK (&cb_newpad), this); 447 500 g_signal_connect (m_decodebin, "unknown-type", G_CALLBACK (&cb_unknown_type), this); … … 647 700 } else if (currentState == GST_STATE_PLAYING) { 648 701 changeState(Phonon::PlayingState); 649 } else if ( !m_atEndOfStream &&gst_element_set_state(m_pipeline, GST_STATE_PLAYING) != GST_STATE_CHANGE_FAILURE) {702 } else if (gst_element_set_state(m_pipeline, GST_STATE_PLAYING) != GST_STATE_CHANGE_FAILURE) { 650 703 m_pendingState = Phonon::PlayingState; 651 704 } else { … … 677 730 678 731 Phonon::State oldState = m_state; 679 m_state = newstate; // m_state must be set before emitting, since 732 m_state = newstate; // m_state must be set before emitting, since 680 733 // Error state requires that state() will return the new value 681 734 m_pendingState = newstate; … … 697 750 case Phonon::StoppedState: 698 751 m_backend->logMessage("phonon state changed: Stopped", Backend::Info, this); 752 // We must reset the pipeline when playing again 753 m_resetNeeded = true; 699 754 m_tickTimer->stop(); 700 755 break; … … 862 917 GstState state; 863 918 gst_element_set_state(m_pipeline, GST_STATE_NULL); 864 gst_element_get_state 919 gst_element_get_state(m_pipeline, &state, NULL, 2000); 865 920 866 921 m_source = source; … … 872 927 changeState(Phonon::LoadingState); 873 928 m_loading = true; 874 m_resetNeeded = false; 929 // IMPORTANT: Honor the m_resetNeeded flag as it currently stands. 930 // See https://qa.mandriva.com/show_bug.cgi?id=56807 931 //m_resetNeeded = false; 875 932 m_resumeState = false; 876 933 m_pendingState = Phonon::StoppedState; … … 885 942 m_aboutToFinishEmitted = false; 886 943 m_error = NoError; 887 m_errorString = QString();888 944 m_errorString.clear(); 945 889 946 m_bufferPercent = 0; 890 947 m_prefinishMarkReachedNotEmitted = true; … … 895 952 m_atEndOfStream = false; 896 953 897 // Clear exising meta tags 954 m_availableTitles = 0; 955 m_pendingTitle = 1; 956 m_currentTitle = 1; 957 958 // Clear existing meta tags 898 959 m_metaData.clear(); 960 m_isStream = false; 899 961 900 962 switch (source.type()) { 901 case MediaSource::Url: { 902 if (createPipefromURL(source.url())) 903 m_loading = true; 904 else 963 case MediaSource::Url: { 964 if (!createPipefromURL(source.url())) 905 965 setError(tr("Could not open media source.")); 906 966 } … … 908 968 909 969 case MediaSource::LocalFile: { 910 if (createPipefromURL(QUrl::fromLocalFile(source.fileName()))) 911 m_loading = true; 912 else 970 if (!createPipefromURL(QUrl::fromLocalFile(source.fileName()))) 913 971 setError(tr("Could not open media source.")); 914 972 } … … 923 981 924 982 case MediaSource::Stream: 925 if (createPipefromStream(source)) 926 m_loading = true; 927 else 983 if (!createPipefromStream(source)) 928 984 setError(tr("Could not open media source.")); 929 985 break; … … 931 987 case MediaSource::Disc: 932 988 { 933 934 935 989 QString mediaUrl; 990 switch (source.discType()) { 991 case Phonon::NoDisc: 936 992 qWarning() << "I should never get to see a MediaSource that is a disc but doesn't specify which one"; 937 993 return; … … 949 1005 return; 950 1006 } 951 if (!mediaUrl.isEmpty() && createPipefromURL(QUrl(mediaUrl))) 952 m_loading = true; 953 else 1007 if (mediaUrl.isEmpty() || !createPipefromURL(QUrl(mediaUrl))) 954 1008 setError(tr("Could not open media source.")); 955 1009 } … … 967 1021 // We need to link this node to ensure that fake sinks are connected 968 1022 // before loading, otherwise the stream will be blocked 969 if (m_loading) 970 link(); 1023 link(); 971 1024 beginLoad(); 972 1025 } … … 1005 1058 } 1006 1059 1007 m_availableTitles = 1;1008 gint64 titleCount;1009 GstFormat format = gst_format_get_by_nick("track");1010 if (gst_element_query_duration (m_pipeline, &format, &titleCount)) {1060 if (m_source.discType() == Phonon::Cd) { 1061 gint64 titleCount; 1062 GstFormat format = gst_format_get_by_nick("track"); 1063 if (gst_element_query_duration (m_pipeline, &format, &titleCount)) { 1011 1064 //check if returned format is still "track", 1012 1065 //gstreamer sometimes returns the total time, if tracks information is not available. 1013 if (qstrcmp(gst_format_get_name(format), "track") == 0) { 1014 int oldAvailableTitles = m_availableTitles; 1015 m_availableTitles = (int)titleCount; 1016 if (m_availableTitles != oldAvailableTitles) { 1017 emit availableTitlesChanged(m_availableTitles); 1018 m_backend->logMessage(QString("Available titles changed: %0").arg(m_availableTitles), Backend::Info, this); 1066 if (qstrcmp(gst_format_get_name(format), "track") == 0) { 1067 int oldAvailableTitles = m_availableTitles; 1068 m_availableTitles = (int)titleCount; 1069 if (m_availableTitles != oldAvailableTitles) { 1070 emit availableTitlesChanged(m_availableTitles); 1071 m_backend->logMessage(QString("Available titles changed: %0").arg(m_availableTitles), Backend::Info, this); 1072 } 1019 1073 } 1020 1074 } 1021 1075 } 1022 1023 1076 } 1024 1077 … … 1078 1131 1079 1132 quint64 current = currentTime(); 1080 quint64 total = totalTime(); 1133 quint64 total = totalTime(); 1081 1134 1082 1135 if (current < total - m_prefinishMark) … … 1099 1152 if (m_tickInterval > 0 && currentTime != m_previousTickTime) { 1100 1153 emit tick(currentTime); 1101 m_previousTickTime = currentTime; 1154 m_previousTickTime = currentTime; 1102 1155 } 1103 1156 if (m_state == Phonon::PlayingState) { … … 1110 1163 // Prepare load of next source 1111 1164 if (currentTime >= totalTime - ABOUT_TO_FINNISH_TIME) { 1112 if (!m_aboutToFinishEmitted) { 1165 if (m_source.type() == MediaSource::Disc && 1166 m_autoplayTitles && 1167 m_availableTitles > 1 && 1168 m_currentTitle < m_availableTitles) { 1169 m_aboutToFinishEmitted = false; 1170 } else if (!m_aboutToFinishEmitted) { 1113 1171 m_aboutToFinishEmitted = true; // track is about to finish 1114 1172 emit aboutToFinish(); … … 1214 1272 switch (GST_MESSAGE_TYPE (gstMessage)) { 1215 1273 1216 case GST_MESSAGE_EOS: 1217 m_backend->logMessage("EOS rec ieved", Backend::Info, this);1274 case GST_MESSAGE_EOS: 1275 m_backend->logMessage("EOS received", Backend::Info, this); 1218 1276 handleEndOfStream(); 1219 1277 break; … … 1223 1281 gst_message_parse_tag(gstMessage, &tag_list); 1224 1282 if (tag_list) { 1283 TagMap newTags; 1284 gst_tag_list_foreach (tag_list, &foreach_tag_function, &newTags); 1285 gst_tag_list_free(tag_list); 1286 1287 // Determine if we should no fake the album/artist tags. 1288 // This is a little confusing as we want to fake it on initial 1289 // connection where title, album and artist are all missing. 1290 // There are however times when we get just other information, 1291 // e.g. codec, and so we want to only do clever stuff if we 1292 // have a commonly available tag (ORGANIZATION) or we have a 1293 // change in title 1294 bool fake_it = 1295 (m_isStream 1296 && ((!newTags.contains("TITLE") 1297 && newTags.contains("ORGANIZATION")) 1298 || (newTags.contains("TITLE") 1299 && m_metaData.value("TITLE") != newTags.value("TITLE"))) 1300 && !newTags.contains("ALBUM") 1301 && !newTags.contains("ARTIST")); 1302 1225 1303 TagMap oldMap = m_metaData; // Keep a copy of the old one for reference 1226 // Append any new meta tags to the existing tag list 1227 gst_tag_list_foreach (tag_list, &foreach_tag_function, &m_metaData); 1304 1305 // Now we've checked the new data, append any new meta tags to the existing tag list 1306 // We cannot use TagMap::iterator as this is a multimap and when streaming data 1307 // could in theory be lost. 1308 QList<QString> keys = newTags.keys(); 1309 for (QList<QString>::iterator i = keys.begin(); i != keys.end(); ++i) { 1310 QString key = *i; 1311 if (m_isStream) { 1312 // If we're streaming, we need to remove data in m_metaData 1313 // in order to stop it filling up indefinitely (as it's a multimap) 1314 m_metaData.remove(key); 1315 } 1316 QList<QString> values = newTags.values(key); 1317 for (QList<QString>::iterator j = values.begin(); j != values.end(); ++j) { 1318 QString value = *j; 1319 QString currVal = m_metaData.value(key); 1320 if (!m_metaData.contains(key) || currVal != value) { 1321 m_metaData.insert(key, value); 1322 } 1323 } 1324 } 1325 1228 1326 m_backend->logMessage("Meta tags found", Backend::Info, this); 1229 if (oldMap != m_metaData && !m_loading) 1230 emit metaDataChanged(m_metaData); 1231 gst_tag_list_free(tag_list); 1232 } 1327 if (oldMap != m_metaData) { 1328 // This is a bit of a hack to ensure that stream metadata is 1329 // returned. We get as much as we can from the Shoutcast server's 1330 // StreamTitle= header. If further info is decoded from the stream 1331 // itself later, then it will overwrite this info. 1332 if (m_isStream && fake_it) { 1333 m_metaData.remove("ALBUM"); 1334 m_metaData.remove("ARTIST"); 1335 1336 // Detect whether we want to "fill in the blanks" 1337 QString str; 1338 if (m_metaData.contains("TITLE")) 1339 { 1340 str = m_metaData.value("TITLE"); 1341 int splitpoint; 1342 // Check to see if our title matches "%s - %s" 1343 // Where neither %s are empty... 1344 if ((splitpoint = str.indexOf(" - ")) > 0 1345 && str.size() > (splitpoint+3)) { 1346 m_metaData.insert("ARTIST", str.left(splitpoint)); 1347 m_metaData.replace("TITLE", str.mid(splitpoint+3)); 1348 } 1349 } else { 1350 str = m_metaData.value("GENRE"); 1351 if (!str.isEmpty()) 1352 m_metaData.insert("TITLE", str); 1353 else 1354 m_metaData.insert("TITLE", "Streaming Data"); 1355 } 1356 if (!m_metaData.contains("ARTIST")) { 1357 str = m_metaData.value("LOCATION"); 1358 if (!str.isEmpty()) 1359 m_metaData.insert("ARTIST", str); 1360 else 1361 m_metaData.insert("ARTIST", "Streaming Data"); 1362 } 1363 str = m_metaData.value("ORGANIZATION"); 1364 if (!str.isEmpty()) 1365 m_metaData.insert("ALBUM", str); 1366 else 1367 m_metaData.insert("ALBUM", "Streaming Data"); 1368 } 1369 // As we manipulate the title, we need to recompare 1370 // oldMap and m_metaData here... 1371 if (oldMap != m_metaData && !m_loading) 1372 emit metaDataChanged(m_metaData); 1373 } 1374 } 1233 1375 } 1234 1376 break; … … 1256 1398 m_tickTimer->start(); 1257 1399 changeState(Phonon::PlayingState); 1400 if ((m_source.type() == MediaSource::Disc) && (m_currentTitle != m_pendingTitle)) { 1401 setTrack(m_pendingTitle); 1402 } 1258 1403 if (m_resumeState && m_oldState == Phonon::PlayingState) { 1259 1404 seek(m_oldPos); … … 1291 1436 m_backend->logMessage("gstreamer: pipeline state set to ready", Backend::Debug, this); 1292 1437 m_tickTimer->stop(); 1438 if ((m_source.type() == MediaSource::Disc) && (m_currentTitle != m_pendingTitle)) { 1439 setTrack(m_pendingTitle); 1440 } 1293 1441 break; 1294 1442 … … 1329 1477 gst_caps_unref (caps); 1330 1478 gst_object_unref (sinkPad); 1331 } 1479 } 1332 1480 } else { 1333 1481 setError(QString(err->message), Phonon::FatalError); … … 1401 1549 //case GST_MESSAGE_LATENCY: only from 0.10.12 1402 1550 //case GST_MESSAGE_ASYNC_DONE: only from 0.10.13 1403 default: 1404 break; 1551 default: 1552 break; 1405 1553 } 1406 1554 } … … 1418 1566 m_atEndOfStream = true; 1419 1567 1420 if (m_autoplayTitles && 1568 if (m_source.type() == MediaSource::Disc && 1569 m_autoplayTitles && 1421 1570 m_availableTitles > 1 && 1422 1571 m_currentTitle < m_availableTitles) { … … 1442 1591 setState(m_pendingState); 1443 1592 } 1593 } 1594 } 1595 1596 void MediaObject::invalidateGraph() 1597 { 1598 m_resetNeeded = true; 1599 if (m_state == Phonon::PlayingState || m_state == Phonon::PausedState) { 1600 changeState(Phonon::StoppedState); 1444 1601 } 1445 1602 } … … 1503 1660 void MediaObject::_iface_setCurrentTitle(int title) 1504 1661 { 1662 m_backend->logMessage(QString("setCurrentTitle %0").arg(title), Backend::Info, this); 1663 if ((title == m_currentTitle) || (title == m_pendingTitle)) 1664 return; 1665 1666 m_pendingTitle = title; 1667 1668 if (m_state == Phonon::PlayingState || m_state == Phonon::StoppedState) { 1669 setTrack(m_pendingTitle); 1670 } else { 1671 setState(Phonon::StoppedState); 1672 } 1673 } 1674 1675 void MediaObject::setTrack(int title) 1676 { 1677 if (((m_state != Phonon::PlayingState) && (m_state != Phonon::StoppedState)) || (title < 1) || (title > m_availableTitles)) 1678 return; 1679 1680 1681 //let's seek to the beginning of the song 1505 1682 GstFormat trackFormat = gst_format_get_by_nick("track"); 1506 m_backend->logMessage(QString("setCurrentTitle %0").arg(title), Backend::Info, this); 1507 if ((title == m_currentTitle) || (title < 1) || (title > m_availableTitles)) 1508 return; 1509 1510 m_currentTitle = title; 1511 1512 //let's seek to the beginning of the song 1513 if (gst_element_seek_simple(m_pipeline, trackFormat, GST_SEEK_FLAG_FLUSH, m_currentTitle - 1)) { 1683 m_backend->logMessage(QString("setTrack %0").arg(title), Backend::Info, this); 1684 if (gst_element_seek_simple(m_pipeline, trackFormat, GST_SEEK_FLAG_FLUSH, title - 1)) { 1685 m_currentTitle = title; 1514 1686 updateTotalTime(); 1515 1687 m_atEndOfStream = false; -
trunk/src/3rdparty/phonon/gstreamer/mediaobject.h
r2 r846 56 56 { 57 57 friend class Stream; 58 friend class AudioDataOutput; 58 59 Q_OBJECT 59 60 Q_INTERFACES(Phonon::MediaObjectInterface … … 145 146 void handleEndOfStream(); 146 147 void addMissingCodecName(const QString &codec) { m_missingCodecs.append(codec); } 147 void invalidateGraph() { 148 m_resetNeeded = true; 149 if (m_state == Phonon::PlayingState || m_state == Phonon::PausedState) { 150 changeState(Phonon::StoppedState); 151 } 152 } 148 void invalidateGraph(); 149 153 150 static void cb_newpad (GstElement *decodebin, GstPad *pad, gboolean last, gpointer data); 154 151 static void cb_pad_added (GstElement *decodebin, GstPad *pad, gpointer data); … … 237 234 int _iface_currentTitle() const; 238 235 void _iface_setCurrentTitle(int title); 236 void setTrack(int title); 239 237 240 238 bool m_resumeState; … … 251 249 qint32 m_prefinishMark; 252 250 qint32 m_transitionTime; 251 bool m_isStream; 253 252 254 253 qint64 m_posAtSeek; … … 286 285 int m_availableTitles; 287 286 int m_currentTitle; 287 int m_pendingTitle; 288 288 }; 289 289 } -
trunk/src/3rdparty/phonon/gstreamer/qwidgetvideosink.h
r2 r846 20 20 21 21 #include "common.h" 22 #include "qwidgetvideosink.h" 22 23 23 24 #include <QtCore/QByteArray> -
trunk/src/3rdparty/phonon/gstreamer/videowidget.h
r561 r846 26 26 #include "medianode.h" 27 27 #include "abstractrenderer.h" 28 #include "videowidget.h" 28 29 29 30 #include <gst/gst.h> -
trunk/src/3rdparty/phonon/gstreamer/x11renderer.cpp
r2 r846 91 91 videoSink = 0; 92 92 } else { 93 // Note that this should not really be nec cessary as these are93 // Note that this should not really be necessary as these are 94 94 // default values, though under certain conditions values are retained 95 95 // even between application instances. (reproducible on 0.10.16/Gutsy) … … 139 139 { 140 140 Q_UNUSED(movieSize); 141 141 142 if (m_renderWidget) { 142 143 m_renderWidget->setGeometry(m_videoWidget->calculateDrawFrameRect());
Note:
See TracChangeset
for help on using the changeset viewer.