Title: [225442] trunk
Revision
225442
Author
[email protected]
Date
2017-12-01 21:39:30 -0800 (Fri, 01 Dec 2017)

Log Message

[MSE] Use correct range end checks in sourceBufferPrivateDidReceiveSample()
https://bugs.webkit.org/show_bug.cgi?id=179690

Patch by Alicia Boya García <[email protected]> on 2017-12-01
Reviewed by Jer Noble.

Source/WebCore:

The Coded Frame Processing algorithm as defined in
https://www.w3.org/TR/media-source/#sourcebuffer-coded-frame-processing states:

1.14. Remove existing coded frames in track buffer:
 -> If highest end timestamp for track buffer is not set:
       [...]
 -> If highest end timestamp for track buffer is set and less than or
    equal to presentation timestamp:
       Remove all coded frames from track buffer that have a
       presentation timestamp greater than or equal to highest end
       timestamp and less than frame end timestamp.

Note the removal range is closed-open [a, b). WebKit is actually removing
frames using an open-closed range (a, b], which causes frames not to be removed
in situations where they should and frames to be removed in situations when
they should not.

Tests: media/media-source/media-source-range-end-frame-not-removed.html
       media/media-source/media-source-range-start-frame-replaced.html

* Modules/mediasource/SampleMap.cpp:
(WebCore::PresentationOrderSampleMap::findSamplesBetweenPresentationTimesFromEnd):
* Modules/mediasource/SampleMap.h:
* Modules/mediasource/SourceBuffer.cpp:
(WebCore::SourceBuffer::sourceBufferPrivateDidReceiveSample):

LayoutTests:

Added test cases for bug #179690.

* media/media-source/media-source-range-end-frame-not-removed-expected.txt: Added.
* media/media-source/media-source-range-end-frame-not-removed.html: Added.
* media/media-source/media-source-range-start-frame-replaced-expected.txt: Added.
* media/media-source/media-source-range-start-frame-replaced.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (225441 => 225442)


--- trunk/LayoutTests/ChangeLog	2017-12-02 03:19:16 UTC (rev 225441)
+++ trunk/LayoutTests/ChangeLog	2017-12-02 05:39:30 UTC (rev 225442)
@@ -1,3 +1,17 @@
+2017-12-01  Alicia Boya García  <[email protected]>
+
+        [MSE] Use correct range end checks in sourceBufferPrivateDidReceiveSample()
+        https://bugs.webkit.org/show_bug.cgi?id=179690
+
+        Reviewed by Jer Noble.
+
+        Added test cases for bug #179690.
+
+        * media/media-source/media-source-range-end-frame-not-removed-expected.txt: Added.
+        * media/media-source/media-source-range-end-frame-not-removed.html: Added.
+        * media/media-source/media-source-range-start-frame-replaced-expected.txt: Added.
+        * media/media-source/media-source-range-start-frame-replaced.html: Added.
+
 2017-12-01  Ms2ger  <[email protected]>
 
         [WPE] Enable wpt css tests.

Added: trunk/LayoutTests/media/media-source/media-source-range-end-frame-not-removed-expected.txt (0 => 225442)


