From e02d340f851d4882173f619d8642473f3624ec9c Mon Sep 17 00:00:00 2001 From: Philippe Normand Date: Fri, 8 Jan 2016 17:53:14 +0100 Subject: [PATCH 1/6] [GStreamer] fix some rounding issues Partly ported from https://bugs.webkit.org/show_bug.cgi?id=90734 --- .../WebCore/platform/graphics/gstreamer/GStreamerUtilities.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/WebCore/platform/graphics/gstreamer/GStreamerUtilities.cpp b/Source/WebCore/platform/graphics/gstreamer/GStreamerUtilities.cpp index 430f889e69956..4f848e3a18e76 100644 --- a/Source/WebCore/platform/graphics/gstreamer/GStreamerUtilities.cpp +++ b/Source/WebCore/platform/graphics/gstreamer/GStreamerUtilities.cpp @@ -181,7 +181,7 @@ GstClockTime toGstClockTime(float time) float microSeconds = modff(time, &seconds) * 1000000; GTimeVal timeValue; timeValue.tv_sec = static_cast(seconds); - timeValue.tv_usec = static_cast(roundf(microSeconds / 10000) * 10000); + timeValue.tv_usec = static_cast(floor(microSeconds + 0.5)); return GST_TIMEVAL_TO_TIME(timeValue); } From 0a23e286ea7fd6edc1b8470e95de5d18456c4355 Mon Sep 17 00:00:00 2001 From: Philippe Normand Date: Fri, 8 Jan 2016 17:57:18 +0100 Subject: [PATCH 2/6] [GStreamer][MSE] refactor no-data timer management --- .../MediaPlayerPrivateGStreamerMSE.cpp | 106 +++++++++--------- 1 file changed, 55 insertions(+), 51 deletions(-) diff --git a/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamerMSE.cpp b/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamerMSE.cpp index 3104f3771b792..c8333804ea430 100644 --- a/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamerMSE.cpp +++ b/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamerMSE.cpp @@ -77,9 +77,9 @@ namespace WebCore { class AppendPipeline : public ThreadSafeRefCounted { public: - enum AppendStage { Invalid, NotStarted, Ongoing, KeyNegotiation, NoDataToDecode, Sampling, LastSample, Aborting }; + enum AppendStage { Invalid, NotStarted, Ongoing, KeyNegotiation, DataStarve, Sampling, LastSample, Aborting }; - static const unsigned int s_noDataToDecodeTimeoutMsec = 1000; + static const unsigned int s_dataStarvedTimeoutMsec = 1000; static const unsigned int s_lastSampleTimeoutMsec = 250; AppendPipeline(PassRefPtr mediaSourceClient, PassRefPtr sourceBufferPrivate, MediaPlayerPrivateGStreamerMSE* playerPrivate); @@ -118,6 +118,9 @@ class AppendPipeline : public ThreadSafeRefCounted { void connectToAppSinkFromAnyThread(GstPad* demuxersrcpad); void connectToAppSink(GstPad* demuxersrcpad); + void scheduleDataStarveTimer(); + void cancelDataStarveTimer(); + private: void resetPipeline(); @@ -157,7 +160,7 @@ class AppendPipeline : public ThreadSafeRefCounted { // useful stream data for decoding. This is detected with a // timeout and reported to the upper layers, so update/updateend // can be generated and the append operation doesn't block. - guint m_noDataToDecodeTimeoutTag; + guint m_dataStarvedTimeoutTag; // Used to detect the last sample. Rescheduled each time a new // sample arrives. @@ -166,7 +169,7 @@ class AppendPipeline : public ThreadSafeRefCounted { // Keeps track of the stages of append processing, to avoid // performing actions inappropriate for the current stage (eg: // processing more samples when the last one has been detected - // or the noDataToDecodeTimeout has been triggered). + // or the dataStarvedTimeout has been triggered). // See setAppendStage() for valid transitions. AppendStage m_appendStage; @@ -1143,8 +1146,8 @@ static const char* dumpAppendStage(AppendPipeline::AppendStage appendStage) return "Ongoing"; case AppendPipeline::AppendStage::KeyNegotiation: return "KeyNegotiation"; - case AppendPipeline::AppendStage::NoDataToDecode: - return "NoDataToDecode"; + case AppendPipeline::AppendStage::DataStarve: + return "DataStarve"; case AppendPipeline::AppendStage::Sampling: return "Sampling"; case AppendPipeline::AppendStage::LastSample: @@ -1165,7 +1168,7 @@ static GstFlowReturn appendPipelineAppSinkNewSample(GstElement*, AppendPipeline* static gboolean appendPipelineAppSinkNewSampleMainThread(NewSampleInfo*); static void appendPipelineAppSinkEOS(GstElement*, AppendPipeline*); static gboolean appendPipelineAppSinkEOSMainThread(AppendPipeline* ap); -static gboolean appendPipelineNoDataToDecodeTimeout(AppendPipeline* ap); +static gboolean appendPipelineDataStarveTimeout(AppendPipeline* ap); static gboolean appendPipelineLastSampleTimeout(AppendPipeline* ap); static void appendPipelineElementMessageCallback(GstBus*, GstMessage* message, AppendPipeline* ap) @@ -1180,7 +1183,7 @@ AppendPipeline::AppendPipeline(PassRefPtr mediaSo , m_id(0) , m_appSinkCaps(NULL) , m_demuxerSrcPadCaps(NULL) - , m_noDataToDecodeTimeoutTag(0) + , m_dataStarvedTimeoutTag(0) , m_lastSampleTimeoutTag(0) , m_appendStage(NotStarted) , m_abortPending(false) @@ -1257,11 +1260,11 @@ AppendPipeline::~AppendPipeline() g_mutex_unlock(&m_padAddRemoveMutex); LOG_MEDIA_MESSAGE("%p", this); - if (m_noDataToDecodeTimeoutTag) { - LOG_MEDIA_MESSAGE("m_noDataToDecodeTimeoutTag=%u", m_noDataToDecodeTimeoutTag); + if (m_dataStarvedTimeoutTag) { + LOG_MEDIA_MESSAGE("m_dataStarvedTimeoutTag=%u", m_dataStarvedTimeoutTag); // TODO: Maybe notify appendComplete here? - g_source_remove(m_noDataToDecodeTimeoutTag); - m_noDataToDecodeTimeoutTag = 0; + g_source_remove(m_dataStarvedTimeoutTag); + m_dataStarvedTimeoutTag = 0; } if (m_lastSampleTimeoutTag) { @@ -1406,12 +1409,28 @@ gint AppendPipeline::id() return m_id; } +void AppendPipeline::scheduleDataStarveTimer() +{ + LOG_MEDIA_MESSAGE("Scheduling data starve timer"); + m_dataStarvedTimeoutTag = g_timeout_add(s_dataStarvedTimeoutMsec, GSourceFunc(appendPipelineDataStarveTimeout), this); +} + +void AppendPipeline::cancelDataStarveTimer() +{ + if (!m_dataStarvedTimeoutTag) + return; + + LOG_MEDIA_MESSAGE("Cancelling data starve timer"); + g_source_remove(m_dataStarvedTimeoutTag); + m_dataStarvedTimeoutTag = 0; +} + void AppendPipeline::setAppendStage(AppendStage newAppendStage) { ASSERT(WTF::isMainThread()); // Valid transitions: - // NotStarted-->Ongoing-->NoDataToDecode-->NotStarted - // | | `->Aborting-->NotStarted + // NotStarted-->Ongoing-->DataStarve-->NotStarted + // | | `->Aborting-->NotStarted // | `->Sampling-ยทยทยท->Sampling-->LastSample-->NotStarted // | | `->Aborting-->NotStarted // | `->KeyNegotiation-->Ongoing-->[...] @@ -1426,13 +1445,13 @@ void AppendPipeline::setAppendStage(AppendStage newAppendStage) switch (oldAppendStage) { case NotStarted: - ASSERT(m_noDataToDecodeTimeoutTag == 0); + ASSERT(m_dataStarvedTimeoutTag == 0); ASSERT(m_lastSampleTimeoutTag == 0); switch (newAppendStage) { case Ongoing: ok = true; gst_element_set_state(m_pipeline, GST_STATE_PLAYING); - m_noDataToDecodeTimeoutTag = g_timeout_add(s_noDataToDecodeTimeoutMsec, GSourceFunc(appendPipelineNoDataToDecodeTimeout), this); + scheduleDataStarveTimer(); break; case NotStarted: ok = true; @@ -1453,19 +1472,16 @@ void AppendPipeline::setAppendStage(AppendStage newAppendStage) } break; case KeyNegotiation: - ASSERT(m_noDataToDecodeTimeoutTag == 0); + ASSERT(m_dataStarvedTimeoutTag == 0); ASSERT(m_lastSampleTimeoutTag == 0); switch (newAppendStage) { case Ongoing: ok = true; - m_noDataToDecodeTimeoutTag = g_timeout_add(s_noDataToDecodeTimeoutMsec, GSourceFunc(appendPipelineNoDataToDecodeTimeout), this); + scheduleDataStarveTimer(); break; case Invalid: ok = true; - if (m_noDataToDecodeTimeoutTag) { - g_source_remove(m_noDataToDecodeTimeoutTag); - m_noDataToDecodeTimeoutTag = 0; - } + cancelDataStarveTimer(); if (m_lastSampleTimeoutTag) { g_source_remove(m_lastSampleTimeoutTag); m_lastSampleTimeoutTag = 0; @@ -1476,22 +1492,16 @@ void AppendPipeline::setAppendStage(AppendStage newAppendStage) } break; case Ongoing: - ASSERT(m_noDataToDecodeTimeoutTag != 0); + ASSERT(m_dataStarvedTimeoutTag != 0); ASSERT(m_lastSampleTimeoutTag == 0); switch (newAppendStage) { case KeyNegotiation: ok = true; - if (m_noDataToDecodeTimeoutTag) { - g_source_remove(m_noDataToDecodeTimeoutTag); - m_noDataToDecodeTimeoutTag = 0; - } + cancelDataStarveTimer(); break; - case NoDataToDecode: + case DataStarve: ok = true; - if (m_noDataToDecodeTimeoutTag) { - g_source_remove(m_noDataToDecodeTimeoutTag); - m_noDataToDecodeTimeoutTag = 0; - } + cancelDataStarveTimer(); m_mediaSourceClient->didReceiveAllPendingSamples(m_sourceBufferPrivate.get()); if (m_abortPending) nextAppendStage = Aborting; @@ -1500,10 +1510,7 @@ void AppendPipeline::setAppendStage(AppendStage newAppendStage) break; case Sampling: ok = true; - if (m_noDataToDecodeTimeoutTag) { - g_source_remove(m_noDataToDecodeTimeoutTag); - m_noDataToDecodeTimeoutTag = 0; - } + cancelDataStarveTimer(); if (m_lastSampleTimeoutTag) { TRACE_MEDIA_MESSAGE("lastSampleTimeoutTag already exists while transitioning Ongoing-->Sampling"); @@ -1514,10 +1521,7 @@ void AppendPipeline::setAppendStage(AppendStage newAppendStage) break; case Invalid: ok = true; - if (m_noDataToDecodeTimeoutTag) { - g_source_remove(m_noDataToDecodeTimeoutTag); - m_noDataToDecodeTimeoutTag = 0; - } + cancelDataStarveTimer(); if (m_lastSampleTimeoutTag) { g_source_remove(m_lastSampleTimeoutTag); m_lastSampleTimeoutTag = 0; @@ -1527,8 +1531,8 @@ void AppendPipeline::setAppendStage(AppendStage newAppendStage) break; } break; - case NoDataToDecode: - ASSERT(m_noDataToDecodeTimeoutTag == 0); + case DataStarve: + ASSERT(m_dataStarvedTimeoutTag == 0); ASSERT(m_lastSampleTimeoutTag == 0); switch (newAppendStage) { case NotStarted: @@ -1546,7 +1550,7 @@ void AppendPipeline::setAppendStage(AppendStage newAppendStage) } break; case Sampling: - ASSERT(m_noDataToDecodeTimeoutTag == 0); + ASSERT(m_dataStarvedTimeoutTag == 0); ASSERT(m_lastSampleTimeoutTag != 0); switch (newAppendStage) { case Sampling: @@ -1581,7 +1585,7 @@ void AppendPipeline::setAppendStage(AppendStage newAppendStage) } break; case LastSample: - ASSERT(m_noDataToDecodeTimeoutTag == 0); + ASSERT(m_dataStarvedTimeoutTag == 0); ASSERT(m_lastSampleTimeoutTag == 0); switch (newAppendStage) { case NotStarted: @@ -1599,7 +1603,7 @@ void AppendPipeline::setAppendStage(AppendStage newAppendStage) } break; case Aborting: - ASSERT(m_noDataToDecodeTimeoutTag == 0); + ASSERT(m_dataStarvedTimeoutTag == 0); ASSERT(m_lastSampleTimeoutTag == 0); switch (newAppendStage) { case NotStarted: @@ -1616,7 +1620,7 @@ void AppendPipeline::setAppendStage(AppendStage newAppendStage) } break; case Invalid: - ASSERT(m_noDataToDecodeTimeoutTag == 0); + ASSERT(m_dataStarvedTimeoutTag == 0); ASSERT(m_lastSampleTimeoutTag == 0); ok = true; break; @@ -1794,7 +1798,7 @@ void AppendPipeline::appSinkEOS() return; // Finish Ongoing and Sampling stages. case Ongoing: - setAppendStage(NoDataToDecode); + setAppendStage(DataStarve); break; case Sampling: setAppendStage(LastSample); @@ -2173,13 +2177,13 @@ static gboolean appendPipelineAppSinkEOSMainThread(AppendPipeline* ap) return G_SOURCE_REMOVE; } -static gboolean appendPipelineNoDataToDecodeTimeout(AppendPipeline* ap) +static gboolean appendPipelineDataStarveTimeout(AppendPipeline* ap) { - TRACE_MEDIA_MESSAGE("no data timeout fired"); + LOG_MEDIA_MESSAGE("data starve timer fired"); if (ap->appendStage()==AppendPipeline::AppendStage::Invalid) return G_SOURCE_REMOVE; - ap->setAppendStage(AppendPipeline::NoDataToDecode); + ap->setAppendStage(AppendPipeline::DataStarve); return G_SOURCE_REMOVE; } @@ -2216,7 +2220,7 @@ MediaSourceClientGStreamerMSE::~MediaSourceClientGStreamerMSE() { ASSERT(WTF::isMainThread()); - // TODO: cancel m_noDataToDecodeTimeoutTag if active and perform appendComplete() + // TODO: cancel m_dataStarvedTimeoutTag if active and perform appendComplete() } MediaSourcePrivate::AddStatus MediaSourceClientGStreamerMSE::addSourceBuffer(RefPtr sourceBufferPrivate, const ContentType&) From e6bbdb2fd86b4eb94319acccfb5013d83bb46392 Mon Sep 17 00:00:00 2001 From: Philippe Normand Date: Fri, 8 Jan 2016 17:59:04 +0100 Subject: [PATCH 3/6] [GStreamer][MSE] remove duplicated floatToGstClockTime function --- .../gstreamer/WebKitMediaSourceGStreamer.cpp | 20 +++---------------- 1 file changed, 3 insertions(+), 17 deletions(-) diff --git a/Source/WebCore/platform/graphics/gstreamer/WebKitMediaSourceGStreamer.cpp b/Source/WebCore/platform/graphics/gstreamer/WebKitMediaSourceGStreamer.cpp index 234652af9a579..b90a8bcb5386f 100644 --- a/Source/WebCore/platform/graphics/gstreamer/WebKitMediaSourceGStreamer.cpp +++ b/Source/WebCore/platform/graphics/gstreamer/WebKitMediaSourceGStreamer.cpp @@ -162,7 +162,6 @@ static GstStateChangeReturn webKitMediaSrcChangeState(GstElement*, GstStateChang static gboolean webKitMediaSrcQueryWithParent(GstPad*, GstObject*, GstQuery*); inline static AtomicString getStreamTrackId(Stream*); -static GstClockTime floatToGstClockTime(float); static gboolean freeStreamLater(Stream*); static gboolean releaseStreamTrackInfo(WebKitMediaSrc*, Stream*); @@ -391,8 +390,8 @@ static gboolean webKitMediaSrcQueryWithParent(GstPad* pad, GstObject* parent, Gs GST_OBJECT_LOCK(src); float duration; if (format == GST_FORMAT_TIME && src->priv && src->priv->mediaPlayerPrivate && ((duration = src->priv->mediaPlayerPrivate->duration()) > 0)) { - gst_query_set_duration(query, format, floatToGstClockTime(duration)); - GST_DEBUG_OBJECT(src, "Answering: duration=%" GST_TIME_FORMAT, GST_TIME_ARGS(floatToGstClockTime(duration))); + gst_query_set_duration(query, format, WebCore::toGstClockTime(duration)); + GST_DEBUG_OBJECT(src, "Answering: duration=%" GST_TIME_FORMAT, GST_TIME_ARGS(WebCore::toGstClockTime(duration))); result = TRUE; } GST_OBJECT_UNLOCK(src); @@ -1276,8 +1275,7 @@ void PlaybackPipeline::enqueueSample(PassRefPtr prsample) RefPtr rsample = prsample; AtomicString trackId = rsample->trackID(); - TRACE_MEDIA_MESSAGE("enqueing sample trackId=%s PTS=%f presentationSize=%.0fx%.0f at %" GST_TIME_FORMAT, trackId.string().utf8().data(), rsample->presentationTime().toFloat(), rsample->presentationSize().width(), rsample->presentationSize().height(), GST_TIME_ARGS(floatToGstClockTime(rsample->presentationTime().toDouble()))); - + TRACE_MEDIA_MESSAGE("enqueing sample trackId=%s PTS=%f presentationSize=%.0fx%.0f at %" GST_TIME_FORMAT " duration: %" GST_TIME_FORMAT, trackId.string().utf8().data(), rsample->presentationTime().toFloat(), rsample->presentationSize().width(), rsample->presentationSize().height(), GST_TIME_ARGS(WebCore::toGstClockTime(rsample->presentationTime().toDouble())), GST_TIME_ARGS(WebCore::toGstClockTime(rsample->duration().toDouble()))); ASSERT(WTF::isMainThread()); GST_OBJECT_LOCK(m_webKitMediaSrc.get()); @@ -1368,18 +1366,6 @@ void webkit_media_src_prepare_seek(WebKitMediaSrc* src, const MediaTime& time) GST_OBJECT_UNLOCK(src); } -static GstClockTime floatToGstClockTime(float time) -{ - // Extract the integer part of the time (seconds) and the fractional part (microseconds). Attempt to - // round the microseconds so no floating point precision is lost and we can perform an accurate seek. - float seconds; - float microSeconds = std::modf(time, &seconds) * 1000000; - GTimeVal timeValue; - timeValue.tv_sec = static_cast(seconds); - timeValue.tv_usec = static_cast(roundf(microSeconds / 10000) * 10000); - return GST_TIMEVAL_TO_TIME(timeValue); -} - namespace WTF { template <> GRefPtr adoptGRef(WebKitMediaSrc* ptr) { From 8734de47b1513392729ef36fcb47abfa039e9e28 Mon Sep 17 00:00:00 2001 From: Philippe Normand Date: Fri, 8 Jan 2016 18:01:29 +0100 Subject: [PATCH 4/6] [GStreamer][MSE] simplify AppendPipeline::handleNewSample This is never called from the main thread. --- .../MediaPlayerPrivateGStreamerMSE.cpp | 25 ++++++++----------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamerMSE.cpp b/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamerMSE.cpp index c8333804ea430..d5cd61bd98ce8 100644 --- a/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamerMSE.cpp +++ b/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamerMSE.cpp @@ -1901,10 +1901,9 @@ GstFlowReturn AppendPipeline::pushNewBuffer(GstBuffer* buffer) GstFlowReturn AppendPipeline::handleNewSample(GstElement* appsink) { - TRACE_MEDIA_MESSAGE("thread %d", WTF::currentThread()); + ASSERT(!WTF::isMainThread()); bool invalid; - g_mutex_lock(&m_newSampleMutex); invalid = !m_playerPrivate || m_appendStage == Invalid; g_mutex_unlock(&m_newSampleMutex); @@ -1919,20 +1918,16 @@ GstFlowReturn AppendPipeline::handleNewSample(GstElement* appsink) return GST_FLOW_ERROR; } - if (WTF::isMainThread()) { - appSinkNewSample(sample); - } else { - g_mutex_lock(&m_newSampleMutex); - if (!(!m_playerPrivate || m_appendStage == Invalid)) { - NewSampleInfo* info = new NewSampleInfo(sample, this); - g_timeout_add(0, GSourceFunc(appendPipelineAppSinkNewSampleMainThread), info); - g_cond_wait(&m_newSampleCondition, &m_newSampleMutex); - // We've been awaken because the sample was processed or because of - // an exceptional condition (entered in Invalid state, destructor, etc.) - // We can't reliably delete info here, appendPipelineAppSinkNewSampleMainThread will do it. - } - g_mutex_unlock(&m_newSampleMutex); + g_mutex_lock(&m_newSampleMutex); + if (!(!m_playerPrivate || m_appendStage == Invalid)) { + NewSampleInfo* info = new NewSampleInfo(sample, this); + g_timeout_add(0, GSourceFunc(appendPipelineAppSinkNewSampleMainThread), info); + g_cond_wait(&m_newSampleCondition, &m_newSampleMutex); + // We've been awaken because the sample was processed or because of + // an exceptional condition (entered in Invalid state, destructor, etc.) + // We can't reliably delete info here, appendPipelineAppSinkNewSampleMainThread will do it. } + g_mutex_unlock(&m_newSampleMutex); gst_sample_unref(sample); return m_flowReturn; } From f7474414bc58d7bc8013693c3e3c21df1c094b94 Mon Sep 17 00:00:00 2001 From: Philippe Normand Date: Wed, 13 Jan 2016 13:12:28 +0100 Subject: [PATCH 5/6] [GStreamer][MSE] byte duration query support in src element --- .../gstreamer/WebKitMediaSourceGStreamer.cpp | 39 ++++++++++++++++--- 1 file changed, 34 insertions(+), 5 deletions(-) diff --git a/Source/WebCore/platform/graphics/gstreamer/WebKitMediaSourceGStreamer.cpp b/Source/WebCore/platform/graphics/gstreamer/WebKitMediaSourceGStreamer.cpp index b90a8bcb5386f..52c9d11aec3c2 100644 --- a/Source/WebCore/platform/graphics/gstreamer/WebKitMediaSourceGStreamer.cpp +++ b/Source/WebCore/platform/graphics/gstreamer/WebKitMediaSourceGStreamer.cpp @@ -376,6 +376,16 @@ static GstStateChangeReturn webKitMediaSrcChangeState(GstElement* element, GstSt return ret; } +gint64 webKitMediaSrcGetSize(WebKitMediaSrc* webKitMediaSrc) +{ + gint64 duration = 0; + for (GList* streams = webKitMediaSrc->priv->streams; streams; streams = streams->next) { + Stream* s = static_cast(streams->data); + duration = MAX(duration, gst_app_src_get_size(GST_APP_SRC(s->appsrc))); + } + return duration; +} + static gboolean webKitMediaSrcQueryWithParent(GstPad* pad, GstObject* parent, GstQuery* query) { WebKitMediaSrc* src = WEBKIT_MEDIA_SRC(GST_ELEMENT(parent)); @@ -388,12 +398,31 @@ static gboolean webKitMediaSrcQueryWithParent(GstPad* pad, GstObject* parent, Gs GST_DEBUG_OBJECT(src, "duration query in format %s", gst_format_get_name(format)); GST_OBJECT_LOCK(src); - float duration; - if (format == GST_FORMAT_TIME && src->priv && src->priv->mediaPlayerPrivate && ((duration = src->priv->mediaPlayerPrivate->duration()) > 0)) { - gst_query_set_duration(query, format, WebCore::toGstClockTime(duration)); - GST_DEBUG_OBJECT(src, "Answering: duration=%" GST_TIME_FORMAT, GST_TIME_ARGS(WebCore::toGstClockTime(duration))); - result = TRUE; + switch (format) { + case GST_FORMAT_TIME: { + float duration; + if (src->priv && src->priv->mediaPlayerPrivate && ((duration = src->priv->mediaPlayerPrivate->duration()) > 0)) { + gst_query_set_duration(query, format, WebCore::toGstClockTime(duration)); + GST_DEBUG_OBJECT(src, "Answering: duration=%" GST_TIME_FORMAT, GST_TIME_ARGS(WebCore::toGstClockTime(duration))); + result = TRUE; + } + break; } + case GST_FORMAT_BYTES: { + if (src->priv) { + gint64 duration = webKitMediaSrcGetSize(src); + if (duration) { + gst_query_set_duration(query, format, duration); + GST_DEBUG_OBJECT(src, "size: %" G_GINT64_FORMAT, duration); + result = TRUE; + } + } + break; + } + default: + break; + } + GST_OBJECT_UNLOCK(src); break; } From 3f981ef3cf21e40a5d8fc0b77ccc8e40ca1fa2c7 Mon Sep 17 00:00:00 2001 From: Philippe Normand Date: Wed, 13 Jan 2016 13:28:42 +0100 Subject: [PATCH 6/6] [GStreamer][MSE] emit no-more-pads earlier in the src element Since the caps are known already there is no need to wait the parser changes its src pad caps. --- .../MediaPlayerPrivateGStreamerMSE.cpp | 2 +- .../gstreamer/WebKitMediaSourceGStreamer.cpp | 29 +++++++------------ .../gstreamer/WebKitMediaSourceGStreamer.h | 2 +- 3 files changed, 12 insertions(+), 21 deletions(-) diff --git a/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamerMSE.cpp b/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamerMSE.cpp index d5cd61bd98ce8..d01ddc60abd4f 100644 --- a/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamerMSE.cpp +++ b/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamerMSE.cpp @@ -877,7 +877,7 @@ void MediaPlayerPrivateGStreamerMSE::trackDetected(RefPtr ap, Re } if (!oldTrack) - m_playbackPipeline->attachTrack(ap->sourceBufferPrivate(), newTrack, s); + m_playbackPipeline->attachTrack(ap->sourceBufferPrivate(), newTrack, s, caps); else m_playbackPipeline->reattachTrack(ap->sourceBufferPrivate(), newTrack); } diff --git a/Source/WebCore/platform/graphics/gstreamer/WebKitMediaSourceGStreamer.cpp b/Source/WebCore/platform/graphics/gstreamer/WebKitMediaSourceGStreamer.cpp index 52c9d11aec3c2..46be79aa4571f 100644 --- a/Source/WebCore/platform/graphics/gstreamer/WebKitMediaSourceGStreamer.cpp +++ b/Source/WebCore/platform/graphics/gstreamer/WebKitMediaSourceGStreamer.cpp @@ -500,21 +500,17 @@ static void webKitMediaSrcLinkStreamToSrcPad(GstPad* srcpad, Stream* stream) } } -static void webKitMediaSrcParserNotifyCaps(GObject* object, GParamSpec*, Stream* stream) +static void webKitMediaSrcLinkParser(GstPad* srcpad, GstCaps* caps, Stream* stream) { - GstPad* srcpad = GST_PAD(object); - GstCaps* caps = gst_pad_get_current_caps(srcpad); - + ASSERT(caps && stream->parent); if (!caps || !stream->parent) { + GST_ERROR("Unable to link parser"); return; } - LOG_MEDIA_MESSAGE("Caps changed"); - webKitMediaSrcUpdatePresentationSize(caps, stream); - gst_caps_unref(caps); - // TODO + // TODO: drop webKitMediaSrcLinkStreamToSrcPad() and move its code here... if (!gst_pad_is_linked(srcpad)) { GST_DEBUG_OBJECT(stream->parent, "pad not linked yet"); webKitMediaSrcLinkStreamToSrcPad(srcpad, stream); @@ -978,12 +974,11 @@ void PlaybackPipeline::removeSourceBuffer(RefPtr s } } -void PlaybackPipeline::attachTrack(RefPtr sourceBufferPrivate, RefPtr trackPrivate, GstStructure* s) +void PlaybackPipeline::attachTrack(RefPtr sourceBufferPrivate, RefPtr trackPrivate, GstStructure* s, GstCaps* caps) { WebKitMediaSrc* webKitMediaSrc = m_webKitMediaSrc.get(); Stream* stream = 0; gchar* parserBinName; - bool capsNotifyHandlerConnected = false; unsigned padId = 0; const gchar* mediaType = gst_structure_get_name(s); @@ -1020,8 +1015,7 @@ void PlaybackPipeline::attachTrack(RefPtr sourceBu gst_bin_add_many(GST_BIN(stream->parser), parser, capsfilter, NULL); gst_element_link_pads(parser, "src", capsfilter, "sink"); - if (!pad) - pad = gst_element_get_static_pad(parser, "sink"); + pad = gst_element_get_static_pad(parser, "sink"); gst_element_add_pad(stream->parser, gst_ghost_pad_new("sink", pad)); gst_object_unref(pad); @@ -1043,8 +1037,7 @@ void PlaybackPipeline::attachTrack(RefPtr sourceBu gst_bin_add_many(GST_BIN(stream->parser), parser, capsfilter, NULL); gst_element_link_pads(parser, "src", capsfilter, "sink"); - if (!pad) - pad = gst_element_get_static_pad(parser, "sink"); + pad = gst_element_get_static_pad(parser, "sink"); gst_element_add_pad(stream->parser, gst_ghost_pad_new("sink", pad)); gst_object_unref(pad); @@ -1061,14 +1054,14 @@ void PlaybackPipeline::attachTrack(RefPtr sourceBu parser = gst_element_factory_make("mpegaudioparse", 0); } else if (mpegversion == 2 || mpegversion == 4) { parser = gst_element_factory_make("aacparse", 0); + //g_object_set(parser, "disable-passthrough", TRUE, nullptr); } else { ASSERT_NOT_REACHED(); } gst_bin_add(GST_BIN(stream->parser), parser); - if (!pad) - pad = gst_element_get_static_pad(parser, "sink"); + pad = gst_element_get_static_pad(parser, "sink"); gst_element_add_pad(stream->parser, gst_ghost_pad_new("sink", pad)); gst_object_unref(pad); @@ -1100,9 +1093,7 @@ void PlaybackPipeline::attachTrack(RefPtr sourceBu srcpad = gst_element_get_static_pad(stream->parser, "src"); // TODO: Is padId the best way to identify the Stream? What about trackId? g_object_set_data(G_OBJECT(srcpad), "id", GINT_TO_POINTER(padId)); - if (!capsNotifyHandlerConnected) - g_signal_connect(srcpad, "notify::caps", G_CALLBACK(webKitMediaSrcParserNotifyCaps), stream); - webKitMediaSrcLinkStreamToSrcPad(srcpad, stream); + webKitMediaSrcLinkParser(srcpad, caps, stream); ASSERT(stream->parent->priv->mediaPlayerPrivate); int signal = -1; diff --git a/Source/WebCore/platform/graphics/gstreamer/WebKitMediaSourceGStreamer.h b/Source/WebCore/platform/graphics/gstreamer/WebKitMediaSourceGStreamer.h index 5e7a925bda09e..ac112aea461df 100644 --- a/Source/WebCore/platform/graphics/gstreamer/WebKitMediaSourceGStreamer.h +++ b/Source/WebCore/platform/graphics/gstreamer/WebKitMediaSourceGStreamer.h @@ -98,7 +98,7 @@ class PlaybackPipeline: public RefCounted { MediaSourcePrivate::AddStatus addSourceBuffer(RefPtr); void removeSourceBuffer(RefPtr); - void attachTrack(RefPtr, RefPtr, GstStructure*); + void attachTrack(RefPtr, RefPtr, GstStructure*, GstCaps*); void reattachTrack(RefPtr, RefPtr); void notifyDurationChanged();