Title: [237271] trunk
Revision
237271
Author
jer.no...@apple.com
Date
2018-10-18 15:48:29 -0700 (Thu, 18 Oct 2018)

Log Message

Safari is not able to adapt between H264 streams with EditList and without EditList
https://bugs.webkit.org/show_bug.cgi?id=190638
<rdar://problem/45342208>

Reviewed by Eric Carlson.

Source/WebCore:

Test: media/media-source/media-source-append-overlapping-dts.html

The MSE frame replacement algorithm does not take decode timestamps into account; this can
lead to situations where the replacement algorithm may leave in place frames where the
presentationTimestamp is less than the replacement frame, but whose decodeTimestamp is
after the replacement frame. When re-enqueuing these frames, they may cause a decode error
if they break the group-of-pictures sequence of the replaced range.

* Modules/mediasource/SampleMap.cpp:
(WebCore::DecodeOrderSampleMap::findSamplesBetweenDecodeKeys):
* Modules/mediasource/SampleMap.h:
* Modules/mediasource/SourceBuffer.cpp:
(WebCore::SourceBuffer::sourceBufferPrivateDidReceiveSample):

LayoutTests:

* media/media-source/media-source-append-overlapping-dts-expected.txt: Added.
* media/media-source/media-source-append-overlapping-dts.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (237270 => 237271)


--- trunk/LayoutTests/ChangeLog	2018-10-18 22:32:13 UTC (rev 237270)
+++ trunk/LayoutTests/ChangeLog	2018-10-18 22:48:29 UTC (rev 237271)
@@ -1,3 +1,14 @@
+2018-10-18  Jer Noble  <jer.no...@apple.com>
+
+        Safari is not able to adapt between H264 streams with EditList and without EditList
+        https://bugs.webkit.org/show_bug.cgi?id=190638
+        <rdar://problem/45342208>
+
+        Reviewed by Eric Carlson.
+
+        * media/media-source/media-source-append-overlapping-dts-expected.txt: Added.
+        * media/media-source/media-source-append-overlapping-dts.html: Added.
+
 2018-10-18  Per Arne Vollan  <pvol...@apple.com>
 
         [WebVTT] Region parameter and value should be separated by ':'

Added: trunk/LayoutTests/media/media-source/media-source-append-overlapping-dts-expected.txt (0 => 237271)


--- trunk/LayoutTests/media/media-source/media-source-append-overlapping-dts-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/media/media-source/media-source-append-overlapping-dts-expected.txt	2018-10-18 22:48:29 UTC (rev 237271)
@@ -0,0 +1,23 @@
+This tests that an overlapping append of samples with reordered presentation timestamps will correctly remove previously appended non-reordered samples.
+
+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 == '9') 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(0), generation(0)}
+{PTS({2000/1000 = 2.000000}), DTS({2000/1000 = 2.000000}), duration({1000/1000 = 1.000000}), flags(0), generation(0)}
+{PTS({3000/1000 = 3.000000}), DTS({3000/1000 = 3.000000}), duration({1000/1000 = 1.000000}), flags(0), generation(0)}
+{PTS({4000/1000 = 4.000000}), DTS({4000/1000 = 4.000000}), duration({1000/1000 = 1.000000}), flags(1), generation(0)}
+{PTS({6000/1000 = 6.000000}), DTS({4000/1000 = 4.000000}), duration({1000/1000 = 1.000000}), flags(1), generation(1)}
+{PTS({7000/1000 = 7.000000}), DTS({5000/1000 = 5.000000}), duration({1000/1000 = 1.000000}), flags(0), generation(1)}
+{PTS({4000/1000 = 4.000000}), DTS({6000/1000 = 6.000000}), duration({1000/1000 = 1.000000}), flags(0), generation(1)}
+{PTS({5000/1000 = 5.000000}), DTS({7000/1000 = 7.000000}), duration({1000/1000 = 1.000000}), flags(0), generation(1)}
+END OF TEST
+

Added: trunk/LayoutTests/media/media-source/media-source-append-overlapping-dts.html (0 => 237271)


