SVN commit 783276 by jbache: * A bit more debug info * Larger max-buffers for streams * Fixed some x11 resizing issues M +1 -2 audiooutput.cpp M +13 -8 backend.cpp M +8 -11 medianode.cpp M +49 -20 mediaobject.cpp M +2 -1 mediaobject.h M +3 -2 videowidget.cpp M +6 -0 x11renderer.cpp --- trunk/kdereview/phonon/gstreamer/audiooutput.cpp #783275:783276 @@ -126,8 +126,7 @@ { if (root()) { root()->stop(); // We cannot currently change audiodevice while the stream is playing - if (gst_element_get_state (root()->pipeline(), NULL, NULL, 3000) != GST_STATE_CHANGE_SUCCESS) - return false; + root()->invalidateGraph(); } bool success = false; --- trunk/kdereview/phonon/gstreamer/backend.cpp #783275:783276 @@ -315,6 +315,7 @@ MediaNode *sinkNode = qobject_cast(sink); if (sourceNode && sinkNode) { if (sourceNode->connectNode(sink)) { + sourceNode->root()->invalidateGraph(); logMessage(QString("Backend connected %0 to %1").arg(source->metaObject()->className()).arg(sink->metaObject()->className())); return true; } @@ -411,16 +412,20 @@ { if (debugLevel() > 0) { QString output; - if (obj) - output = QString("%0 (%1 %2)").arg(message).arg(obj->objectName()).arg(obj->metaObject()->className()); - else + if (obj) { + // Strip away namespace from className + QString className(obj->metaObject()->className()); + int nameLength = className.length() - className.lastIndexOf(':') - 1; + className = className.right(nameLength); + output.sprintf("%s %s (%s %p)", message.toLatin1().constData(), + obj->objectName().toLatin1().constData(), + className.toLatin1().constData(), obj); + } + else { output = message; - + } if (priority <= (int)debugLevel()) { - if (priority == Backend::Warning) - qDebug() << "PHONON_GST(warn): " << output; - else - qDebug() << "PHONON_GST(info): " << output; + qDebug() << QString("PGST(%1): %2").arg(priority).arg(output); } } } --- trunk/kdereview/phonon/gstreamer/medianode.cpp #783275:783276 @@ -293,6 +293,7 @@ if (!sinkElement) return false; + GstState state = GST_STATE (root()->pipeline()); GstPad *srcPad = gst_element_get_request_pad (tee, "src%d"); GstPad *sinkPad = gst_element_get_pad (sinkElement, "sink"); @@ -304,14 +305,6 @@ return true; } - // Sync state with pipeline before adding - // and fail if this is not possible - GstState state = GST_STATE (root()->pipeline()); - if (gst_element_set_state(sinkElement, state) == GST_STATE_CHANGE_FAILURE) { - success = false; - m_backend->logMessage("Could not sync element state with pipeline, connection failed"); - } - if (success) { if (output->description() & AudioSink) gst_bin_add(GST_BIN(root()->audioGraph()), sinkElement); @@ -319,10 +312,12 @@ gst_bin_add(GST_BIN(root()->videoGraph()), sinkElement); } - if (success) + if (success) { gst_pad_link(srcPad, sinkPad); - else + gst_element_set_state(sinkElement, state); + } else { gst_element_release_request_pad(tee, srcPad); + } gst_object_unref (GST_OBJECT (srcPad)); gst_object_unref (GST_OBJECT (sinkPad)); @@ -344,9 +339,10 @@ GstPad *srcPad = gst_element_get_request_pad (tee, "src%d"); gst_bin_add(GST_BIN(bin), sink); - success = (gst_element_set_state(sink, GST_STATE(bin)) != GST_STATE_CHANGE_FAILURE); if (success) success = (gst_pad_link (srcPad, sinkPad) == GST_PAD_LINK_OK); + if (success) + success = (gst_element_set_state(sink, GST_STATE(bin)) != GST_STATE_CHANGE_FAILURE); gst_object_unref (srcPad); gst_object_unref (sinkPad); return success; @@ -379,6 +375,7 @@ gst_bin_add(GST_BIN(bin), tee); if (!gst_element_link_pads(src, "src", tee, "sink")) return false; + gst_element_set_state(tee, GST_STATE(bin)); } if (list.isEmpty()) { //connect node to a fake sink to avoid clogging the pipeline --- trunk/kdereview/phonon/gstreamer/mediaobject.cpp #783275:783276 @@ -35,6 +35,7 @@ #include #define ABOUT_TO_FINNISH_TIME 2000 +#define MAX_QUEUE_TIME 20 * GST_SECOND QT_BEGIN_NAMESPACE @@ -71,6 +72,7 @@ , m_audioGraph(0) , m_videoGraph(0) , m_previousTickTime(-1) + , m_resetNeeded(false) { qRegisterMetaType("GstCaps*"); @@ -222,15 +224,15 @@ if (addToPipeline(m_videoGraph)) { GstPad *videopad = gst_element_get_pad (m_videoGraph, "sink"); if (!GST_PAD_IS_LINKED (videopad) && (gst_pad_link (pad, videopad) == GST_PAD_LINK_OK)) { + gst_element_set_state(m_videoGraph, GST_STATE_PAUSED); m_videoStreamFound = true; - m_backend->logMessage("Video track connected"); + 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); - gst_element_set_state(m_videoGraph, GST_STATE_PAUSED); } gst_object_unref (videopad); } else { - m_backend->logMessage("The video stream could not be plugged."); + m_backend->logMessage("The video stream could not be plugged.", Backend::Info, this); } } @@ -239,13 +241,13 @@ if (addToPipeline(m_audioGraph)) { GstPad *audiopad = gst_element_get_pad (m_audioGraph, "sink"); if (!GST_PAD_IS_LINKED (audiopad) && (gst_pad_link (pad, audiopad)==GST_PAD_LINK_OK)) { + gst_element_set_state(m_audioGraph, GST_STATE_PAUSED); m_hasAudio = true; - m_backend->logMessage("Audio track connected"); - gst_element_set_state(m_audioGraph, GST_STATE_PAUSED); + m_backend->logMessage("Audio track connected", Backend::Info, this); } gst_object_unref (audiopad); } else { - m_backend->logMessage("The audio stream could not be plugged."); + m_backend->logMessage("The audio stream could not be plugged.", Backend::Info, this); } } @@ -332,7 +334,12 @@ gst_object_ref (GST_OBJECT (m_audioGraph)); gst_object_sink (GST_OBJECT (m_audioGraph)); - m_audioPipe = gst_element_factory_make("identity", NULL); + // Note that these queues are only required for streaming content + // And should ideally be created on demand as they will disable + // pull-mode access. Also note that the max-size-time are increased to + // reduce buffer overruns as these are not gracefully handled at the moment. + m_audioPipe = gst_element_factory_make("queue", NULL); + g_object_set(G_OBJECT(m_audioPipe), "max-size-time", MAX_QUEUE_TIME, NULL); gst_bin_add(GST_BIN(m_audioGraph), m_audioPipe); GstPad *audiopad = gst_element_get_pad (m_audioPipe, "sink"); gst_element_add_pad (m_audioGraph, gst_ghost_pad_new ("sink", audiopad)); @@ -343,7 +350,8 @@ gst_object_ref (GST_OBJECT (m_videoGraph)); gst_object_sink (GST_OBJECT (m_videoGraph)); - m_videoPipe = gst_element_factory_make("identity", NULL); + m_videoPipe = gst_element_factory_make("queue", NULL); + g_object_set(G_OBJECT(m_videoPipe), "max-size-time", MAX_QUEUE_TIME, NULL); gst_bin_add(GST_BIN(m_videoGraph), m_videoPipe); GstPad *videopad = gst_element_get_pad (m_videoPipe, "sink"); gst_element_add_pad (m_videoGraph, gst_ghost_pad_new ("sink", videopad)); @@ -494,6 +502,14 @@ break; case Phonon::PlayingState: + if (m_resetNeeded) { + // ### Note this is a workaround and it should really be gracefully + // handled by medianode when we implement live connections. + // This generally happens if medianodes have been connected after the MediaSource was set + // Note that a side-effect of this is that we resend all meta data. + gst_element_set_state(m_pipeline, GST_STATE_NULL); + m_resetNeeded = false; + } m_backend->logMessage("phonon state request: Playing", Backend::Info, this); if (m_atEndOfStream) { m_backend->logMessage("EOS already reached", Backend::Info, this); @@ -570,7 +586,14 @@ m_error = error; m_tickTimer->stop(); - changeState(Phonon::ErrorState); + if (error == Phonon::FatalError) { + emit hasVideoChanged(false); + gst_element_set_state(m_pipeline, GST_STATE_READY); + changeState(Phonon::ErrorState); + } else { + //Flag error after loading has completed + m_pendingState = Phonon::ErrorState; + } } qint64 MediaObject::totalTime() const @@ -648,11 +671,11 @@ } if (m_seekable) - m_backend->logMessage("Stream is seekable"); + m_backend->logMessage("Stream is seekable", Backend::Info, this); else - m_backend->logMessage("Stream is non-seekable"); + m_backend->logMessage("Stream is non-seekable", Backend::Info, this); } else { - m_backend->logMessage("updateSeekable query failed"); + m_backend->logMessage("updateSeekable query failed", Backend::Info, this); } gst_query_unref (query); } @@ -689,9 +712,6 @@ if (!isValid()) return; - if (errorType() == FatalError) - return; - // We have to reset the state completely here, otherwise // remnants of the old pipeline can result in strangenes // such as failing duration queries etc @@ -709,6 +729,7 @@ // Go into to loading state changeState(Phonon::LoadingState); m_loading = true; + m_resetNeeded = false; m_pendingState = Phonon::StoppedState; // Make sure we start out unconnected @@ -784,7 +805,7 @@ void MediaObject::beginLoad() { if (gst_element_set_state(m_pipeline, GST_STATE_PAUSED) != GST_STATE_CHANGE_FAILURE) { - m_backend->logMessage("Begin source load"); + m_backend->logMessage("Begin source load", Backend::Info, this); } else { setError(tr("Could not load source")); } @@ -985,6 +1006,14 @@ GstMessage *gstMessage = message.rawMessage(); Q_ASSERT(m_pipeline); + if (m_backend->debugLevel() >= Backend::Debug) { + int type = GST_MESSAGE_TYPE(gstMessage); + gchar* name = gst_element_get_name(gstMessage->src); + QString message = QString("Bus: %0 (%1)").arg(gst_message_type_get_name ((GstMessageType)type)).arg(name); + g_free(name); + m_backend->logMessage(message, Backend::Debug, this); + } + switch (GST_MESSAGE_TYPE (gstMessage)) { case GST_MESSAGE_EOS: @@ -1065,7 +1094,10 @@ QString message; message.sprintf("Error: %s", err->message); m_backend->logMessage(message, Backend::Warning); - setError(QString(err->message)); + if (err->domain == GST_STREAM_ERROR) //Cannot continue + setError(QString(err->message), Phonon::FatalError); + else + setError(QString(err->message), Phonon::NormalError); g_error_free (err); break; } @@ -1122,9 +1154,6 @@ //case GST_MESSAGE_LATENCY: only from 0.10.12 //case GST_MESSAGE_ASYNC_DONE: only from 0.10.13 default: - int type = GST_MESSAGE_TYPE(gstMessage); - QString message = QString("Bus: %0").arg(gst_message_type_get_name ((GstMessageType)type)); - //m_backend->logMessage(message, Backend::Debug, this); break; } } --- trunk/kdereview/phonon/gstreamer/mediaobject.h #783275:783276 @@ -143,6 +143,7 @@ void handleBusMessage(const Message &msg); void handleEndOfStream(); void setState(State); + void invalidateGraph() {m_resetNeeded = true;} static void cb_newpad (GstElement *decodebin, GstPad *pad, gboolean last, gpointer data); static void cb_unknown_type (GstElement *decodebin, GstPad *pad, GstCaps *caps, gpointer data); @@ -237,7 +238,7 @@ GstElement *m_audioGraph; GstElement *m_videoGraph; int m_previousTickTime; - + bool m_resetNeeded; QMultiMap m_metaData; }; } --- trunk/kdereview/phonon/gstreamer/videowidget.cpp #783275:783276 @@ -134,11 +134,10 @@ // Disable overlays for graphics view if (root() && parentWidget() && parentWidget()->testAttribute(Qt::WA_DontShowOnScreen) && !m_renderer->paintsOnWidget()) { - m_backend->logMessage(QString("Overlays disabled"), Backend::Info); + m_backend->logMessage(QString("Widget rendering forced"), Backend::Info, this); GstElement *videoSink = m_renderer->videoSink(); Q_ASSERT(videoSink); - gst_element_set_state (root()->pipeline(), GST_STATE_READY); gst_element_set_state (videoSink, GST_STATE_NULL); gst_bin_remove(GST_BIN(m_videoBin), videoSink); delete m_renderer; @@ -148,8 +147,10 @@ videoSink = m_renderer->videoSink(); gst_bin_add(GST_BIN(m_videoBin), videoSink); gst_element_link(m_videoplug, videoSink); + gst_element_set_state (videoSink, GST_STATE_PAUSED); // Request return to current state + root()->invalidateGraph(); root()->setState(root()->state()); } QWidget::setVisible(val); --- trunk/kdereview/phonon/gstreamer/x11renderer.cpp #783275:783276 @@ -124,7 +124,13 @@ if (e->type() == QEvent::Show) { m_videoWidget->setAttribute(Qt::WA_PaintOnScreen, true); setOverlay(); + } else if (e->type() == QEvent::Resize) { + // This is a workaround for missing background repaints + // when reducing window size + QApplication::syncX(); + windowExposed(); } + return false; }