Changeset 247010 in webkit


Ignore:
Timestamp:
Jul 1, 2019 9:57:03 AM (5 years ago)
Author:
Philippe Normand
Message:

[GStreamer] Cannot play Bert's Bytes radio stream from http://radio.dos.nl/
https://bugs.webkit.org/show_bug.cgi?id=198376

Reviewed by Xabier Rodriguez-Calvar.

Source/WebCore:

The delayed startup was due to a mix of buffering feedback
messages not handled correctly by the player. We were handling
download and streaming buffering metrics without distinction.
Range requests (used for seeking) were also triggering on-disk
buffering in some cases. The buffering percentage estimation based
on network read position was not working either because uint64_t
division doesn't return a floating point value.

No new tests, existing media tests cover this patch.

  • platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp:

(WebCore::MediaPlayerPrivateGStreamer::commitLoad):
(WebCore::MediaPlayerPrivateGStreamer::play):
(WebCore::MediaPlayerPrivateGStreamer::handleMessage):
(WebCore::MediaPlayerPrivateGStreamer::processBufferingStats):
(WebCore::MediaPlayerPrivateGStreamer::updateBufferingStatus):
(WebCore::MediaPlayerPrivateGStreamer::fillTimerFired):
(WebCore::MediaPlayerPrivateGStreamer::maxTimeLoaded const):
(WebCore::MediaPlayerPrivateGStreamer::didLoadingProgress const):
(WebCore::MediaPlayerPrivateGStreamer::updateStates):
(WebCore::MediaPlayerPrivateGStreamer::updateDownloadBufferingFlag):
(WebCore::MediaPlayerPrivateGStreamer::setPreload):

  • platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.h:
  • platform/graphics/gstreamer/WebKitWebSourceGStreamer.cpp:

(webkitWebSrcReset):

  • platform/graphics/gstreamer/mse/MediaPlayerPrivateGStreamerMSE.h:

Source/WTF:

  • wtf/glib/GLibUtilities.h:

(enumToString): Utility function to get a string representation of of a GLib enum.