--- trunk/LayoutTests/media/media-source/media-source-append-overlapping-dts.html	                        (rev 0)
+++ trunk/LayoutTests/media/media-source/media-source-append-overlapping-dts.html	2018-10-18 22:48:29 UTC (rev 237271)
@@ -0,0 +1,63 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <title>media-source-append-overlapping-dts</title>
+    <script src=""
+    <script src=""
+    <script>
+    var source;
+    var sourceBuffer;
+    var initSegment;
+
+    if (window.internals)
+        internals.initializeMockMediaSource();
+
+    window.addEventListener('load', async event => {
+
+        findMediaElement();
+
+        source = new MediaSource();
+        run('video.src = ""
+        await waitFor(source, 'sourceopen');
+
+        run('sourceBuffer = source.addSourceBuffer("video/mock; codecs=mock")');
+        initSegment = makeAInit(8, [makeATrack(1, 'mock', TRACK_KIND.VIDEO)]);
+        run('sourceBuffer.appendBuffer(initSegment)');
+
+        await waitFor(sourceBuffer, 'updateend');
+
+        samples = concatenateSamples([
+            makeASample(0, 0, 1, 1, SAMPLE_FLAG.SYNC, 0),
+            makeASample(1, 1, 1, 1, SAMPLE_FLAG.NONE, 0),
+            makeASample(2, 2, 1, 1, SAMPLE_FLAG.NONE, 0),
+            makeASample(3, 3, 1, 1, SAMPLE_FLAG.NONE, 0),
+            makeASample(4, 4, 1, 1, SAMPLE_FLAG.SYNC, 0),
+            makeASample(5, 5, 1, 1, SAMPLE_FLAG.NONE, 0),
+            makeASample(6, 6, 1, 1, SAMPLE_FLAG.NONE, 0),
+            makeASample(7, 7, 1, 1, SAMPLE_FLAG.NONE, 0),
+        ]);
+        run('sourceBuffer.appendBuffer(samples)');
+        await waitFor(sourceBuffer, 'updateend');
+
+        samples = concatenateSamples([
+            makeASample(6, 4, 1, 1, SAMPLE_FLAG.SYNC, 1),
+            makeASample(7, 5, 1, 1, SAMPLE_FLAG.NONE, 1),
+            makeASample(4, 6, 1, 1, SAMPLE_FLAG.NONE, 1),
+            makeASample(5, 7, 1, 1, SAMPLE_FLAG.NONE, 1),
+        ]);
+        run('sourceBuffer.appendBuffer(samples)');
+        await waitFor(sourceBuffer, 'updateend');
+
+        bufferedSamples = internals.bufferedSamplesForTrackID(sourceBuffer, 1);
+        testExpected("bufferedSamples.length", 9);
+        bufferedSamples.forEach(consoleWrite);
+        endTest();
+
+    }, {once: true});
+    </script>
+</head>
+<body>
+    <div>This tests that an overlapping append of samples with reordered presentation timestamps will correctly remove previously appended non-reordered samples.</div>
+    <video></video>
+</body>
+</html>

Modified: trunk/Source/WebCore/ChangeLog (237270 => 237271)


--- trunk/Source/WebCore/ChangeLog	2018-10-18 22:32:13 UTC (rev 237270)
+++ trunk/Source/WebCore/ChangeLog	2018-10-18 22:48:29 UTC (rev 237271)
@@ -1,3 +1,25 @@
+2018-10-18  Jer Noble  <jer.no...@apple.com>
+
+        Safari is not able to adapt between H264 streams with EditList and without EditList
+        https://bugs.webkit.org/show_bug.cgi?id=190638
+        <rdar://problem/45342208>
+
+        Reviewed by Eric Carlson.
+
+        Test: media/media-source/media-source-append-overlapping-dts.html
+
+        The MSE frame replacement algorithm does not take decode timestamps into account; this can
+        lead to situations where the replacement algorithm may leave in place frames where the 
+        presentationTimestamp is less than the replacement frame, but whose decodeTimestamp is
+        after the replacement frame. When re-enqueuing these frames, they may cause a decode error
+        if they break the group-of-pictures sequence of the replaced range.
+
+        * Modules/mediasource/SampleMap.cpp:
+        (WebCore::DecodeOrderSampleMap::findSamplesBetweenDecodeKeys):
+        * Modules/mediasource/SampleMap.h:
+        * Modules/mediasource/SourceBuffer.cpp:
+        (WebCore::SourceBuffer::sourceBufferPrivateDidReceiveSample):
+
 2018-10-18  Per Arne Vollan  <pvol...@apple.com>
 
         [WebVTT] Region parameter and value should be separated by ':'

Modified: trunk/Source/WebCore/Modules/mediasource/SampleMap.cpp (237270 => 237271)


--- trunk/Source/WebCore/Modules/mediasource/SampleMap.cpp	2018-10-18 22:32:13 UTC (rev 237270)
+++ trunk/Source/WebCore/Modules/mediasource/SampleMap.cpp	2018-10-18 22:48:29 UTC (rev 237271)
@@ -307,4 +307,18 @@
     return reverse_iterator_range(currentDecodeIter, nextSyncSample);
 }
 
