Diff
Modified: trunk/LayoutTests/ChangeLog (171623 => 171624)
--- trunk/LayoutTests/ChangeLog 2014-07-25 22:38:37 UTC (rev 171623)
+++ trunk/LayoutTests/ChangeLog 2014-07-25 22:39:06 UTC (rev 171624)
@@ -1,3 +1,14 @@
+2014-07-25 Jer Noble <[email protected]>
+
+ [MSE] Playback stalls & readyState drops to HAVE_CURRENT_DATA at end of stream with unbalanced buffered SourceBuffers
+ https://bugs.webkit.org/show_bug.cgi?id=135291
+ <rdar://problem/17715503>
+
+ Reviewed by Sam Weinig.
+
+ * media/media-source/media-source-end-of-stream-buffered-expected.txt: Added.
+ * media/media-source/media-source-end-of-stream-buffered.html: Added.
+
2014-07-25 Filip Pizlo <[email protected]>
Merge r169795, r169819, r169864, r169902, r169949, r169950, r170016, r170017, r170060, r170064 from ftlopt.
Added: trunk/LayoutTests/media/media-source/media-source-end-of-stream-buffered-expected.txt (0 => 171624)
--- trunk/LayoutTests/media/media-source/media-source-end-of-stream-buffered-expected.txt (rev 0)
+++ trunk/LayoutTests/media/media-source/media-source-end-of-stream-buffered-expected.txt 2014-07-25 22:39:06 UTC (rev 171624)
@@ -0,0 +1,16 @@
+
+RUN(video.src = ""
+EVENT(sourceopen)
+RUN(sourceBuffer1 = source.addSourceBuffer("video/mock; codecs=mock"))
+RUN(sourceBuffer1.appendBuffer(mediaSegment))
+EVENT(updateend)
+RUN(sourceBuffer2 = source.addSourceBuffer("video/mock; codecs=mock"))
+RUN(sourceBuffer2.appendBuffer(mediaSegment))
+EVENT(updateend)
+RUN(source.endOfStream())
+RUN(video.currentTime = 5)
+EVENT(seeked)
+RUN(video.play())
+EVENT(playing)
+END OF TEST
+
Added: trunk/LayoutTests/media/media-source/media-source-end-of-stream-buffered.html (0 => 171624)
--- trunk/LayoutTests/media/media-source/media-source-end-of-stream-buffered.html (rev 0)
+++ trunk/LayoutTests/media/media-source/media-source-end-of-stream-buffered.html 2014-07-25 22:39:06 UTC (rev 171624)
@@ -0,0 +1,62 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>mock-media-source</title>
+ <script src=""
+ <script src=""
+ <script>
+ var source;
+ var sourceBuffer1;
+ var sourceBuffer2;
+ var initSegment;
+ var mediaSegment;
+
+ if (window.internals)
+ internals.initializeMockMediaSource();
+
+ function runTest() {
+ findMediaElement();
+
+ source = new MediaSource();
+ waitForEventOn(source, 'sourceopen', sourceOpen, false, true);
+ run('video.src = ""
+ }
+
+ function sourceOpen() {
+ run('sourceBuffer1 = source.addSourceBuffer("video/mock; codecs=mock")');
+ waitForEventOn(sourceBuffer1, 'updateend', updateEndInit1);
+ mediaSegment = concatenateSamples([
+ makeAInit(10, [makeATrack(1, 'mock', TRACK_KIND.AUDIO)]),
+ makeASample(0, 0, 10, 1, SAMPLE_FLAG.SYNC, 0),
+ ]);
+ run('sourceBuffer1.appendBuffer(mediaSegment)');
+ }
+
+ function updateEndInit1() {
+ run('sourceBuffer2 = source.addSourceBuffer("video/mock; codecs=mock")');
+ waitForEventOn(sourceBuffer2, 'updateend', updateEndInit2);
+ mediaSegment = concatenateSamples([
+ makeAInit(10, [makeATrack(1, 'mock', TRACK_KIND.VIDEO)]),
+ makeASample(0, 0, 5, 1, SAMPLE_FLAG.SYNC, 0),
+ ]);
+ run('sourceBuffer2.appendBuffer(mediaSegment)');
+ }
+
+ function updateEndInit2() {
+ run('source.endOfStream()');
+ waitForEvent('seeked', seeked);
+ run('video.currentTime = 5');
+ }
+
+ function seeked() {
+ run('video.play()');
+ waitForEventAndEnd('playing');
+ waitForEventAndFail('waiting');
+ }
+
+ </script>
+</head>
+<body _onload_="runTest()">
+ <video></video>
+</body>
+</html>
Modified: trunk/Source/WebCore/ChangeLog (171623 => 171624)
--- trunk/Source/WebCore/ChangeLog 2014-07-25 22:38:37 UTC (rev 171623)
+++ trunk/Source/WebCore/ChangeLog 2014-07-25 22:39:06 UTC (rev 171624)
@@ -1,3 +1,41 @@
+2014-07-25 Jer Noble <[email protected]>
+
+ [MSE] Playback stalls & readyState drops to HAVE_CURRENT_DATA at end of stream with unbalanced buffered SourceBuffers
+ https://bugs.webkit.org/show_bug.cgi?id=135291
+ <rdar://problem/17715503>
+
+ Reviewed by Sam Weinig.
+
+ Test: media/media-source/media-source-end-of-stream-buffered.html
+
+ When determining the correct ReadyState for the MediaSource in monitorSourceBuffers(), use the same
+ definition of "buffered" as is used in the calculation of HTMLMediaElement.buffered and in the
+ Stream Ended algorithm. Namely, when the stream has ended, treat each SourceBuffer as if its last
+ buffered range extends to the duration of the stream. This allows playback to continue through to
+ the duration without stalling due to monitorSourceBuffers().
+
+ * Modules/mediasource/SourceBuffer.cpp:
+ (WebCore::SourceBuffer::bufferedAccountingForEndOfStream): Added; extends the last range in buffered
+ to MediaSource::duration() if the MediaSource is ended.
+ (WebCore::SourceBuffer::hasCurrentTime): Uses bufferedAccountingForEndOfStream().
+ (WebCore::SourceBuffer::hasFutureTime): Ditto.
+ (WebCore::SourceBuffer::canPlayThrough): Ditto.
+ * Modules/mediasource/SourceBuffer.h:
+
+ Add a convenience method for determining whether the MediaSource has ended:
+ * Modules/mediasource/MediaSource.cpp:
+ (WebCore::MediaSource::isEnded):
+ * Modules/mediasource/MediaSource.h:
+
+ Add start() and end() methods that don't take a (usually ignored) isValid inout parameter. Add duration()
+ and maximumBufferedTime() convenience methods:
+ * platform/graphics/PlatformTimeRanges.cpp:
+ (WebCore::PlatformTimeRanges::start):
+ (WebCore::PlatformTimeRanges::end):
+ (WebCore::PlatformTimeRanges::duration):
+ (WebCore::PlatformTimeRanges::maximumBufferedTime):
+ * platform/graphics/PlatformTimeRanges.h:
+
2014-07-25 Pratik Solanki <[email protected]>
[iOS] REGRESSION(r171526): Images fail to load sometimes
Modified: trunk/Source/WebCore/Modules/mediasource/MediaSource.cpp (171623 => 171624)
--- trunk/Source/WebCore/Modules/mediasource/MediaSource.cpp 2014-07-25 22:38:37 UTC (rev 171623)
+++ trunk/Source/WebCore/Modules/mediasource/MediaSource.cpp 2014-07-25 22:39:06 UTC (rev 171624)
@@ -739,6 +739,11 @@
return readyState() == closedKeyword();
}
+bool MediaSource::isEnded() const
+{
+ return readyState() == endedKeyword();
+}
+
void MediaSource::close()
{
setReadyState(closedKeyword());
Modified: trunk/Source/WebCore/Modules/mediasource/MediaSource.h (171623 => 171624)
--- trunk/Source/WebCore/Modules/mediasource/MediaSource.h 2014-07-25 22:38:37 UTC (rev 171623)
+++ trunk/Source/WebCore/Modules/mediasource/MediaSource.h 2014-07-25 22:39:06 UTC (rev 171624)
@@ -65,6 +65,8 @@
void removedFromRegistry();
void openIfInEndedState();
bool isOpen() const;
+ bool isClosed() const;
+ bool isEnded() const;
void sourceBufferDidChangeAcitveState(SourceBuffer*, bool);
void streamEndedWithError(const AtomicString& error, ExceptionCode&);
@@ -76,7 +78,6 @@
bool attachToElement(HTMLMediaElement*);
void close();
- bool isClosed() const;
void monitorSourceBuffers();
void completeSeek();
Modified: trunk/Source/WebCore/Modules/mediasource/SourceBuffer.cpp (171623 => 171624)
--- trunk/Source/WebCore/Modules/mediasource/SourceBuffer.cpp 2014-07-25 22:38:37 UTC (rev 171623)
+++ trunk/Source/WebCore/Modules/mediasource/SourceBuffer.cpp 2014-07-25 22:39:06 UTC (rev 171624)
@@ -1454,13 +1454,27 @@
LOG(MediaSource, "SourceBuffer::monitorBufferingRate(%p) - m_avegareBufferRate: %lf", this, m_averageBufferRate);
}
+std::unique_ptr<PlatformTimeRanges> SourceBuffer::bufferedAccountingForEndOfStream() const
+{
+ // FIXME: Revisit this method once the spec bug <https://www.w3.org/Bugs/Public/show_bug.cgi?id=26436> is resolved.
+ std::unique_ptr<PlatformTimeRanges> virtualRanges = PlatformTimeRanges::create(m_buffered->ranges());
+ if (m_source->isEnded()) {
+ MediaTime start = virtualRanges->maximumBufferedTime();
+ MediaTime end = MediaTime::createWithDouble(m_source->duration());
+ if (start <= end)
+ virtualRanges->add(start, end);
+ }
+ return virtualRanges;
+}
+
bool SourceBuffer::hasCurrentTime() const
{
if (isRemoved() || !m_buffered->length())
return false;
MediaTime currentTime = MediaTime::createWithDouble(m_source->currentTime());
- return abs(m_buffered->ranges().nearest(currentTime) - currentTime) <= currentTimeFudgeFactor();
+ std::unique_ptr<PlatformTimeRanges> ranges = bufferedAccountingForEndOfStream();
+ return abs(ranges->nearest(currentTime) - currentTime) <= currentTimeFudgeFactor();
}
bool SourceBuffer::hasFutureTime() const
@@ -1468,21 +1482,21 @@
if (isRemoved())
return false;
- const PlatformTimeRanges& ranges = m_buffered->ranges();
- if (!ranges.length())
+ std::unique_ptr<PlatformTimeRanges> ranges = bufferedAccountingForEndOfStream();
+ if (!ranges->length())
return false;
MediaTime currentTime = MediaTime::createWithDouble(m_source->currentTime());
- MediaTime nearest = ranges.nearest(currentTime);
+ MediaTime nearest = ranges->nearest(currentTime);
if (abs(nearest - currentTime) > currentTimeFudgeFactor())
return false;
- size_t found = ranges.find(nearest);
+ size_t found = ranges->find(nearest);
if (found == notFound)
return false;
bool ignoredValid = false;
- return ranges.end(found, ignoredValid) - currentTime > currentTimeFudgeFactor();
+ return ranges->end(found, ignoredValid) - currentTime > currentTimeFudgeFactor();
}
bool SourceBuffer::canPlayThrough()
@@ -1498,18 +1512,16 @@
return true;
// Add up all the time yet to be buffered.
- MediaTime unbufferedTime = MediaTime::zeroTime();
MediaTime currentTime = MediaTime::createWithDouble(m_source->currentTime());
MediaTime duration = MediaTime::createWithDouble(m_source->duration());
- PlatformTimeRanges unbufferedRanges = m_buffered->ranges();
- unbufferedRanges.invert();
- unbufferedRanges.intersectWith(PlatformTimeRanges(currentTime, std::max(currentTime, duration)));
- bool valid = true;
+ std::unique_ptr<PlatformTimeRanges> unbufferedRanges = bufferedAccountingForEndOfStream();
+ unbufferedRanges->invert();
+ unbufferedRanges->intersectWith(PlatformTimeRanges(currentTime, std::max(currentTime, duration)));
+ MediaTime unbufferedTime = unbufferedRanges->totalDuration();
+ if (!unbufferedTime.isValid())
+ return true;
- for (size_t i = 0, end = unbufferedRanges.length(); i < end; ++i)
- unbufferedTime += unbufferedRanges.end(i, valid) - unbufferedRanges.start(i, valid);
-
MediaTime timeRemaining = duration - currentTime;
return unbufferedTime.toDouble() / m_averageBufferRate < timeRemaining.toDouble();
}
Modified: trunk/Source/WebCore/Modules/mediasource/SourceBuffer.h (171623 => 171624)
--- trunk/Source/WebCore/Modules/mediasource/SourceBuffer.h 2014-07-25 22:38:37 UTC (rev 171623)
+++ trunk/Source/WebCore/Modules/mediasource/SourceBuffer.h 2014-07-25 22:39:06 UTC (rev 171624)
@@ -52,6 +52,7 @@
class AudioTrackList;
class MediaSource;
+class PlatformTimeRanges;
class SourceBufferPrivate;
class TextTrackList;
class TimeRanges;
@@ -160,6 +161,8 @@
void reportExtraMemoryCost();
+ std::unique_ptr<PlatformTimeRanges> bufferedAccountingForEndOfStream() const;
+
// Internals
friend class Internals;
Vector<String> bufferedSamplesForTrackID(const AtomicString&);
Modified: trunk/Source/WebCore/platform/graphics/PlatformTimeRanges.cpp (171623 => 171624)
--- trunk/Source/WebCore/platform/graphics/PlatformTimeRanges.cpp 2014-07-25 22:38:37 UTC (rev 171623)
+++ trunk/Source/WebCore/platform/graphics/PlatformTimeRanges.cpp 2014-07-25 22:39:06 UTC (rev 171624)
@@ -115,6 +115,12 @@
m_ranges.swap(unioned.m_ranges);
}
+MediaTime PlatformTimeRanges::start(unsigned index) const
+{
+ bool ignoredValid;
+ return start(index, ignoredValid);
+}
+
MediaTime PlatformTimeRanges::start(unsigned index, bool& valid) const
{
if (index >= length()) {
@@ -126,6 +132,12 @@
return m_ranges[index].m_start;
}
+MediaTime PlatformTimeRanges::end(unsigned index) const
+{
+ bool ignoredValid;
+ return end(index, ignoredValid);
+}
+
MediaTime PlatformTimeRanges::end(unsigned index, bool& valid) const
{
if (index >= length()) {
@@ -137,6 +149,22 @@
return m_ranges[index].m_end;
}
+MediaTime PlatformTimeRanges::duration(unsigned index) const
+{
+ if (index >= length())
+ return MediaTime::invalidTime();
+
+ return m_ranges[index].m_end - m_ranges[index].m_start;
+}
+
+MediaTime PlatformTimeRanges::maximumBufferedTime() const
+{
+ if (!length())
+ return MediaTime::invalidTime();
+
+ return m_ranges[length() - 1].m_end;
+}
+
void PlatformTimeRanges::add(const MediaTime& start, const MediaTime& end)
{
ASSERT(start <= end);
Modified: trunk/Source/WebCore/platform/graphics/PlatformTimeRanges.h (171623 => 171624)
--- trunk/Source/WebCore/platform/graphics/PlatformTimeRanges.h 2014-07-25 22:38:37 UTC (rev 171623)
+++ trunk/Source/WebCore/platform/graphics/PlatformTimeRanges.h 2014-07-25 22:39:06 UTC (rev 171624)
@@ -46,8 +46,12 @@
PlatformTimeRanges& operator=(const PlatformTimeRanges&);
+ MediaTime start(unsigned index) const;
MediaTime start(unsigned index, bool& valid) const;
+ MediaTime end(unsigned index) const;
MediaTime end(unsigned index, bool& valid) const;
+ MediaTime duration(unsigned index) const;
+ MediaTime maximumBufferedTime() const;
void invert();
void intersectWith(const PlatformTimeRanges&);