Diff
Modified: trunk/LayoutTests/ChangeLog (238085 => 238086)
--- trunk/LayoutTests/ChangeLog 2018-11-12 14:55:03 UTC (rev 238085)
+++ trunk/LayoutTests/ChangeLog 2018-11-12 15:12:35 UTC (rev 238086)
@@ -1,3 +1,13 @@
+2018-11-12 Jer Noble <jer.no...@apple.com>
+
+ [MSE] Frame re-ordering can cause iframes to never be enqueued
+ https://bugs.webkit.org/show_bug.cgi?id=191485
+
+ Reviewed by Eric Carlson.
+
+ * media/media-source/media-source-dropped-iframe-expected.txt: Added.
+ * media/media-source/media-source-dropped-iframe.html: Added.
+
2018-11-11 Wenson Hsieh <wenson_hs...@apple.com>
Implement a new edit command to change the enclosing list type
Added: trunk/LayoutTests/media/media-source/media-source-dropped-iframe-expected.txt (0 => 238086)
--- trunk/LayoutTests/media/media-source/media-source-dropped-iframe-expected.txt (rev 0)
+++ trunk/LayoutTests/media/media-source/media-source-dropped-iframe-expected.txt 2018-11-12 15:12:35 UTC (rev 238086)
@@ -0,0 +1,27 @@
+
+EXPECTED (source.readyState == 'closed') OK
+EVENT(sourceopen)
+RUN(sourceBuffer = source.addSourceBuffer("video/mock; codecs=mock"))
+RUN(sourceBuffer.appendBuffer(initSegment))
+EVENT(updateend)
+RUN(sourceBuffer.appendBuffer(samples))
+EVENT(updateend)
+RUN(sourceBuffer.timestampOffset = 3)
+RUN(sourceBuffer.appendBuffer(samples))
+EVENT(updateend)
+Buffered:
+{PTS({0/1 = 0.000000}), DTS({0/1 = 0.000000}), duration({1/1 = 1.000000}), flags(1), generation(1)}
+{PTS({1/1 = 1.000000}), DTS({1/1 = 1.000000}), duration({1/1 = 1.000000}), flags(0), generation(1)}
+{PTS({2/1 = 2.000000}), DTS({2/1 = 2.000000}), duration({1/1 = 1.000000}), flags(0), generation(1)}
+{PTS({3/1 = 3.000000}), DTS({2/1 = 2.000000}), duration({1/1 = 1.000000}), flags(1), generation(2)}
+{PTS({5/1 = 5.000000}), DTS({3/1 = 3.000000}), duration({1/1 = 1.000000}), flags(0), generation(2)}
+{PTS({4/1 = 4.000000}), DTS({4/1 = 4.000000}), duration({1/1 = 1.000000}), flags(0), generation(2)}
+Enqueued:
+{PTS({0/1 = 0.000000}), DTS({0/1 = 0.000000}), duration({1/1 = 1.000000}), flags(1), generation(1)}
+{PTS({1/1 = 1.000000}), DTS({1/1 = 1.000000}), duration({1/1 = 1.000000}), flags(0), generation(1)}
+{PTS({2/1 = 2.000000}), DTS({2/1 = 2.000000}), duration({1/1 = 1.000000}), flags(0), generation(1)}
+{PTS({3/1 = 3.000000}), DTS({2/1 = 2.000000}), duration({1/1 = 1.000000}), flags(1), generation(2)}
+{PTS({5/1 = 5.000000}), DTS({3/1 = 3.000000}), duration({1/1 = 1.000000}), flags(0), generation(2)}
+{PTS({4/1 = 4.000000}), DTS({4/1 = 4.000000}), duration({1/1 = 1.000000}), flags(0), generation(2)}
+END OF TEST
+
Added: trunk/LayoutTests/media/media-source/media-source-dropped-iframe.html (0 => 238086)
--- trunk/LayoutTests/media/media-source/media-source-dropped-iframe.html (rev 0)
+++ trunk/LayoutTests/media/media-source/media-source-dropped-iframe.html 2018-11-12 15:12:35 UTC (rev 238086)
@@ -0,0 +1,64 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>media-source-dropped-iframe</title>
+ <script src=""
+ <script src=""
+ <script>
+ var source;
+ var sourceBuffer;
+ var initSegment;
+ var samples;
+
+ if (window.internals)
+ internals.initializeMockMediaSource();
+
+ async function runTest() {
+ findMediaElement();
+
+ source = new MediaSource();
+ testExpected('source.readyState', 'closed');
+
+ video.srcObject = source;
+ 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, 1, SAMPLE_FLAG.SYNC, 1),
+ makeASample(1, 1, 1, 1, 1, SAMPLE_FLAG.NONE, 1),
+ makeASample(2, 2, 1, 1, 1, SAMPLE_FLAG.NONE, 1),
+ ]);
+ run('sourceBuffer.appendBuffer(samples)');
+ await waitFor(sourceBuffer, 'updateend');
+
+ run('sourceBuffer.timestampOffset = 3');
+ samples = concatenateSamples([
+ makeASample(0, -1, 1, 1, 1, SAMPLE_FLAG.SYNC, 2),
+ makeASample(2, 0, 1, 1, 1, SAMPLE_FLAG.NONE, 2),
+ makeASample(1, 1, 1, 1, 1, SAMPLE_FLAG.NONE, 2),
+ ]);
+ run('sourceBuffer.appendBuffer(samples)');
+ await waitFor(sourceBuffer, 'updateend');
+
+ bufferedSamples = internals.bufferedSamplesForTrackID(sourceBuffer, 1);
+ enqueuedSamples = internals.enqueuedSamplesForTrackID(sourceBuffer, 1);
+
+ consoleWrite("Buffered:");
+ bufferedSamples.forEach(consoleWrite);
+
+ consoleWrite("Enqueued:");
+ enqueuedSamples.forEach(consoleWrite);
+
+ endTest();
+ }
+
+ </script>
+</head>
+<body _onload_="runTest().catch(failTest)">
+ <video></video>
+</body>
+</html>
Modified: trunk/Source/WebCore/ChangeLog (238085 => 238086)
--- trunk/Source/WebCore/ChangeLog 2018-11-12 14:55:03 UTC (rev 238085)
+++ trunk/Source/WebCore/ChangeLog 2018-11-12 15:12:35 UTC (rev 238086)
@@ -1,3 +1,27 @@
+2018-11-12 Jer Noble <jer.no...@apple.com>
+
+ [MSE] Frame re-ordering can cause iframes to never be enqueued
+ https://bugs.webkit.org/show_bug.cgi?id=191485
+
+ Reviewed by Eric Carlson.
+
+ Test: media/media-source/media-source-dropped-iframe.html
+
+ Some frame re-ordering techniques result in files where the first frame has a
+ decode timestamp < 0, but a presentation timestamp >= 0. When appending these
+ samples to existing content, we can fail to enqueue the first frame because its
+ DTS overlaps an existing sample, but the presentation timestamp does not.
+ Rather than try to only enqueue samples whose decode timestamps are > than the
+ greatest decode end timestamp (minus some fudge factor), allow all frames to be
+ added to the decode queue if they are strictly ordered greater than the last
+ enqueued frame.
+
+ * Modules/mediasource/SourceBuffer.cpp:
+ (WebCore::SourceBuffer::TrackBuffer::TrackBuffer):
+ (WebCore::SourceBuffer::sourceBufferPrivateDidReceiveSample):
+ (WebCore::SourceBuffer::provideMediaData):
+ (WebCore::SourceBuffer::reenqueueMediaForTime):
+
2018-11-12 Yusuke Suzuki <yusukesuz...@slowstart.org>
IDBTransaction does not use "RefPtr<IDBTransaction> self"
Modified: trunk/Source/WebCore/Modules/mediasource/SourceBuffer.cpp (238085 => 238086)
--- trunk/Source/WebCore/Modules/mediasource/SourceBuffer.cpp 2018-11-12 14:55:03 UTC (rev 238085)
+++ trunk/Source/WebCore/Modules/mediasource/SourceBuffer.cpp 2018-11-12 15:12:35 UTC (rev 238086)
@@ -67,7 +67,8 @@
MediaTime lastFrameDuration;
MediaTime highestPresentationTimestamp;
MediaTime lastEnqueuedPresentationTime;
- MediaTime lastEnqueuedDecodeEndTime;
+ DecodeOrderSampleMap::KeyType lastEnqueuedDecodeKey;
+ MediaTime lastEnqueuedDecodeDuration;
MediaTime roundedTimestampOffset;
uint32_t lastFrameTimescale { 0 };
bool needRandomAccessFlag { true };
@@ -84,7 +85,8 @@
, lastFrameDuration(MediaTime::invalidTime())
, highestPresentationTimestamp(MediaTime::invalidTime())
, lastEnqueuedPresentationTime(MediaTime::invalidTime())
- , lastEnqueuedDecodeEndTime(MediaTime::invalidTime())
+ , lastEnqueuedDecodeKey({MediaTime::invalidTime(), MediaTime::invalidTime()})
+ , lastEnqueuedDecodeDuration(MediaTime::invalidTime())
{
}
};
@@ -1748,9 +1750,9 @@
// queue are "enqueued" (sent to the inner media framework) in `provideMediaData()`.
//
// In order to check whether a frame should be added to the decode queue we check whether it starts after the
- // lastEnqueuedDecodeEndTime or even a bit before that to accomodate files with imprecise timing information.
- if (trackBuffer.lastEnqueuedDecodeEndTime.isInvalid() || decodeTimestamp >= (trackBuffer.lastEnqueuedDecodeEndTime - contiguousFrameTolerance)) {
- DecodeOrderSampleMap::KeyType decodeKey(sample.decodeTime(), sample.presentationTime());
+ // lastEnqueuedDecodeKey.
+ DecodeOrderSampleMap::KeyType decodeKey(sample.decodeTime(), sample.presentationTime());
+ if (trackBuffer.lastEnqueuedDecodeKey.first.isInvalid() || decodeKey > trackBuffer.lastEnqueuedDecodeKey) {
trackBuffer.decodeQueue.insert(DecodeOrderSampleMap::MapType::value_type(decodeKey, &sample));
}
@@ -2004,7 +2006,9 @@
// new current time without triggering this early return.
// FIXME(135867): Make this gap detection logic less arbitrary.
MediaTime oneSecond(1, 1);
- if (trackBuffer.lastEnqueuedDecodeEndTime.isValid() && sample->decodeTime() - trackBuffer.lastEnqueuedDecodeEndTime > oneSecond)
+ if (trackBuffer.lastEnqueuedDecodeKey.first.isValid()
+ && trackBuffer.lastEnqueuedDecodeDuration.isValid()
+ && sample->decodeTime() - trackBuffer.lastEnqueuedDecodeKey.first > oneSecond + trackBuffer.lastEnqueuedDecodeDuration)
break;
// Remove the sample from the decode queue now.
@@ -2011,7 +2015,8 @@
trackBuffer.decodeQueue.erase(trackBuffer.decodeQueue.begin());
trackBuffer.lastEnqueuedPresentationTime = sample->presentationTime();
- trackBuffer.lastEnqueuedDecodeEndTime = sample->decodeTime() + sample->duration();
+ trackBuffer.lastEnqueuedDecodeKey = {sample->decodeTime(), sample->presentationTime()};
+ trackBuffer.lastEnqueuedDecodeDuration = sample->duration();
m_private->enqueueSample(sample.releaseNonNull(), trackID);
#if !LOG_DISABLED
++enqueuedSamples;
@@ -2070,12 +2075,16 @@
}
if (!trackBuffer.decodeQueue.empty()) {
- auto& lastSample = trackBuffer.decodeQueue.rbegin()->second;
- trackBuffer.lastEnqueuedPresentationTime = lastSample->presentationTime();
- trackBuffer.lastEnqueuedDecodeEndTime = lastSample->decodeTime();
+ auto lastSampleIter = trackBuffer.decodeQueue.rbegin();
+ auto lastSampleDecodeKey = lastSampleIter->first;
+ auto lastSampleDuration = lastSampleIter->second->duration();
+ trackBuffer.lastEnqueuedPresentationTime = lastSampleDecodeKey.second;
+ trackBuffer.lastEnqueuedDecodeKey = lastSampleDecodeKey;
+ trackBuffer.lastEnqueuedDecodeDuration = lastSampleDuration;
} else {
trackBuffer.lastEnqueuedPresentationTime = MediaTime::invalidTime();
- trackBuffer.lastEnqueuedDecodeEndTime = MediaTime::invalidTime();
+ trackBuffer.lastEnqueuedDecodeKey = {MediaTime::invalidTime(), MediaTime::invalidTime()};
+ trackBuffer.lastEnqueuedDecodeDuration = MediaTime::invalidTime();
}
// Fill the decode queue with the remaining samples.