--- trunk/LayoutTests/media/media-source/media-source-range-end-frame-not-removed-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/media/media-source/media-source-range-end-frame-not-removed-expected.txt	2017-12-02 05:39:30 UTC (rev 225442)
@@ -0,0 +1,22 @@
+
+RUN(video.src = ""
+EVENT(sourceopen)
+RUN(sourceBuffer = source.addSourceBuffer("video/mock; codecs=mock"))
+RUN(sourceBuffer.appendBuffer(initSegment))
+EVENT(updateend)
+RUN(sourceBuffer.appendBuffer(samples))
+EVENT(updateend)
+RUN(sourceBuffer.appendBuffer(samples))
+EVENT(updateend)
+EXPECTED (bufferedSamples.length == '6') OK
+{PTS({0/1000 = 0.000000}), DTS({0/1000 = 0.000000}), duration({1000/1000 = 1.000000}), flags(1), generation(0)}
+{PTS({1000/1000 = 1.000000}), DTS({1000/1000 = 1.000000}), duration({1000/1000 = 1.000000}), flags(1), generation(0)}
+{PTS({2000/1000 = 2.000000}), DTS({2000/1000 = 2.000000}), duration({1000/1000 = 1.000000}), flags(1), generation(0)}
+{PTS({3000/1000 = 3.000000}), DTS({3000/1000 = 3.000000}), duration({1000/1000 = 1.000000}), flags(1), generation(0)}
+{PTS({4000/1000 = 4.000000}), DTS({4000/1000 = 4.000000}), duration({1000/1000 = 1.000000}), flags(1), generation(0)}
+{PTS({5000/1000 = 5.000000}), DTS({5000/1000 = 5.000000}), duration({1000/1000 = 1.000000}), flags(1), generation(0)}
+EXPECTED (sourceBuffer.buffered.length == '1') OK
+EXPECTED (sourceBuffer.buffered.start(0) == '0') OK
+EXPECTED (sourceBuffer.buffered.end(0) == '6') OK
+END OF TEST
+

Added: trunk/LayoutTests/media/media-source/media-source-range-end-frame-not-removed.html (0 => 225442)


--- trunk/LayoutTests/media/media-source/media-source-range-end-frame-not-removed.html	                        (rev 0)
+++ trunk/LayoutTests/media/media-source/media-source-range-end-frame-not-removed.html	2017-12-02 05:39:30 UTC (rev 225442)
@@ -0,0 +1,72 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <title>media-source-range-ends</title>
+    <script src=""
+    <script src=""
+    <script>
+    var source;
+    var sourceBuffer;
+    var initSegment;
+    var samples;
+    var bufferedSamples;
+
+    if (window.internals)
+        internals.initializeMockMediaSource();
+
+    function runTest()
+    {
+        findMediaElement();
+
+        source = new MediaSource();
+        waitForEventOn(source, 'sourceopen', sourceOpen);
+        run('video.src = ""
+    }
+
+    function sourceOpen()
+    {
+        run('sourceBuffer = source.addSourceBuffer("video/mock; codecs=mock")');
+        waitForEventOn(sourceBuffer, 'updateend', loadSamples1, false, true);
+        initSegment = makeAInit(6, [makeATrack(1, 'mock', TRACK_KIND.VIDEO)]);
+        run('sourceBuffer.appendBuffer(initSegment)');
+    }
+
+    function loadSamples1()
+    {
+        samples = concatenateSamples([
+            makeASample(3, 3, 1, 1, SAMPLE_FLAG.SYNC, 0),
+            makeASample(4, 4, 1, 1, SAMPLE_FLAG.SYNC, 0),
+            makeASample(5, 5, 1, 1, SAMPLE_FLAG.SYNC, 0),
+        ]);
+        waitForEventOn(sourceBuffer, 'updateend', loadSamples2, false, true);
+        run('sourceBuffer.appendBuffer(samples)');
+    }
+
+    function loadSamples2()
+    {
+        samples = concatenateSamples([
+            makeASample(0, 0, 1, 1, SAMPLE_FLAG.SYNC, 0),
+            makeASample(1, 1, 1, 1, SAMPLE_FLAG.SYNC, 0),
+            makeASample(2, 2, 1, 1, SAMPLE_FLAG.SYNC, 0),
+        ]);
+        waitForEventOn(sourceBuffer, 'updateend', samplesAdded, false, true);
+        run('sourceBuffer.appendBuffer(samples)');
+    }
+
+    function samplesAdded()
+    {
+        bufferedSamples = internals.bufferedSamplesForTrackID(sourceBuffer, 1);
+        testExpected("bufferedSamples.length", 6);
+        bufferedSamples.forEach(consoleWrite);
+
+        testExpected("sourceBuffer.buffered.length", 1);
+        testExpected("sourceBuffer.buffered.start(0)", 0);
+        testExpected("sourceBuffer.buffered.end(0)", 6);
+
+        endTest();
+    }
+    </script>
+</head>
+<body _onload_="runTest()">
+    <video></video>
+</body>

Added: trunk/LayoutTests/media/media-source/media-source-range-start-frame-replaced-expected.txt (0 => 225442)


--- trunk/LayoutTests/media/media-source/media-source-range-start-frame-replaced-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/media/media-source/media-source-range-start-frame-replaced-expected.txt	2017-12-02 05:39:30 UTC (rev 225442)
@@ -0,0 +1,17 @@
+
+RUN(video.src = ""
+EVENT(sourceopen)
+RUN(sourceBuffer = source.addSourceBuffer("video/mock; codecs=mock"))
+RUN(sourceBuffer.appendBuffer(initSegment))
+EVENT(updateend)
+RUN(sourceBuffer.appendBuffer(samples))
+EVENT(updateend)
+RUN(sourceBuffer.appendBuffer(samples))
+EVENT(updateend)
+{PTS({0/1000 = 0.000000}), DTS({0/1000 = 0.000000}), duration({1000/1000 = 1.000000}), flags(1), generation(0)}
+{PTS({1000/1000 = 1.000000}), DTS({1000/1000 = 1.000000}), duration({2000/1000 = 2.000000}), flags(1), generation(0)}
+EXPECTED (sourceBuffer.buffered.length == '1') OK
+EXPECTED (sourceBuffer.buffered.start(0) == '0') OK
+EXPECTED (sourceBuffer.buffered.end(0) == '3') OK
+END OF TEST
+

Added: trunk/LayoutTests/media/media-source/media-source-range-start-frame-replaced.html (0 => 225442)


--- trunk/LayoutTests/media/media-source/media-source-range-start-frame-replaced.html	                        (rev 0)
+++ trunk/LayoutTests/media/media-source/media-source-range-start-frame-replaced.html	2017-12-02 05:39:30 UTC (rev 225442)
@@ -0,0 +1,69 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <title>media-source-range-start-frame-replaced</title>
+    <script src=""
+    <script src=""
+    <script>
+    var source;
+    var sourceBuffer;
+    var initSegment;
+    var samples;
+    var bufferedSamples;
+
+    if (window.internals)
+        internals.initializeMockMediaSource();
+
+    function runTest()
+    {
+        findMediaElement();
+
+        source = new MediaSource();
+        waitForEventOn(source, 'sourceopen', sourceOpen);
+        run('video.src = ""
+    }
+
+    function sourceOpen()
+    {
+        run('sourceBuffer = source.addSourceBuffer("video/mock; codecs=mock")');
+        waitForEventOn(sourceBuffer, 'updateend', loadSamples1, false, true);
+        initSegment = makeAInit(3, [makeATrack(1, 'mock', TRACK_KIND.VIDEO)]);
+        run('sourceBuffer.appendBuffer(initSegment)');
+    }
+
+    function loadSamples1()
+    {
+        samples = concatenateSamples([
+            makeASample(1, 1, 1, 1, SAMPLE_FLAG.SYNC, 0),
+        ]);
+        waitForEventOn(sourceBuffer, 'updateend', loadSamples2, false, true);
+        run('sourceBuffer.appendBuffer(samples)');
+    }
+
+    function loadSamples2()
+    {
+        samples = concatenateSamples([
+            // New Coded Frame Group (DTS went backwards)
+            makeASample(0, 0, 1, 1, SAMPLE_FLAG.SYNC, 0),
+            makeASample(1, 1, 2, 1, SAMPLE_FLAG.SYNC, 0), // duration = 2
+        ]);
+        waitForEventOn(sourceBuffer, 'updateend', samplesAdded, false, true);
+        run('sourceBuffer.appendBuffer(samples)');
+    }
+
+    function samplesAdded()
+    {
+        bufferedSamples = internals.bufferedSamplesForTrackID(sourceBuffer, 1);
+        bufferedSamples.forEach(consoleWrite);
+
+        testExpected("sourceBuffer.buffered.length", 1);
+        testExpected("sourceBuffer.buffered.start(0)", 0);
+        testExpected("sourceBuffer.buffered.end(0)", 3);
+
+        endTest();
+    }
+    </script>
+</head>
+<body _onload_="runTest()">
+    <video></video>
+</body>

Modified: trunk/Source/WebCore/ChangeLog (225441 => 225442)


--- trunk/Source/WebCore/ChangeLog	2017-12-02 03:19:16 UTC (rev 225441)
+++ trunk/Source/WebCore/ChangeLog	2017-12-02 05:39:30 UTC (rev 225442)
@@ -1,3 +1,36 @@
+2017-12-01  Alicia Boya García  <[email protected]>
+
+        [MSE] Use correct range end checks in sourceBufferPrivateDidReceiveSample()
+        https://bugs.webkit.org/show_bug.cgi?id=179690
+
+        Reviewed by Jer Noble.
+
+        The Coded Frame Processing algorithm as defined in
+        https://www.w3.org/TR/media-source/#sourcebuffer-coded-frame-processing states:
+
+        1.14. Remove existing coded frames in track buffer:
+         -> If highest end timestamp for track buffer is not set:
+               [...]
+         -> If highest end timestamp for track buffer is set and less than or
+            equal to presentation timestamp:
+               Remove all coded frames from track buffer that have a
+               presentation timestamp greater than or equal to highest end
+               timestamp and less than frame end timestamp.
+
+        Note the removal range is closed-open [a, b). WebKit is actually removing
+        frames using an open-closed range (a, b], which causes frames not to be removed
+        in situations where they should and frames to be removed in situations when
+        they should not.
+
+        Tests: media/media-source/media-source-range-end-frame-not-removed.html
+               media/media-source/media-source-range-start-frame-replaced.html
+
+        * Modules/mediasource/SampleMap.cpp:
+        (WebCore::PresentationOrderSampleMap::findSamplesBetweenPresentationTimesFromEnd):
+        * Modules/mediasource/SampleMap.h:
+        * Modules/mediasource/SourceBuffer.cpp:
+        (WebCore::SourceBuffer::sourceBufferPrivateDidReceiveSample):
+
 2017-12-01  Simon Fraser  <[email protected]>
 
         Reduce the number of calls to ViewportConfiguration::updateConfiguration()

Modified: trunk/Source/WebCore/Modules/mediasource/SampleMap.cpp (225441 => 225442)


--- trunk/Source/WebCore/Modules/mediasource/SampleMap.cpp	2017-12-02 03:19:16 UTC (rev 225441)
+++ trunk/Source/WebCore/Modules/mediasource/SampleMap.cpp	2017-12-02 05:39:30 UTC (rev 225442)
@@ -284,28 +284,21 @@
     return { lower_bound, upper_bound };
 }
 
-PresentationOrderSampleMap::iterator_range PresentationOrderSampleMap::findSamplesWithinPresentationRange(const MediaTime& beginTime, const MediaTime& endTime)
+PresentationOrderSampleMap::iterator_range PresentationOrderSampleMap::findSamplesBetweenPresentationTimesFromEnd(const MediaTime& beginTime, const MediaTime& endTime)
 {
-    // startTime is not inclusive, so use upper_bound to exclude samples which start exactly at startTime.
-    // endTime is inclusive, so use upper_bound to include samples which start exactly at endTime.
-    auto lower_bound = m_samples.upper_bound(beginTime);
-    auto upper_bound = m_samples.upper_bound(endTime);
-    if (lower_bound == upper_bound)
-        return { end(), end() };
-    return { lower_bound, upper_bound };
-}
-
-PresentationOrderSampleMap::iterator_range PresentationOrderSampleMap::findSamplesWithinPresentationRangeFromEnd(const MediaTime& beginTime, const MediaTime& endTime)
-{
-    reverse_iterator rangeEnd = std::find_if(rbegin(), rend(), [&beginTime](auto& value) {
-        return value.second->presentationTime() <= beginTime;
+    reverse_iterator rangeEnd = std::find_if(rbegin(), rend(), [&endTime](auto& value) {
+        return value.first < endTime;
     });
 
-    reverse_iterator rangeStart = std::find_if(rbegin(), rangeEnd, [&endTime](auto& value) {
-        return value.second->presentationTime() <= endTime;
+    reverse_iterator rangeStart = std::find_if(rangeEnd, rend(), [&beginTime](auto& value) {
+        return value.first < beginTime;
     });
 
-    return iterator_range(rangeEnd.base(), rangeStart.base());
+    if (rangeStart == rangeEnd)
+        return { end(), end() };
+
+    // ( rangeStart, rangeEnd ] == [ rangeStart.base(), rangeEnd.base() )
+    return { rangeStart.base(), rangeEnd.base() };
 }
 
 DecodeOrderSampleMap::reverse_iterator_range DecodeOrderSampleMap::findDependentSamples(MediaSample* sample)

Modified: trunk/Source/WebCore/Modules/mediasource/SampleMap.h (225441 => 225442)


--- trunk/Source/WebCore/Modules/mediasource/SampleMap.h	2017-12-02 03:19:16 UTC (rev 225441)
+++ trunk/Source/WebCore/Modules/mediasource/SampleMap.h	2017-12-02 05:39:30 UTC (rev 225442)
@@ -63,8 +63,7 @@
     WEBCORE_EXPORT reverse_iterator reverseFindSampleContainingPresentationTime(const MediaTime&);
     WEBCORE_EXPORT reverse_iterator reverseFindSampleBeforePresentationTime(const MediaTime&);
     WEBCORE_EXPORT iterator_range findSamplesBetweenPresentationTimes(const MediaTime&, const MediaTime&);
-    WEBCORE_EXPORT iterator_range findSamplesWithinPresentationRange(const MediaTime&, const MediaTime&);
-    WEBCORE_EXPORT iterator_range findSamplesWithinPresentationRangeFromEnd(const MediaTime&, const MediaTime&);
+    WEBCORE_EXPORT iterator_range findSamplesBetweenPresentationTimesFromEnd(const MediaTime&, const MediaTime&);
 
 private:
     MapType m_samples;

Modified: trunk/Source/WebCore/Modules/mediasource/SourceBuffer.cpp (225441 => 225442)


--- trunk/Source/WebCore/Modules/mediasource/SourceBuffer.cpp	2017-12-02 03:19:16 UTC (rev 225441)
+++ trunk/Source/WebCore/Modules/mediasource/SourceBuffer.cpp	2017-12-02 05:39:30 UTC (rev 225442)
@@ -1537,9 +1537,11 @@
 
                 PresentationOrderSampleMap::iterator_range range;
                 if (highestBufferedTime - trackBuffer.highestPresentationTimestamp < trackBuffer.lastFrameDuration)
-                    range = trackBuffer.samples.presentationOrder().findSamplesWithinPresentationRangeFromEnd(trackBuffer.highestPresentationTimestamp, frameEndTimestamp);
+                    // If the new frame is at the end of the buffered ranges, perform a sequential scan from end (O(1)).
+                    range = trackBuffer.samples.presentationOrder().findSamplesBetweenPresentationTimesFromEnd(trackBuffer.highestPresentationTimestamp, frameEndTimestamp);
                 else
-                    range = trackBuffer.samples.presentationOrder().findSamplesWithinPresentationRange(trackBuffer.highestPresentationTimestamp, frameEndTimestamp);
+                    // In any other case, perform a binary search (O(log(n)).
+                    range = trackBuffer.samples.presentationOrder().findSamplesBetweenPresentationTimes(trackBuffer.highestPresentationTimestamp, frameEndTimestamp);
 
                 if (range.first != trackBuffer.samples.presentationOrder().end())
                     erasedSamples.addRange(range.first, range.second);

Modified: trunk/Tools/TestWebKitAPI/Tests/WebCore/SampleMap.cpp (225441 => 225442)


--- trunk/Tools/TestWebKitAPI/Tests/WebCore/SampleMap.cpp	2017-12-02 03:19:16 UTC (rev 225441)
+++ trunk/Tools/TestWebKitAPI/Tests/WebCore/SampleMap.cpp	2017-12-02 05:39:30 UTC (rev 225442)
@@ -202,30 +202,30 @@
     EXPECT_TRUE(presentationMap.end() == iterator_range.second);
 }
 
-TEST_F(SampleMapTest, findSamplesWithinPresentationRange)
+TEST_F(SampleMapTest, findSamplesBetweenPresentationTimesFromEnd)
 {
     auto& presentationMap = map.presentationOrder();
-    auto iterator_range = presentationMap.findSamplesWithinPresentationRange(MediaTime(0, 1), MediaTime(1, 1));
-    EXPECT_EQ(MediaTime(1, 1), iterator_range.first->second->presentationTime());
-    EXPECT_EQ(MediaTime(2, 1), iterator_range.second->second->presentationTime());
+    auto iterator_range = presentationMap.findSamplesBetweenPresentationTimesFromEnd(MediaTime(0, 1), MediaTime(1, 1));
+    EXPECT_EQ(MediaTime(0, 1), iterator_range.first->second->presentationTime());
+    EXPECT_EQ(MediaTime(1, 1), iterator_range.second->second->presentationTime());
 
-    iterator_range = presentationMap.findSamplesWithinPresentationRange(MediaTime(1, 2), MediaTime(3, 2));
+    iterator_range = presentationMap.findSamplesBetweenPresentationTimesFromEnd(MediaTime(1, 2), MediaTime(3, 2));
     EXPECT_EQ(MediaTime(1, 1), iterator_range.first->second->presentationTime());
     EXPECT_EQ(MediaTime(2, 1), iterator_range.second->second->presentationTime());
 
-    iterator_range = presentationMap.findSamplesWithinPresentationRange(MediaTime(9, 1), MediaTime(21, 1));
-    EXPECT_EQ(MediaTime(11, 1), iterator_range.first->second->presentationTime());
+    iterator_range = presentationMap.findSamplesBetweenPresentationTimesFromEnd(MediaTime(9, 1), MediaTime(21, 1));
+    EXPECT_EQ(MediaTime(9, 1), iterator_range.first->second->presentationTime());
     EXPECT_TRUE(presentationMap.end() == iterator_range.second);
 
-    iterator_range = presentationMap.findSamplesWithinPresentationRange(MediaTime(-1, 1), MediaTime(0, 1));
-    EXPECT_EQ(MediaTime(0, 1), iterator_range.first->second->presentationTime());
-    EXPECT_EQ(MediaTime(1, 1), iterator_range.second->second->presentationTime());
+    iterator_range = presentationMap.findSamplesBetweenPresentationTimesFromEnd(MediaTime(-1, 1), MediaTime(0, 1));
+    EXPECT_TRUE(presentationMap.end() == iterator_range.first);
+    EXPECT_TRUE(presentationMap.end() == iterator_range.second);
 
-    iterator_range = presentationMap.findSamplesWithinPresentationRange(MediaTime(10, 1), MediaTime(21, 2));
+    iterator_range = presentationMap.findSamplesBetweenPresentationTimesFromEnd(MediaTime(19, 2), MediaTime(10, 1));
     EXPECT_TRUE(presentationMap.end() == iterator_range.first);
     EXPECT_TRUE(presentationMap.end() == iterator_range.second);
 
-    iterator_range = presentationMap.findSamplesWithinPresentationRange(MediaTime(20, 1), MediaTime(21, 1));
+    iterator_range = presentationMap.findSamplesBetweenPresentationTimesFromEnd(MediaTime(20, 1), MediaTime(21, 1));
     EXPECT_TRUE(presentationMap.end() == iterator_range.first);
     EXPECT_TRUE(presentationMap.end() == iterator_range.second);
 }
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to