Location:
trunk/Source
Files:
8 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WTF/ChangeLog

    r246951 r247010  
     12019-07-01  Philippe Normand  <pnormand@igalia.com>
     2
     3        [GStreamer] Cannot play Bert's Bytes radio stream from http://radio.dos.nl/
     4        https://bugs.webkit.org/show_bug.cgi?id=198376
     5
     6        Reviewed by Xabier Rodriguez-Calvar.
     7
     8        * wtf/glib/GLibUtilities.h:
     9        (enumToString): Utility function to get a string representation of of a GLib enum.
     10
    1112019-06-22  Darin Adler  <darin@apple.com>
    212
  • trunk/Source/WTF/wtf/glib/GLibUtilities.cpp

    r237099 r247010  
    7878    return g_get_prgname();
    7979}
     80
     81CString enumToString(GType type, guint value)
     82{
     83#if GLIB_CHECK_VERSION(2, 54, 0)
     84    GUniquePtr<char> result(g_enum_to_string(type, value));
     85    return result.get();
     86#else
     87    GEnumClass* enumClass = reinterpret_cast<GEnumClass*>(g_type_class_ref(type));
     88    GEnumValue* enumValue = g_enum_get_value(enumClass, value);
     89    char* representation = enumValue ? g_strdup(enumValue->value_nick) : nullptr;
     90    g_type_class_unref(enumClass);
     91    GUniquePtr<char> result(representation);
     92    return result.get();
     93#endif
     94}
  • trunk/Source/WTF/wtf/glib/GLibUtilities.h

    r228987 r247010  
    2121#define GLibUtilities_h
    2222
     23#include <glib-object.h>
    2324#include <wtf/Assertions.h>
    2425#include <wtf/text/CString.h>
     
    2627CString getCurrentExecutablePath();
    2728CString getCurrentExecutableName();
     29CString enumToString(GType, guint value);
    2830
    2931// These might be added to glib in the future, but in the meantime they're defined here.
  • trunk/Source/WebCore/ChangeLog

    r247007 r247010  
     12019-07-01  Philippe Normand  <pnormand@igalia.com>
     2
     3        [GStreamer] Cannot play Bert's Bytes radio stream from http://radio.dos.nl/
     4        https://bugs.webkit.org/show_bug.cgi?id=198376
     5
     6        Reviewed by Xabier Rodriguez-Calvar.
     7
     8        The delayed startup was due to a mix of buffering feedback
     9        messages not handled correctly by the player. We were handling
     10        download and streaming buffering metrics without distinction.
     11        Range requests (used for seeking) were also triggering on-disk
     12        buffering in some cases. The buffering percentage estimation based
     13        on network read position was not working either because uint64_t
     14        division doesn't return a floating point value.
     15
     16        No new tests, existing media tests cover this patch.
     17
     18        * platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp:
     19        (WebCore::MediaPlayerPrivateGStreamer::commitLoad):
     20        (WebCore::MediaPlayerPrivateGStreamer::play):
     21        (WebCore::MediaPlayerPrivateGStreamer::handleMessage):
     22        (WebCore::MediaPlayerPrivateGStreamer::processBufferingStats):
     23        (WebCore::MediaPlayerPrivateGStreamer::updateBufferingStatus):
     24        (WebCore::MediaPlayerPrivateGStreamer::fillTimerFired):
     25        (WebCore::MediaPlayerPrivateGStreamer::maxTimeLoaded const):
     26        (WebCore::MediaPlayerPrivateGStreamer::didLoadingProgress const):
     27        (WebCore::MediaPlayerPrivateGStreamer::updateStates):
     28        (WebCore::MediaPlayerPrivateGStreamer::updateDownloadBufferingFlag):
     29        (WebCore::MediaPlayerPrivateGStreamer::setPreload):
     30        * platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.h:
     31        * platform/graphics/gstreamer/WebKitWebSourceGStreamer.cpp:
     32        (webkitWebSrcReset):
     33        * platform/graphics/gstreamer/mse/MediaPlayerPrivateGStreamerMSE.h:
     34
    1352019-07-01  Miguel Gomez  <magomez@igalia.com>
    236
  • trunk/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp

    r246730 r247010  
    4949#include <wtf/URL.h>
    5050#include <wtf/WallTime.h>
    51 #include <wtf/glib/GUniquePtr.h>
     51#include <wtf/glib/GLibUtilities.h>
    5252#include <wtf/glib/RunLoopSourcePriority.h>
    5353#include <wtf/text/CString.h>
     
    350350    changePipelineState(GST_STATE_PAUSED);
    351351
    352     setDownloadBuffering();
     352    updateDownloadBufferingFlag();
    353353    updateStates();
    354354}
     
    459459        m_delayingLoad = false;
    460460        m_preload = MediaPlayer::Auto;
    461         setDownloadBuffering();
     461        updateDownloadBufferingFlag();
    462462        GST_INFO_OBJECT(pipeline(), "Play");
    463463    } else
     
    13501350                }
    13511351            }
     1352
     1353            bool isRangeRequest = false;
     1354            GUniqueOutPtr<GstStructure> requestHeaders;
     1355            if (gst_structure_get(structure, "request-headers", GST_TYPE_STRUCTURE, &requestHeaders.outPtr(), nullptr))
     1356                isRangeRequest = gst_structure_has_field(requestHeaders.get(), "Range");
     1357
     1358            GST_DEBUG_OBJECT(pipeline(), "Is range request: %s", boolForPrinting(isRangeRequest));
     1359
    13521360            GUniqueOutPtr<GstStructure> responseHeaders;
    13531361            if (gst_structure_get(structure, "response-headers", GST_TYPE_STRUCTURE, &responseHeaders.outPtr(), nullptr)) {
     
    13641372                    }
    13651373                }
    1366                 GST_INFO_OBJECT(pipeline(), "%s stream detected", !contentLength ? "Live" : "Non-live");
    1367                 if (!contentLength) {
    1368                     m_isStreaming = true;
    1369                     setDownloadBuffering();
     1374                if (!isRangeRequest) {
     1375                    m_isStreaming = !contentLength;
     1376                    GST_INFO_OBJECT(pipeline(), "%s stream detected", m_isStreaming ? "Live" : "Non-live");
     1377                    updateDownloadBufferingFlag();
    13701378                }
    13711379            }
     
    14511459void MediaPlayerPrivateGStreamer::processBufferingStats(GstMessage* message)
    14521460{
    1453     m_buffering = true;
    1454     gst_message_parse_buffering(message, &m_bufferingPercentage);
    1455 
    1456     GST_DEBUG_OBJECT(pipeline(), "[Buffering] Buffering: %d%%.", m_bufferingPercentage);
    1457 
    1458     if (m_bufferingPercentage == 100)
     1461    GstBufferingMode mode;
     1462    gst_message_parse_buffering_stats(message, &mode, nullptr, nullptr, nullptr);
     1463
     1464    int percentage;
     1465    gst_message_parse_buffering(message, &percentage);
     1466
     1467    updateBufferingStatus(mode, percentage);
     1468}
     1469
     1470void MediaPlayerPrivateGStreamer::updateMaxTimeLoaded(double percentage)
     1471{
     1472    MediaTime mediaDuration = durationMediaTime();
     1473    if (!mediaDuration)
     1474        return;
     1475
     1476    m_maxTimeLoaded = MediaTime(percentage * static_cast<double>(toGstUnsigned64Time(mediaDuration)) / 100, GST_SECOND);
     1477    GST_DEBUG_OBJECT(pipeline(), "[Buffering] Updated maxTimeLoaded: %s", toString(m_maxTimeLoaded).utf8().data());
     1478}
     1479
     1480void MediaPlayerPrivateGStreamer::updateBufferingStatus(GstBufferingMode mode, double percentage)
     1481{
     1482    GST_DEBUG_OBJECT(pipeline(), "[Buffering] mode: %s, status: %f%%", enumToString(GST_TYPE_BUFFERING_MODE, mode).data(), percentage);
     1483
     1484    m_downloadFinished = percentage == 100;
     1485    m_buffering = !m_downloadFinished;
     1486
     1487    switch (mode) {
     1488    case GST_BUFFERING_STREAM: {
     1489        updateMaxTimeLoaded(percentage);
     1490
     1491        m_bufferingPercentage = percentage;
     1492        if (m_downloadFinished)
     1493            updateStates();
     1494
     1495        break;
     1496    }
     1497    case GST_BUFFERING_DOWNLOAD: {
     1498        updateMaxTimeLoaded(percentage);
     1499
     1500        // Media is now fully loaded. It will play even if network connection is
     1501        // cut. Buffering is done, remove the fill source from the main loop.
     1502        if (m_downloadFinished)
     1503            m_fillTimer.stop();
     1504
    14591505        updateStates();
     1506        break;
     1507    }
     1508    default:
     1509        GST_DEBUG_OBJECT(pipeline(), "Unhandled buffering mode: %s", enumToString(GST_TYPE_BUFFERING_MODE, mode).data());
     1510        break;
     1511    }
    14601512}
    14611513
     
    15861638    GRefPtr<GstQuery> query = adoptGRef(gst_query_new_buffering(GST_FORMAT_PERCENT));
    15871639    double fillStatus = 100.0;
    1588 
    1589     if (gst_element_query(m_pipeline.get(), query.get())) {
    1590         int64_t stop;
    1591         GstFormat format;
    1592         gst_query_parse_buffering_range(query.get(), &format, nullptr, &stop, nullptr);
    1593         ASSERT(format == GST_FORMAT_PERCENT);
    1594 
    1595         if (stop != -1)
    1596             fillStatus = 100.0 * stop / GST_FORMAT_PERCENT_MAX;
     1640    GstBufferingMode mode = GST_BUFFERING_DOWNLOAD;
     1641
     1642    if (gst_element_query(m_source.get(), query.get())) {
     1643        gst_query_parse_buffering_stats(query.get(), &mode, nullptr, nullptr, nullptr);
     1644
     1645        int percentage;
     1646        gst_query_parse_buffering_percent(query.get(), nullptr, &percentage);
     1647        fillStatus = percentage;
    15971648    } else if (m_httpResponseTotalSize) {
    15981649        GST_DEBUG_OBJECT(pipeline(), "[Buffering] Query failed, falling back to network read position estimation");
    1599         fillStatus = 100.0 * (m_networkReadPosition / m_httpResponseTotalSize);
     1650        fillStatus = 100.0 * (static_cast<double>(m_networkReadPosition) / static_cast<double>(m_httpResponseTotalSize));
    16001651    } else {
    16011652        GST_DEBUG_OBJECT(pipeline(), "[Buffering] Unable to determine on-disk buffering status");
     
    16031654    }
    16041655
    1605     GST_DEBUG_OBJECT(pipeline(), "[Buffering] Download buffer filled up to %f%%", fillStatus);
    1606 
    1607     MediaTime mediaDuration = durationMediaTime();
    1608 
    1609     // Update maxTimeLoaded only if the media duration is
    1610     // available. Otherwise we can't compute it.
    1611     if (mediaDuration) {
    1612         if (fillStatus == 100.0)
    1613             m_maxTimeLoaded = mediaDuration;
    1614         else
    1615             m_maxTimeLoaded = MediaTime(fillStatus * static_cast<double>(toGstUnsigned64Time(mediaDuration)) / 100, GST_SECOND);
    1616         GST_DEBUG_OBJECT(pipeline(), "[Buffering] Updated maxTimeLoaded: %s", toString(m_maxTimeLoaded).utf8().data());
    1617     }
    1618 
    1619     m_downloadFinished = fillStatus == 100.0;
    1620     if (!m_downloadFinished) {
    1621         updateStates();
    1622         return;
    1623     }
    1624 
    1625     // Media is now fully loaded. It will play even if network
    1626     // connection is cut. Buffering is done, remove the fill source
    1627     // from the main loop.
    1628     m_fillTimer.stop();
    1629     updateStates();
     1656    updateBufferingStatus(mode, fillStatus);
    16301657}
    16311658
     
    16561683    if (m_isEndReached)
    16571684        loaded = durationMediaTime();
    1658     GST_LOG("maxTimeLoaded: %s", toString(loaded).utf8().data());
     1685    GST_LOG_OBJECT(pipeline(), "maxTimeLoaded: %s", toString(loaded).utf8().data());
    16591686    return loaded;
    16601687}
     
    16671694    if (WEBKIT_IS_WEB_SRC(m_source.get())) {
    16681695        GST_LOG_OBJECT(pipeline(), "Last network read position: %" G_GUINT64_FORMAT ", current: %" G_GUINT64_FORMAT, m_readPositionAtLastDidLoadingProgress, m_networkReadPosition);
    1669         bool didLoadingProgress = m_readPositionAtLastDidLoadingProgress != m_networkReadPosition;
     1696        bool didLoadingProgress = m_readPositionAtLastDidLoadingProgress < m_networkReadPosition;
    16701697        m_readPositionAtLastDidLoadingProgress = m_networkReadPosition;
     1698        GST_LOG_OBJECT(pipeline(), "didLoadingProgress: %s", boolForPrinting(didLoadingProgress));
    16711699        return didLoadingProgress;
    16721700    }
     
    20022030        // Live pipelines go in PAUSED without prerolling.
    20032031        m_isStreaming = true;
    2004         setDownloadBuffering();
     2032        updateDownloadBufferingFlag();
    20052033
    20062034        if (m_currentState == GST_STATE_READY)
     
    22572285}
    22582286
    2259 void MediaPlayerPrivateGStreamer::setDownloadBuffering()
     2287void MediaPlayerPrivateGStreamer::updateDownloadBufferingFlag()
    22602288{
    22612289    if (!m_pipeline)
     
    22922320
    22932321    m_preload = preload;
    2294     setDownloadBuffering();
     2322    updateDownloadBufferingFlag();
    22952323
    22962324    if (m_delayingLoad && m_preload != MediaPlayer::None) {
  • trunk/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.h

    r246677 r247010  
    155155    void mediaLocationChanged(GstMessage*);
    156156
    157     virtual void setDownloadBuffering();
     157    virtual void updateDownloadBufferingFlag();
    158158    void processBufferingStats(GstMessage*);
     159    void updateBufferingStatus(GstBufferingMode, double percentage);
     160    void updateMaxTimeLoaded(double percentage);
     161
    159162#if ENABLE(VIDEO_TRACK)
    160163#if USE(GSTREAMER_MPEGTS)
  • trunk/Source/WebCore/platform/graphics/gstreamer/WebKitWebSourceGStreamer.cpp

    r246399 r247010  
    238238    WebKitWebSrcPrivate* priv = WEBKIT_WEB_SRC_GET_PRIVATE(src);
    239239
     240    GST_DEBUG_OBJECT(src, "Resetting internal state");
    240241    priv->haveSize = false;
    241242    priv->wereHeadersReceived = false;
  • trunk/Source/WebCore/platform/graphics/gstreamer/mse/MediaPlayerPrivateGStreamerMSE.h

    r242034 r247010  
    5353    void load(const String&, MediaSourcePrivateClient*) override;
    5454
    55     void setDownloadBuffering() override { };
     55    void updateDownloadBufferingFlag() override { };
    5656
    5757    bool isLiveStream() const override { return false; }
Note: See TracChangeset for help on using the changeset viewer.