+DecodeOrderSampleMap::iterator_range DecodeOrderSampleMap::findSamplesBetweenDecodeKeys(const KeyType& beginKey, const KeyType& endKey)
+{
+    if (beginKey > endKey)
+        return { end(), end() };
+
+    // beginKey is inclusive, so use lower_bound to include samples wich start exactly at beginKey.
+    // endKey is not inclusive, so use lower_bound to exclude samples which start exactly at endKey.
+    auto lower_bound = m_samples.lower_bound(beginKey);
+    auto upper_bound = m_samples.lower_bound(endKey);
+    if (lower_bound == upper_bound)
+        return { end(), end() };
+    return { lower_bound, upper_bound };
 }
+
+}

Modified: trunk/Source/WebCore/Modules/mediasource/SampleMap.h (237270 => 237271)


--- trunk/Source/WebCore/Modules/mediasource/SampleMap.h	2018-10-18 22:32:13 UTC (rev 237270)
+++ trunk/Source/WebCore/Modules/mediasource/SampleMap.h	2018-10-18 22:48:29 UTC (rev 237271)
@@ -79,6 +79,7 @@
     typedef MapType::const_iterator const_iterator;
     typedef MapType::reverse_iterator reverse_iterator;
     typedef MapType::const_reverse_iterator const_reverse_iterator;
+    typedef std::pair<iterator, iterator> iterator_range;
     typedef std::pair<reverse_iterator, reverse_iterator> reverse_iterator_range;
     typedef MapType::value_type value_type;
 
@@ -98,6 +99,7 @@
     WEBCORE_EXPORT iterator findSyncSampleAfterPresentationTime(const MediaTime&, const MediaTime& threshold = MediaTime::positiveInfiniteTime());
     WEBCORE_EXPORT iterator findSyncSampleAfterDecodeIterator(iterator);
     WEBCORE_EXPORT reverse_iterator_range findDependentSamples(MediaSample*);
+    WEBCORE_EXPORT iterator_range findSamplesBetweenDecodeKeys(const KeyType&, const KeyType&);
 
 private:
     MapType m_samples;

Modified: trunk/Source/WebCore/Modules/mediasource/SourceBuffer.cpp (237270 => 237271)


--- trunk/Source/WebCore/Modules/mediasource/SourceBuffer.cpp	2018-10-18 22:32:13 UTC (rev 237270)
+++ trunk/Source/WebCore/Modules/mediasource/SourceBuffer.cpp	2018-10-18 22:48:29 UTC (rev 237271)
@@ -1648,6 +1648,14 @@
             auto nextSyncIter = trackBuffer.samples.decodeOrder().findSyncSampleAfterDecodeIterator(lastDecodeIter);
             dependentSamples.insert(firstDecodeIter, nextSyncIter);
 
+            // NOTE: in the case of b-frames, the previous step may leave in place samples whose presentation
+            // timestamp < presentationTime, but whose decode timestamp >= decodeTime. These will eventually cause
+            // a decode error if left in place, so remove these samples as well.
+            DecodeOrderSampleMap::KeyType decodeKey(sample.decodeTime(), sample.presentationTime());
+            auto samplesWithHigherDecodeTimes = trackBuffer.samples.decodeOrder().findSamplesBetweenDecodeKeys(decodeKey, erasedSamples.decodeOrder().begin()->first);
+            if (samplesWithHigherDecodeTimes.first != samplesWithHigherDecodeTimes.second)
+                dependentSamples.insert(samplesWithHigherDecodeTimes.first, samplesWithHigherDecodeTimes.second);
+
             PlatformTimeRanges erasedRanges = removeSamplesFromTrackBuffer(dependentSamples, trackBuffer, this, "sourceBufferPrivateDidReceiveSample");
 
             // Only force the TrackBuffer to re-enqueue if the removed ranges overlap with enqueued and possibly
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to