diff --git a/dom/media/mediasource/MediaSource.cpp b/dom/media/mediasource/MediaSource.cpp index 6a45d1118cbe..a41fe9eb2542 100644 --- a/dom/media/mediasource/MediaSource.cpp +++ b/dom/media/mediasource/MediaSource.cpp @@ -418,14 +418,10 @@ void MediaSource::DurationChange(double aOldDuration, double aNewDuration) { MOZ_ASSERT(NS_IsMainThread()); - MSE_DEBUG("MediaSource(%p)::DurationChange(aNewDuration=%f)", this, aNewDuration); + MSE_DEBUG("MediaSource(%p)::DurationChange(aOldDuration=%f, aNewDuration=%f)", this, aOldDuration, aNewDuration); if (aNewDuration < aOldDuration) { - ErrorResult rv; - mSourceBuffers->Remove(aNewDuration, aOldDuration, rv); - if (rv.Failed()) { - return; - } + mSourceBuffers->RangeRemoval(aNewDuration, aOldDuration); } // TODO: If partial audio frames/text cues exist, clamp duration based on mSourceBuffers. } diff --git a/dom/media/mediasource/SourceBuffer.cpp b/dom/media/mediasource/SourceBuffer.cpp index 320e2a6559e1..838e02c56ba9 100644 --- a/dom/media/mediasource/SourceBuffer.cpp +++ b/dom/media/mediasource/SourceBuffer.cpp @@ -188,10 +188,19 @@ SourceBuffer::Remove(double aStart, double aEnd, ErrorResult& aRv) aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR); return; } - if (mUpdating || mMediaSource->ReadyState() != MediaSourceReadyState::Open) { + if (mUpdating) { aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); return; } + if (mMediaSource->ReadyState() == MediaSourceReadyState::Ended) { + mMediaSource->SetReadyState(MediaSourceReadyState::Open); + } + RangeRemoval(aStart, aEnd); +} + +void +SourceBuffer::RangeRemoval(double aStart, double aEnd) +{ StartUpdating(); /// TODO: Run coded frame removal algorithm. diff --git a/dom/media/mediasource/SourceBuffer.h b/dom/media/mediasource/SourceBuffer.h index 5be60b50a219..88a6f892a1db 100644 --- a/dom/media/mediasource/SourceBuffer.h +++ b/dom/media/mediasource/SourceBuffer.h @@ -108,6 +108,9 @@ public: double GetBufferedStart(); double GetBufferedEnd(); + // Runs the range removal algorithm as defined by the MSE spec. + void RangeRemoval(double aStart, double aEnd); + #if defined(DEBUG) void Dump(const char* aPath); #endif diff --git a/dom/media/mediasource/SourceBufferList.cpp b/dom/media/mediasource/SourceBufferList.cpp index d833bc9ddbc9..041fbb80ed96 100644 --- a/dom/media/mediasource/SourceBufferList.cpp +++ b/dom/media/mediasource/SourceBufferList.cpp @@ -108,15 +108,12 @@ SourceBufferList::AnyUpdating() } void -SourceBufferList::Remove(double aStart, double aEnd, ErrorResult& aRv) +SourceBufferList::RangeRemoval(double aStart, double aEnd) { MOZ_ASSERT(NS_IsMainThread()); - MSE_DEBUG("SourceBufferList(%p)::Remove(aStart=%f, aEnd=%f", this, aStart, aEnd); + MSE_DEBUG("SourceBufferList(%p)::RangeRemoval(aStart=%f, aEnd=%f", this, aStart, aEnd); for (uint32_t i = 0; i < mSourceBuffers.Length(); ++i) { - mSourceBuffers[i]->Remove(aStart, aEnd, aRv); - if (aRv.Failed()) { - return; - } + mSourceBuffers[i]->RangeRemoval(aStart, aEnd); } } diff --git a/dom/media/mediasource/SourceBufferList.h b/dom/media/mediasource/SourceBufferList.h index ca5087f2ea22..de02b914a435 100644 --- a/dom/media/mediasource/SourceBufferList.h +++ b/dom/media/mediasource/SourceBufferList.h @@ -66,9 +66,8 @@ public: // Returns true if updating is true on any SourceBuffers in the list. bool AnyUpdating(); - // Calls Remove(aStart, aEnd) on each SourceBuffer in the list. Aborts on - // first error, with result returned in aRv. - void Remove(double aStart, double aEnd, ErrorResult& aRv); + // Runs the range removal steps from the MSE specification on each SourceBuffer. + void RangeRemoval(double aStart, double aEnd); // Mark all SourceBuffers input buffers as ended. void Ended(); diff --git a/dom/media/mediasource/test/mochitest.ini b/dom/media/mediasource/test/mochitest.ini index 9d527391816b..2bb16b2fd8bc 100644 --- a/dom/media/mediasource/test/mochitest.ini +++ b/dom/media/mediasource/test/mochitest.ini @@ -9,6 +9,7 @@ support-files = [test_MediaSource_disabled.html] [test_BufferedSeek.html] [test_BufferingWait.html] +[test_EndOfStream.html] [test_FrameSelection.html] [test_HaveMetadataUnbufferedSeek.html] [test_LoadedMetadataFired.html] diff --git a/dom/media/mediasource/test/test_BufferedSeek.html b/dom/media/mediasource/test/test_BufferedSeek.html index b800a573576f..949fee773b7d 100644 --- a/dom/media/mediasource/test/test_BufferedSeek.html +++ b/dom/media/mediasource/test/test_BufferedSeek.html @@ -12,6 +12,8 @@ SimpleTest.waitForExplicitFinish(); +var updateCount = 0; + runWithMSE(function (ms, v) { ms.addEventListener("sourceopen", function () { var sb = ms.addSourceBuffer("video/webm"); @@ -19,7 +21,13 @@ runWithMSE(function (ms, v) { fetchWithXHR("seek.webm", function (arrayBuffer) { sb.appendBuffer(new Uint8Array(arrayBuffer)); sb.addEventListener("updateend", function () { - ms.endOfStream() + updateCount++; + /* Ensure that we endOfStream on the first update event only as endOfStream can + raise more if the duration of the last buffered range and the intial duration + differ. See bug 1065207 */ + if (updateCount == 1) { + ms.endOfStream(); + }; }); }); diff --git a/dom/media/mediasource/test/test_EndOfStream.html b/dom/media/mediasource/test/test_EndOfStream.html new file mode 100644 index 000000000000..0ab76701dfdf --- /dev/null +++ b/dom/media/mediasource/test/test_EndOfStream.html @@ -0,0 +1,47 @@ + + + + MSE: endOfStream call after an appendBuffer + + + + + +
+
+
+ + diff --git a/dom/media/mediasource/test/test_FrameSelection.html b/dom/media/mediasource/test/test_FrameSelection.html index d75d8f7ddedd..bb2634c706a1 100644 --- a/dom/media/mediasource/test/test_FrameSelection.html +++ b/dom/media/mediasource/test/test_FrameSelection.html @@ -12,6 +12,8 @@ SimpleTest.waitForExplicitFinish(); +var updateCount = 0; + runWithMSE(function (ms, v) { ms.addEventListener("sourceopen", function () { var sb = ms.addSourceBuffer("video/webm"); @@ -34,13 +36,13 @@ runWithMSE(function (ms, v) { fetchWithXHR("seek_lowres.webm", function (arrayBuffer) { // Append initialization segment. sb.appendBuffer(new Uint8Array(arrayBuffer, 0, 438)); - var first = true; sb.addEventListener("updateend", function () { - if (first) { + updateCount++; + if (updateCount == 1) { // Append media segment covering range [2, 4]. sb.appendBuffer(new Uint8Array(arrayBuffer, 51003)); - first = false; - } else { + } + else if (updateCount == 2) { ms.endOfStream(); target = targets.shift(); v.currentTime = target.currentTime; diff --git a/dom/media/mediasource/test/test_MediaSource.html b/dom/media/mediasource/test/test_MediaSource.html index 131d64b1c485..53c03cefa130 100644 --- a/dom/media/mediasource/test/test_MediaSource.html +++ b/dom/media/mediasource/test/test_MediaSource.html @@ -57,7 +57,12 @@ runWithMSE(function () { sb.addEventListener("update", function () { is(sb.updating, false, "SourceBuffer.updating is expected value in update event"); updateCount++; - ms.endOfStream(); + /* Ensure that we endOfStream on the first update event only as endOfStream can + raise more if the duration of the last buffered range and the intial duration + differ. See bug 1065207 */ + if (updateCount == 1) { + ms.endOfStream(); + } }); sb.addEventListener("updatestart", function () { @@ -84,9 +89,10 @@ runWithMSE(function () { // XXX: Duration should be exactly 4.0, see bug 1065207. ok(Math.abs(v.duration - 4) <= 0.002, "Video has correct duration"); ok(Math.abs(v.currentTime - 4) <= 0.002, "Video has played to end"); - is(updateCount, 1, "update event received"); - is(updateendCount, 1, "updateend event received"); - is(updatestartCount, 1, "updatestart event received"); + // XXX: 2 update events can be received dueto duration differences, see bug 1065207. + ok(updateCount == 1 || updateCount == 2, "update event received"); + ok(updateendCount == 1 || updateendCount == 2, "updateend event received"); + ok(updatestartCount == 1 || updatestartCount == 2, "updatestart event received"); is(loadedmetadataCount, 1, "loadedmetadata event received"); v.parentNode.removeChild(v); SimpleTest.finish(); diff --git a/dom/media/mediasource/test/test_SeekableAfterEndOfStream.html b/dom/media/mediasource/test/test_SeekableAfterEndOfStream.html index 7ffe68686685..850434429a24 100644 --- a/dom/media/mediasource/test/test_SeekableAfterEndOfStream.html +++ b/dom/media/mediasource/test/test_SeekableAfterEndOfStream.html @@ -12,6 +12,8 @@ SimpleTest.waitForExplicitFinish(); +var updateCount = 0; + runWithMSE(function (ms, v) { ms.addEventListener("sourceopen", function () { var sb = ms.addSourceBuffer("video/webm"); @@ -19,7 +21,13 @@ runWithMSE(function (ms, v) { fetchWithXHR("seek.webm", function (arrayBuffer) { sb.appendBuffer(new Uint8Array(arrayBuffer)); sb.addEventListener("updateend", function () { - ms.endOfStream() + updateCount++; + /* Ensure that we endOfStream on the first update event only as endOfStream can + raise more if the duration of the last buffered range and the intial duration + differ. See bug 1065207 */ + if (updateCount == 1) { + ms.endOfStream(); + }; }); }); diff --git a/dom/media/mediasource/test/test_SeekableAfterEndOfStreamSplit.html b/dom/media/mediasource/test/test_SeekableAfterEndOfStreamSplit.html index 5f75f11ffec2..771f9b159a60 100644 --- a/dom/media/mediasource/test/test_SeekableAfterEndOfStreamSplit.html +++ b/dom/media/mediasource/test/test_SeekableAfterEndOfStreamSplit.html @@ -24,7 +24,7 @@ runWithMSE(function (ms, v) { if (updateCount == 1) { sb.appendBuffer(new Uint8Array(arrayBuffer, 25223)); } - else { + else if (updateCount == 2) { ms.endOfStream(); } }); diff --git a/dom/media/mediasource/test/test_SplitAppend.html b/dom/media/mediasource/test/test_SplitAppend.html index f743032080d7..e87bd00edca5 100644 --- a/dom/media/mediasource/test/test_SplitAppend.html +++ b/dom/media/mediasource/test/test_SplitAppend.html @@ -12,18 +12,20 @@ SimpleTest.waitForExplicitFinish(); +var updateCount = 0; + runWithMSE(function (ms, v) { ms.addEventListener("sourceopen", function () { var sb = ms.addSourceBuffer("video/webm"); fetchWithXHR("seek.webm", function (arrayBuffer) { sb.appendBuffer(new Uint8Array(arrayBuffer, 0, 318)); - var first = true; sb.addEventListener("updateend", function () { - if (first) { + updateCount++; + if (updateCount == 1) { sb.appendBuffer(new Uint8Array(arrayBuffer, 318)); - first = false; - } else { + } + else if (updateCount == 2) { ms.endOfStream(); } }); diff --git a/dom/media/mediasource/test/test_SplitAppendDelay.html b/dom/media/mediasource/test/test_SplitAppendDelay.html index 10dde8b8156e..f4604b3d0c1c 100644 --- a/dom/media/mediasource/test/test_SplitAppendDelay.html +++ b/dom/media/mediasource/test/test_SplitAppendDelay.html @@ -12,20 +12,22 @@ SimpleTest.waitForExplicitFinish(); +var updateCount = 0; + runWithMSE(function (ms, v) { ms.addEventListener("sourceopen", function () { var sb = ms.addSourceBuffer("video/webm"); fetchWithXHR("seek.webm", function (arrayBuffer) { sb.appendBuffer(new Uint8Array(arrayBuffer, 0, 318)); - var first = true; sb.addEventListener("updateend", function () { - if (first) { + updateCount++; + if (updateCount == 1) { window.setTimeout(function () { sb.appendBuffer(new Uint8Array(arrayBuffer, 318)); - first = false; }, 1000); - } else { + } + else if (updateCount == 2) { ms.endOfStream(); } });