Changeset 260506 in webkit


Ignore:
Timestamp:
Apr 22, 2020 4:36:27 AM (4 years ago)
Author:
eocanha@igalia.com
Message:

[GStreamer][MSE] Youtube 'live stream'/H264 URLs fail to play, VP8/9 URLs play OK
https://bugs.webkit.org/show_bug.cgi?id=209119

Reviewed by Xabier Rodriguez-Calvar.

Source/WebCore:

The fix consists of removing the initial avoiding of seeking and just
issuing the proper segment instead of seeking (seeks in GStreamer can't
be done before prerolling anyway). Appsrc doesn't make easy to emit our
own custom segment, so what I did was to use a segment fixer probe to
modify the original [0, infinity] segment issued by appsrc and use
a [startTime, stopTime] with proper values depending on the seek target
and rate.

Covered by existing tests.

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

(WebCore::checkShouldDelaySeek): Don't hold seeks on startup, when changing from READY to PAUSED.
(WebCore::MediaPlayerPrivateGStreamerMSE::doSeek): Refactored seek delay condition. Also, don't do a regular
gst_element_seek() for initial seeks, just proceed with a special case in that situation.

  • platform/graphics/gstreamer/mse/WebKitMediaSourceGStreamer.cpp:

(initialSeekSegmentFixerProbe): Probe that fixes the segment.
(webKitMediaSrcPrepareInitialSeek): Behave much like a regular seek, but also compute the right GstSegment, install
the segment fixer probe and setReadyForMoreSamples() on the SourceBufferPrivates.

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

LayoutTests:

Unskipped media/media-source/media-source-seek-redundant-append.html,
which passes now.

  • platform/gtk/TestExpectations:
  • platform/wpe/TestExpectations:
Location:
trunk
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r260505 r260506  
     12020-04-22  Enrique Ocaña González  <eocanha@igalia.com>
     2
     3        [GStreamer][MSE] Youtube 'live stream'/H264 URLs fail to play, VP8/9 URLs play OK
     4        https://bugs.webkit.org/show_bug.cgi?id=209119
     5
     6        Reviewed by Xabier Rodriguez-Calvar.
     7
     8        Unskipped media/media-source/media-source-seek-redundant-append.html,
     9        which passes now.
     10
     11        * platform/gtk/TestExpectations:
     12        * platform/wpe/TestExpectations:
     13
    1142020-04-21  Sergio Villar Senin  <svillar@igalia.com>
    215
  • trunk/LayoutTests/platform/gtk/TestExpectations

    r260503 r260506  
    33263326webkit.org/b/202736 [ Release ] http/wpt/cache-storage/quota-third-party.https.html [ Failure Timeout Pass ]
    33273327
    3328 webkit.org/b/206873 media/media-source/media-source-seek-redundant-append.html [ Timeout ]
    3329 
    33303328webkit.org/b/206876 http/tests/security/storage-blocking-strengthened-private-browsing-plugin.html [ Timeout ]
    33313329
  • trunk/LayoutTests/platform/wpe/TestExpectations

    r260505 r260506  
    15001500webkit.org/b/201268 accessibility/insert-newline.html [ Timeout ]
    15011501
    1502 webkit.org/b/206873 media/media-source/media-source-seek-redundant-append.html [ Timeout ]
    1503 
    15041502webkit.org/b/207711 [ Debug ] fast/selectors/slow-style-sharing-with-long-cousin-list.html [ Timeout ]
    15051503webkit.org/b/207711 http/tests/cookies/double-quoted-value-with-semi-colon.html [ Failure Timeout ]
  • trunk/Source/WebCore/ChangeLog

    r260505 r260506  
     12020-04-22  Enrique Ocaña González  <eocanha@igalia.com>
     2
     3        [GStreamer][MSE] Youtube 'live stream'/H264 URLs fail to play, VP8/9 URLs play OK
     4        https://bugs.webkit.org/show_bug.cgi?id=209119
     5
     6        Reviewed by Xabier Rodriguez-Calvar.
     7
     8        The fix consists of removing the initial avoiding of seeking and just
     9        issuing the proper segment instead of seeking (seeks in GStreamer can't
     10        be done before prerolling anyway). Appsrc doesn't make easy to emit our
     11        own custom segment, so what I did was to use a segment fixer probe to
     12        modify the original [0, infinity] segment issued by appsrc and use
     13        a [startTime, stopTime] with proper values depending on the seek target
     14        and rate.
     15
     16        Covered by existing tests.
     17
     18        * platform/graphics/gstreamer/mse/MediaPlayerPrivateGStreamerMSE.cpp:
     19        (WebCore::checkShouldDelaySeek): Don't hold seeks on startup, when changing from READY to PAUSED.
     20        (WebCore::MediaPlayerPrivateGStreamerMSE::doSeek): Refactored seek delay condition. Also, don't do a regular
     21        gst_element_seek() for initial seeks, just proceed with a special case in that situation.
     22        * platform/graphics/gstreamer/mse/WebKitMediaSourceGStreamer.cpp:
     23        (initialSeekSegmentFixerProbe): Probe that fixes the segment.
     24        (webKitMediaSrcPrepareInitialSeek): Behave much like a regular seek, but also compute the right GstSegment, install
     25        the segment fixer probe and setReadyForMoreSamples() on the SourceBufferPrivates.
     26        * platform/graphics/gstreamer/mse/WebKitMediaSourceGStreamer.h:
     27
    1282020-04-21  Sergio Villar Senin  <svillar@igalia.com>
    229
  • trunk/Source/WebCore/platform/graphics/gstreamer/mse/MediaPlayerPrivateGStreamerMSE.cpp

    r258542 r260506  
    242242}
    243243
     244static bool checkShouldDelaySeek(GstStateChangeReturn getStateResult, GstState currentState, GstState newState)
     245{
     246    if (getStateResult != GST_STATE_CHANGE_ASYNC)
     247        return false;
     248    if (GST_STATE_TRANSITION(currentState, newState) == GST_STATE_CHANGE_PLAYING_TO_PAUSED)
     249        return false;
     250    if (currentState == GST_STATE_READY && newState >= GST_STATE_PAUSED)
     251        return false;
     252    return true;
     253}
     254
    244255bool MediaPlayerPrivateGStreamerMSE::doSeek(const MediaTime& position, float rate, GstSeekFlags seekType)
    245256{
     
    260271        return false;
    261272    }
    262     if ((getStateResult == GST_STATE_CHANGE_ASYNC
    263         && !(state == GST_STATE_PLAYING && newState == GST_STATE_PAUSED))
    264         || state < GST_STATE_PAUSED
    265         || m_isEndReached
    266         || !m_gstSeekCompleted) {
     273
     274    bool shouldDelaySeek = checkShouldDelaySeek(getStateResult, state, newState);
     275    if (shouldDelaySeek || m_isEndReached || !m_gstSeekCompleted) {
    267276        CString reason = "Unknown reason";
    268         if (getStateResult == GST_STATE_CHANGE_ASYNC) {
     277        if (shouldDelaySeek) {
    269278            reason = makeString("In async change ",
    270279                gst_element_state_get_name(state), " --> ",
     
    348357    GST_DEBUG_OBJECT(pipeline(), "Actual seek to %s, end time:  %s, rate: %f", toString(startTime).utf8().data(), toString(endTime).utf8().data(), rate);
    349358
    350     // This will call notifySeekNeedsData() after some time to tell that the pipeline is ready for sample enqueuing.
    351     webKitMediaSrcPrepareSeek(WEBKIT_MEDIA_SRC(m_source.get()), seekTime);
    352 
    353359    m_gstSeekCompleted = false;
    354     if (!gst_element_seek(m_pipeline.get(), rate, GST_FORMAT_TIME, seekType, GST_SEEK_TYPE_SET, toGstClockTime(startTime), GST_SEEK_TYPE_SET, toGstClockTime(endTime))) {
    355         webKitMediaSrcSetReadyForSamples(WEBKIT_MEDIA_SRC(m_source.get()), true);
    356         m_isSeeking = false;
    357         m_gstSeekCompleted = true;
    358         GST_DEBUG_OBJECT(pipeline(), "doSeek(): gst_element_seek() failed, returning false");
    359         return false;
    360     }
    361 
    362     // The samples will be enqueued in notifySeekNeedsData().
    363     GST_DEBUG_OBJECT(pipeline(), "doSeek(): gst_element_seek() succeeded, returning true");
     360    if (state < GST_STATE_PAUSED) {
     361        // Special case of initial seek. We set the right segment instead of a seek.
     362        webKitMediaSrcPrepareInitialSeek(WEBKIT_MEDIA_SRC(m_source.get()), rate, startTime, endTime);
     363        notifySeekNeedsDataForTime(seekTime);
     364        GST_DEBUG("Initial seek succeeded, returning true");
     365    } else {
     366        // This will call notifySeekNeedsData() after some time to tell that the pipeline is ready for sample enqueuing.
     367        webKitMediaSrcPrepareSeek(WEBKIT_MEDIA_SRC(m_source.get()), seekTime);
     368
     369        if (!gst_element_seek(m_pipeline.get(), rate, GST_FORMAT_TIME, seekType, GST_SEEK_TYPE_SET, toGstClockTime(startTime), GST_SEEK_TYPE_SET, toGstClockTime(endTime))) {
     370            webKitMediaSrcSetReadyForSamples(WEBKIT_MEDIA_SRC(m_source.get()), true);
     371            m_isSeeking = false;
     372            m_gstSeekCompleted = true;
     373            GST_DEBUG("gst_element_seek() failed, returning false");
     374            return false;
     375        }
     376        // The samples will be enqueued in notifySeekNeedsData().
     377        GST_DEBUG("gst_element_seek() succeeded, returning true");
     378    }
    364379    return true;
    365380}
  • trunk/Source/WebCore/platform/graphics/gstreamer/mse/WebKitMediaSourceGStreamer.cpp

    r251365 r260506  
    730730}
    731731
     732GstPadProbeReturn initialSeekSegmentFixerProbe(GstPad *pad, GstPadProbeInfo *info, gpointer userData)
     733{
     734    GstEvent* event = GST_PAD_PROBE_INFO_EVENT(info);
     735    if (GST_EVENT_TYPE(event) == GST_EVENT_SEGMENT) {
     736        const GstSegment* originalSegment = nullptr;
     737        const GstSegment* fixedSegment = static_cast<GstSegment*>(userData);
     738        gst_event_parse_segment(event, &originalSegment);
     739        GST_DEBUG("Segment at %s: %" GST_SEGMENT_FORMAT ", replaced by %" GST_SEGMENT_FORMAT, GST_ELEMENT_NAME(GST_PAD_PARENT(pad)), originalSegment, fixedSegment);
     740        gst_event_replace(reinterpret_cast<GstEvent**>(&info->data), gst_event_new_segment(fixedSegment));
     741        return GST_PAD_PROBE_REMOVE;
     742    }
     743    return GST_PAD_PROBE_OK;
     744}
     745
     746void webKitMediaSrcPrepareInitialSeek(WebKitMediaSrc* source, double rate, const MediaTime& startTime, const MediaTime& endTime)
     747{
     748    GST_OBJECT_LOCK(source);
     749    MediaTime seekTime = (rate >= 0) ? startTime : endTime;
     750    source->priv->seekTime = seekTime;
     751    source->priv->appsrcSeekDataCount = 0;
     752    source->priv->appsrcNeedDataCount = 0;
     753
     754    for (Stream* stream : source->priv->streams) {
     755        stream->appsrcNeedDataFlag = false;
     756        // Don't allow samples away from the seekTime to be enqueued.
     757        stream->lastEnqueuedTime = seekTime;
     758    }
     759
     760    // The pending action will be performed in enabledAppsrcSeekData().
     761    source->priv->appsrcSeekDataNextAction = MediaSourceSeekToTime;
     762
     763    GUniquePtr<GstSegment> segment(gst_segment_new());
     764    segment->format = GST_FORMAT_TIME;
     765    gst_segment_do_seek(segment.get(), rate, GST_FORMAT_TIME,
     766        static_cast<GstSeekFlags>(GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
     767        GST_SEEK_TYPE_SET, WebCore::toGstUnsigned64Time(startTime),
     768        GST_SEEK_TYPE_SET, WebCore::toGstUnsigned64Time(endTime), nullptr);
     769
     770    for (Stream* stream : source->priv->streams) {
     771        // This probe will fix the segment autogenerated by appsrc.
     772        GRefPtr<GstPad> pad = adoptGRef(gst_element_get_static_pad(stream->appsrc, "src"));
     773        gst_pad_add_probe(pad.get(), GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM,
     774            initialSeekSegmentFixerProbe, gst_segment_copy(segment.get()), reinterpret_cast<GDestroyNotify>(gst_segment_free));
     775        stream->sourceBuffer->setReadyForMoreSamples(true);
     776    }
     777
     778    GST_OBJECT_UNLOCK(source);
     779}
     780
    732781namespace WTF {
    733782template <> GRefPtr<WebKitMediaSrc> adoptGRef(WebKitMediaSrc* ptr)
  • trunk/Source/WebCore/platform/graphics/gstreamer/mse/WebKitMediaSourceGStreamer.h

    r251365 r260506  
    7474
    7575void webKitMediaSrcPrepareSeek(WebKitMediaSrc*, const MediaTime&);
     76void webKitMediaSrcPrepareInitialSeek(WebKitMediaSrc*, double rate, const MediaTime& startTime, const MediaTime& endTime);
    7677void webKitMediaSrcSetReadyForSamples(WebKitMediaSrc*, bool);
    7778
Note: See TracChangeset for help on using the changeset viewer.