Commit 1d1b575b authored by henriks@opera.com's avatar henriks@opera.com

Implement seekable() according to the MediaSource specification

BUG=432051
R=philipj@opera.com

Review URL: https://codereview.chromium.org/710173004

git-svn-id: svn://svn.chromium.org/blink/trunk@185191 bbb929c8-8fbe-4397-9dbb-9b2b20218538
parent 1f0854bc
PASS Get seekable time ranges when the sourcebuffer is empty.
PASS Get seekable time ranges after init segment received.
PASS Get seekable time ranges on an infinite stream.
<!DOCTYPE html>
<html>
<head>
<script src="/w3c/resources/testharness.js"></script>
<script src="/w3c/resources/testharnessreport.js"></script>
<script src="mediasource-util.js"></script>
<link rel="stylesheet" href="/w3c/resources/testharness.css">
</head>
<body>
<div id="log"></div>
<script>
mediasource_test(function(test, mediaElement, mediaSource)
{
test.failOnEvent(mediaElement, 'error');
test.endOnEvent(mediaElement, 'ended');
var sourceBuffer = mediaSource.addSourceBuffer(MediaSourceUtil.AUDIO_ONLY_TYPE);
assertSeekableEquals(mediaElement, '{ }', 'mediaElement.seekable');
test.done();
}, 'Get seekable time ranges when the sourcebuffer is empty.');
mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
{
var initSegment = MediaSourceUtil.extractSegmentData(mediaData, segmentInfo.init);
test.expectEvent(mediaElement, 'durationchange', 'mediaElement got duration');
sourceBuffer.appendBuffer(initSegment);
test.waitForExpectedEvents(function()
{
assert_equals(mediaElement.duration, 6.042);
assertSeekableEquals(mediaElement, '{ [0.000, 6.042) }', 'mediaElement.seekable');
test.done();
});
}, 'Get seekable time ranges after init segment received.');
mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
{
var initSegment = MediaSourceUtil.extractSegmentData(mediaData, segmentInfo.init);
test.expectEvent(mediaElement, 'durationchange', 'mediaElement got duration after initsegment');
sourceBuffer.appendBuffer(initSegment);
test.waitForExpectedEvents(function()
{
test.expectEvent(mediaElement, 'durationchange', 'mediaElement got infinity duration');
mediaSource.duration = Infinity;
test.waitForExpectedEvents(function()
{
assertSeekableEquals(mediaElement, '{ }', 'mediaElement.seekable');
// Append a segment from the middle of the stream to make sure that seekable does not use buffered.start(0) or duration as first or last value
var midSegment = MediaSourceUtil.extractSegmentData(mediaData, segmentInfo.media[2]);
test.expectEvent(sourceBuffer, 'update');
test.expectEvent(sourceBuffer, 'updateend');
sourceBuffer.appendBuffer(midSegment);
test.waitForExpectedEvents(function()
{
assert_equals(mediaElement.seekable.length, 1, 'mediaElement.seekable.length');
assert_equals(mediaElement.buffered.length, 1, 'mediaElement.buffered.length');
assert_equals(mediaElement.seekable.start(0), 0);
assert_not_equals(mediaElement.seekable.end(0), mediaElement.duration);
assert_not_equals(0, mediaElement.buffered.start(0));
assert_equals(mediaElement.seekable.end(0), mediaElement.buffered.end(0));
test.done();
});
});
});
}, 'Get seekable time ranges on an infinite stream.');
</script>
</body>
</html>
......@@ -399,4 +399,10 @@
assert_equals(actual, expected, description);
};
window['assertSeekableEquals'] = function(obj, expected, description)
{
var actual = timeRangesToString(obj.seekable);
assert_equals(actual, expected, description);
};
})(window);
......@@ -3352,6 +3352,9 @@ PassRefPtrWillBeRawPtr<TimeRanges> HTMLMediaElement::seekable() const
if (!webMediaPlayer())
return TimeRanges::create();
if (m_mediaSource)
return m_mediaSource->seekable();
return TimeRanges::create(webMediaPlayer()->seekable());
}
......
......@@ -67,6 +67,7 @@ public:
virtual bool isClosed() const = 0;
virtual double duration() const = 0;
virtual PassRefPtrWillBeRawPtr<TimeRanges> buffered() const = 0;
virtual PassRefPtrWillBeRawPtr<TimeRanges> seekable() const = 0;
#if !ENABLE(OILPAN)
virtual void refHTMLMediaSource() = 0;
virtual void derefHTMLMediaSource() = 0;
......
......@@ -361,6 +361,29 @@ PassRefPtrWillBeRawPtr<TimeRanges> MediaSource::buffered() const
return intersectionRanges.release();
}
PassRefPtrWillBeRawPtr<TimeRanges> MediaSource::seekable() const
{
// Implements MediaSource algorithm for HTMLMediaElement.seekable.
// https://dvcs.w3.org/hg/html-media/raw-file/default/media-source/media-source.html#htmlmediaelement-extensions
double sourceDuration = duration();
// 1. If duration equals NaN then return an empty TimeRanges object.
if (std::isnan(sourceDuration))
return TimeRanges::create();
// 2. If duration equals positive Infinity, then return a single range with a start time of 0 and an end time equal to the
// highest end time reported by the HTMLMediaElement.buffered attribute.
if (sourceDuration == std::numeric_limits<double>::infinity()) {
RefPtrWillBeRawPtr<TimeRanges> buffered = m_attachedElement->buffered();
if (buffered->length() == 0)
return TimeRanges::create();
return TimeRanges::create(0, buffered->end(buffered->length() - 1, ASSERT_NO_EXCEPTION));
}
// 3. Otherwise, return a single range with a start time of 0 and an end time equal to duration.
return TimeRanges::create(0, sourceDuration);
}
void MediaSource::setDuration(double duration, ExceptionState& exceptionState)
{
// 2.1 http://www.w3.org/TR/media-source/#widl-MediaSource-duration
......
......@@ -81,6 +81,7 @@ public:
virtual bool isClosed() const override;
virtual double duration() const override;
virtual PassRefPtrWillBeRawPtr<TimeRanges> buffered() const override;
virtual PassRefPtrWillBeRawPtr<TimeRanges> seekable() const override;
#if !ENABLE(OILPAN)
virtual void refHTMLMediaSource() override { ref(); }
virtual void derefHTMLMediaSource() override { deref(); }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment