Import Cobalt 19.master.0.203780

Includes the following patches:
  https://cobalt-review.googlesource.com/c/cobalt/+/5210
    by errong.leng@samsung.com
  https://cobalt-review.googlesource.com/c/cobalt/+/5270
    by linus.wang@samsung.com
diff --git a/src/third_party/web_platform_tests/media-source/SourceBuffer-abort-readyState.html b/src/third_party/web_platform_tests/media-source/SourceBuffer-abort-readyState.html
new file mode 100644
index 0000000..159ee60
--- /dev/null
+++ b/src/third_party/web_platform_tests/media-source/SourceBuffer-abort-readyState.html
@@ -0,0 +1,72 @@
+<!doctype html>
+<html>
+<head>
+  <meta charset='utf-8'>
+  <title>SourceBuffer#abort() when readyState attribute is not in the "open"</title>
+  <meta name="timeout" content="long">
+  <script src="/resources/testharness.js"></script>
+  <script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+<div id="log"></div>
+
+<script>
+var contents = {'/media/white.webm': 'video/webm; codecs="vorbis,vp8"',
+                '/media/white.mp4' : 'video/mp4'};
+
+//check the browser supports the MIME used in this test
+function isTypeSupported(mime) {
+    if(!MediaSource.isTypeSupported(mime)) {
+        this.step(function() {
+            assert_unreached("Browser doesn't support the MIME used in this test: " + mime);
+        });
+        this.done();
+        return false;
+    }
+    return true;
+}
+function GET(url, processBody) {
+    var xhr = new XMLHttpRequest();
+    xhr.open('GET', url, true);
+    xhr.responseType = 'arraybuffer';
+    xhr.send();
+    xhr.onload = function(e) {
+        if (xhr.status != 200) {
+            alert("Unexpected status code " + xhr.status + " for " + url);
+            return false;
+        }
+        processBody(new Uint8Array(xhr.response));
+    };
+}
+function mediaTest(file, mime) {
+    async_test(function(t) {
+        if(!isTypeSupported.bind(t)(mime)) {
+            return;
+        }
+        GET(file, function(data) {
+            var mediaSource = new MediaSource();
+            var sourceBuffer = null;
+            mediaSource.addEventListener('sourceopen', function(e) {
+                sourceBuffer = mediaSource.addSourceBuffer(mime);
+                mediaSource.endOfStream();
+                assert_equals(mediaSource.readyState, 'ended',
+                              'mediaSource.readyState is "ended" after endOfStream()');
+            });
+            mediaSource.addEventListener('sourceended', t.step_func_done(function(e) {
+                assert_throws({name: 'InvalidStateError'}, function() {
+                    sourceBuffer.abort();
+                });
+            }));
+            var video = document.createElement('video');
+            video.src = window.URL.createObjectURL(mediaSource);
+        });
+    }, 'SourceBuffer#abort() (' + mime + ') : If the readyState attribute ' +
+       'of the parent media source is not in the "open" state then throw ' +
+       'an INVALID_STATE_ERR exception and abort these steps.');
+}
+for(var file in contents) {
+    mediaTest(file, contents[file]);
+}
+</script>
+</body>
+</html>
diff --git a/src/third_party/web_platform_tests/media-source/SourceBuffer-abort-removed.html b/src/third_party/web_platform_tests/media-source/SourceBuffer-abort-removed.html
new file mode 100644
index 0000000..00d65c1
--- /dev/null
+++ b/src/third_party/web_platform_tests/media-source/SourceBuffer-abort-removed.html
@@ -0,0 +1,52 @@
+<!doctype html>
+<html>
+<head>
+  <meta charset='utf-8'>
+  <title>SourceBuffer#abort() for already removed buffer from parent media source</title>
+  <script src="/resources/testharness.js"></script>
+  <script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+<div id="log"></div>
+
+<script>
+var mimes = ['video/webm; codecs="vorbis,vp8"', 'video/mp4'];
+
+//check the browser supports the MIME used in this test
+function isTypeSupported(mime) {
+    if(!MediaSource.isTypeSupported(mime)) {
+        this.step(function() {
+            assert_unreached("Browser doesn't support the MIME used in this test: " + mime);
+        });
+        this.done();
+        return false;
+    }
+    return true;
+}
+function mediaTest(mime) {
+    async_test(function(t) {
+        if(!isTypeSupported.bind(t)(mime)) {
+            return;
+        }
+        var mediaSource = new MediaSource();
+        mediaSource.addEventListener('sourceopen', t.step_func_done(function(e) {
+            var sourceBuffer = mediaSource.addSourceBuffer(mime);
+            mediaSource.removeSourceBuffer(sourceBuffer);
+            assert_throws({name: 'InvalidStateError'},
+                          function() {
+                              sourceBuffer.abort();
+                          },
+                          'SourceBuffer#abort() after removing the SourceBuffer object');
+        }), false);
+        var video = document.createElement('video');
+        video.src = window.URL.createObjectURL(mediaSource);
+    }, 'SourceBuffer#abort (' + mime + ') : ' +
+       'if this object has been removed from the sourceBuffers attribute of the parent media source, ' +
+       'then throw an INVALID_STATE_ERR exception and abort these steps.');
+}
+mimes.forEach(function(mime) {
+    mediaTest(mime);
+});
+</script>
+</body>
+</html>
diff --git a/src/third_party/web_platform_tests/media-source/SourceBuffer-abort-updating.html b/src/third_party/web_platform_tests/media-source/SourceBuffer-abort-updating.html
new file mode 100644
index 0000000..1132d14
--- /dev/null
+++ b/src/third_party/web_platform_tests/media-source/SourceBuffer-abort-updating.html
@@ -0,0 +1,92 @@
+<!doctype html>
+<html>
+<head>
+  <meta charset='utf-8'>
+  <title>Check SourceBuffer#abort() when the updating attribute is true</title>
+  <script src="/resources/testharness.js"></script>
+  <script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+<div id="log"></div>
+
+<script>
+var contents = {'/media/white.webm': 'video/webm; codecs="vorbis,vp8"',
+                '/media/white.mp4' : 'video/mp4'};
+
+function GET(url, processBody) {
+    var xhr = new XMLHttpRequest();
+    xhr.open('GET', url, true);
+    xhr.responseType = 'arraybuffer';
+    xhr.send();
+    xhr.onload = function(e) {
+        if (xhr.status != 200) {
+            alert("Unexpected status code " + xhr.status + " for " + url);
+            return false;
+        }
+        processBody(new Uint8Array(xhr.response));
+    };
+}
+//check the browser supports the MIME used in this test
+function isTypeSupported(mime) {
+    if(!MediaSource.isTypeSupported(mime)) {
+        this.step(function() {
+            assert_unreached("Browser doesn't support the MIME used in this test: " + mime);
+        });
+        this.done();
+        return false;
+    }
+    return true;
+}
+function mediaTest(file, mime) {
+    async_test(function(t) {
+        if(!isTypeSupported.bind(t)(mime)) {
+            return;
+        }
+        GET(file, function(data) {
+            var mediaSource = new MediaSource();
+            var num_updateend = 0;
+            var events = [];
+            mediaSource.addEventListener('sourceopen', t.step_func(function(e) {
+                var sourceBuffer = mediaSource.addSourceBuffer(mime);
+                assert_equals(sourceBuffer.updating, false);
+                sourceBuffer.addEventListener('updatestart', t.step_func(function(e) {
+                    events.push('updatestart');
+                    //abort when sourceBuffer#updating is true
+                    sourceBuffer.abort();
+
+                    assert_equals(sourceBuffer.updating, false,
+                                  'Check updating value after calling abort.');
+                    assert_equals(sourceBuffer.appendWindowStart, 0);
+                    assert_equals(sourceBuffer.appendWindowEnd, Number.POSITIVE_INFINITY);
+                }));
+                sourceBuffer.addEventListener('update', t.step_func(function(e) {
+                    assert_unreached("Can't touch this");
+                }));
+                sourceBuffer.addEventListener('updateend', function(e) {
+                    events.push('updateend');
+                    mediaSource.endOfStream();
+                });
+                sourceBuffer.addEventListener('abort', function(e) {
+                    events.push('abort');
+                });
+                sourceBuffer.addEventListener('error', t.step_func(function(e) {
+                    assert_unreached("Can't touch this");
+                }));
+                sourceBuffer.appendBuffer(data);
+            }));
+            mediaSource.addEventListener('sourceended', t.step_func_done(function(e) {
+                assert_array_equals(events,
+                                    ['updatestart', 'abort', 'updateend'],
+                                    'Check the sequence of fired events.');
+            }));
+            var video = document.createElement('video');
+            video.src = window.URL.createObjectURL(mediaSource);
+        });
+    }, 'SourceBuffer#abort() (' + mime + ') : Check the algorithm when the updating attribute is true.');
+}
+for(var file in contents) {
+    mediaTest(file, contents[file]);
+}
+</script>
+</body>
+</html>
diff --git a/src/third_party/web_platform_tests/media-source/SourceBuffer-abort.html b/src/third_party/web_platform_tests/media-source/SourceBuffer-abort.html
new file mode 100644
index 0000000..7d7c9ff
--- /dev/null
+++ b/src/third_party/web_platform_tests/media-source/SourceBuffer-abort.html
@@ -0,0 +1,34 @@
+<!doctype html>
+<html>
+<head>
+  <meta charset='utf-8'>
+  <title>Check the values of appendWindowStart and appendWindowEnd after abort()</title>
+  <script src="/resources/testharness.js"></script>
+  <script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+<div id="log"></div>
+
+<script>
+var mimes = ['video/webm; codecs="vorbis,vp8"', 'video/mp4'];
+
+mimes.forEach(function(mime) {
+    async_test(function() {
+        assert_true(MediaSource.isTypeSupported(mime),
+                    "Browser doesn't support the MIME used in this test: " + mime);
+
+        var mediaSource = new MediaSource();
+        mediaSource.addEventListener('sourceopen', this.step_func_done(function(e) {
+            var sourceBuffer = mediaSource.addSourceBuffer(mime);
+            sourceBuffer.abort();
+            assert_equals(sourceBuffer.appendWindowStart, 0);
+            assert_equals(sourceBuffer.appendWindowEnd, Number.POSITIVE_INFINITY);
+        }));
+
+        var video = document.createElement('video');
+        video.src = window.URL.createObjectURL(mediaSource);
+    }, 'SourceBuffer#abort() (' + mime + '): Check the values of appendWindowStart and appendWindowEnd.');
+});
+</script>
+</body>
+</html>
diff --git a/src/third_party/web_platform_tests/media-source/URL-createObjectURL-null.html b/src/third_party/web_platform_tests/media-source/URL-createObjectURL-null.html
new file mode 100644
index 0000000..a4177dd
--- /dev/null
+++ b/src/third_party/web_platform_tests/media-source/URL-createObjectURL-null.html
@@ -0,0 +1,19 @@
+<!doctype html>
+<html>
+<head>
+  <meta charset='utf-8'>
+  <title>URL.createObjectURL(null)</title>
+  <script src="/resources/testharness.js"></script>
+  <script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+<div id="log"></div>
+<script>
+test(function() {
+    assert_throws(new TypeError(), function() {
+        window.URL.createObjectURL(null);
+    });
+}, "URL.createObjectURL(null)");
+</script>
+</body>
+</html>
diff --git a/src/third_party/web_platform_tests/media-source/URL-createObjectURL-revoke.html b/src/third_party/web_platform_tests/media-source/URL-createObjectURL-revoke.html
new file mode 100644
index 0000000..c5e18d4
--- /dev/null
+++ b/src/third_party/web_platform_tests/media-source/URL-createObjectURL-revoke.html
@@ -0,0 +1,59 @@
+<!doctype html>
+<html>
+<head>
+  <meta charset='utf-8'>
+  <title>Revoking a created URL with URL.revokeObjectURL(url)</title>
+  <script src="/resources/testharness.js"></script>
+  <script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+<div id="log"></div>
+<script>
+async_test(function(t) {
+    var mediaSource = new MediaSource();
+    var url = window.URL.createObjectURL(mediaSource);
+    window.URL.revokeObjectURL(url);
+    mediaSource.addEventListener('sourceopen',
+                                 t.unreached_func("url should not reference MediaSource."));
+    var video = document.createElement('video');
+    video.src = url;
+    video.addEventListener('error', t.step_func_done(function(e) {
+        assert_equals(e.target.error.code,
+                      MediaError.MEDIA_ERR_SRC_NOT_SUPPORTED,
+                      'Expected error code');
+        assert_equals(mediaSource.readyState, 'closed');
+    }));
+}, "Check revoking behavior of URL.revokeObjectURL(url).");
+async_test(function(t) {
+    var mediaSource = new MediaSource();
+    var url = window.URL.createObjectURL(mediaSource);
+    var video = document.createElement('video');
+    var unexpectedErrorHandler = t.unreached_func("Unexpected error.")
+    video.addEventListener('error', unexpectedErrorHandler);
+    video.src = url;
+    window.URL.revokeObjectURL(url);
+    mediaSource.addEventListener('sourceopen', t.step_func_done(function(e) {
+        assert_equals(mediaSource.readyState, 'open');
+        mediaSource.endOfStream();
+        video.removeEventListener('error', unexpectedErrorHandler);
+    }));
+}, "Check referenced MediaSource can open after URL.revokeObjectURL(url).");
+async_test(function(t) {
+    var mediaSource = new MediaSource();
+    var url = window.URL.createObjectURL(mediaSource);
+    setTimeout(function() {
+        mediaSource.addEventListener('sourceopen',
+                                     t.unreached_func("url should not reference MediaSource."));
+        var video = document.createElement('video');
+        video.src = url;
+        video.addEventListener('error', t.step_func_done(function(e) {
+            assert_equals(e.target.error.code,
+                          MediaError.MEDIA_ERR_SRC_NOT_SUPPORTED,
+                          'Expected error code');
+            assert_equals(mediaSource.readyState, 'closed');
+        }));
+    }, 0);
+}, "Check auto-revoking behavior with URL.createObjectURL(MediaSource).");
+</script>
+</body>
+</html>
diff --git a/src/third_party/web_platform_tests/media-source/URL-createObjectURL.html b/src/third_party/web_platform_tests/media-source/URL-createObjectURL.html
new file mode 100644
index 0000000..da82806
--- /dev/null
+++ b/src/third_party/web_platform_tests/media-source/URL-createObjectURL.html
@@ -0,0 +1,20 @@
+<!doctype html>
+<html>
+<head>
+  <meta charset='utf-8'>
+  <title>URL.createObjectURL(mediaSource)</title>
+  <script src="/resources/testharness.js"></script>
+  <script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+<div id="log"></div>
+<script>
+test(function() {
+    var mediaSource = new MediaSource();
+    var url = window.URL.createObjectURL(mediaSource);
+    assert_true(url != null);
+    assert_true(url.match(/^blob:.+/) != null);
+}, "URL.createObjectURL(mediaSource) should return a unique Blob URI.");
+</script>
+</body>
+</html>
diff --git a/src/third_party/web_platform_tests/media-source/import_tests.sh b/src/third_party/web_platform_tests/media-source/import_tests.sh
new file mode 100755
index 0000000..a87619c
--- /dev/null
+++ b/src/third_party/web_platform_tests/media-source/import_tests.sh
@@ -0,0 +1,52 @@
+#!/bin/bash
+
+if [ $# -lt 1 ]
+then
+  echo "Usage: $0 <Blink directory>"
+  exit -1
+fi
+
+BLINK_ROOT=$1
+LAYOUT_TEST_DIR=$BLINK_ROOT/LayoutTests
+HTTP_MEDIA_TEST_DIR=$LAYOUT_TEST_DIR/http/tests/media
+
+if [ ! -d "$BLINK_ROOT" ]
+then
+  echo "$BLINK_ROOT is not a directory or doesn't exist"
+  exit -1
+fi
+
+if [ ! -d "$LAYOUT_TEST_DIR" ]
+then
+  echo "$LAYOUT_TEST_DIR is not a directory or doesn't exist"
+  exit -1
+fi
+
+#rm -rf *.html *.js webm mp4 manifest.txt
+
+cp $HTTP_MEDIA_TEST_DIR/media-source/mediasource-*.html $HTTP_MEDIA_TEST_DIR/media-source/mediasource-*.js .
+cp -r $HTTP_MEDIA_TEST_DIR/resources/media-source/webm .
+cp -r $HTTP_MEDIA_TEST_DIR/resources/media-source/mp4 .
+
+# Remove Blink-specific files
+rm mediasource-gc-after-decode-error-crash.html
+
+sed -i 's/\/w3c\/resources\//\/resources\//g' *.html
+sed -i 's/\/media\/resources\/media-source\///g' *.html
+sed -i 's/\/media\/resources\/media-source\///g' *.js
+sed -i 's/\/media\/resources\/media-source\///g' webm/*
+
+
+for TEST_FILE in `ls *.html`
+do
+  if [ "$TEST_FILE" = "index.html" ]
+  then
+    continue
+  fi
+  echo -e "$TEST_FILE" >> manifest.txt
+done
+
+cp import_tests-template.txt index.html
+
+chmod -R a+r *.html *.js webm mp4 manifest.txt
+chmod a+rx webm mp4
diff --git a/src/third_party/web_platform_tests/media-source/interfaces.html b/src/third_party/web_platform_tests/media-source/interfaces.html
new file mode 100644
index 0000000..9d6985e
--- /dev/null
+++ b/src/third_party/web_platform_tests/media-source/interfaces.html
@@ -0,0 +1,145 @@
+<!doctype html>
+<meta charset=utf-8>
+<title>Media Source Extensions IDL tests</title>
+<div id=log></div>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src=/resources/WebIDLParser.js></script>
+<script src=/resources/idlharness.js></script>
+<script type=text/plain class=untested>
+interface EventTarget {
+  void addEventListener(DOMString type, EventListener? callback, optional boolean capture /* = false */);
+  void removeEventListener(DOMString type, EventListener? callback, optional boolean capture /* = false */);
+  boolean dispatchEvent(Event event);
+};
+interface URL {};
+interface HTMLVideoElement {};
+interface AudioTrack {};
+interface VideoTrack {};
+interface TextTrack {};
+interface TimeRanges {};
+typedef double DOMHighResTimeStamp;
+</script>
+<script type=text/plain>
+[Constructor]
+interface MediaSource : EventTarget {
+    readonly    attribute SourceBufferList    sourceBuffers;
+    readonly    attribute SourceBufferList    activeSourceBuffers;
+    readonly    attribute ReadyState          readyState;
+                attribute unrestricted double duration;
+    SourceBuffer   addSourceBuffer (DOMString type);
+    void           removeSourceBuffer (SourceBuffer sourceBuffer);
+    void           endOfStream (optional EndOfStreamError error);
+    static boolean isTypeSupported (DOMString type);
+};
+
+interface SourceBuffer : EventTarget {
+                attribute AppendMode          mode;
+    readonly    attribute boolean             updating;
+    readonly    attribute TimeRanges          buffered;
+                attribute double              timestampOffset;
+    readonly    attribute AudioTrackList      audioTracks;
+    readonly    attribute VideoTrackList      videoTracks;
+    readonly    attribute TextTrackList       textTracks;
+                attribute double              appendWindowStart;
+                attribute unrestricted double appendWindowEnd;
+    void appendBuffer (ArrayBuffer data);
+    void appendBuffer (ArrayBufferView data);
+    void appendStream (Stream stream, [EnforceRange] optional unsigned long long maxSize);
+    void abort ();
+    void remove (double start, double end);
+};
+
+interface SourceBufferList : EventTarget {
+    readonly    attribute unsigned long length;
+    getter SourceBuffer (unsigned long index);
+};
+
+interface VideoPlaybackQuality {
+    readonly    attribute DOMHighResTimeStamp creationTime;
+    readonly    attribute unsigned long       totalVideoFrames;
+    readonly    attribute unsigned long       droppedVideoFrames;
+    readonly    attribute unsigned long       corruptedVideoFrames;
+    readonly    attribute double              totalFrameDelay;
+};
+
+partial interface URL {
+    static DOMString createObjectURL (MediaSource mediaSource);
+};
+
+partial interface HTMLVideoElement {
+    VideoPlaybackQuality getVideoPlaybackQuality ();
+};
+
+partial interface AudioTrack {
+                attribute DOMString     kind;
+                attribute DOMString     language;
+    readonly    attribute SourceBuffer? sourceBuffer;
+};
+
+partial interface VideoTrack {
+                attribute DOMString     kind;
+                attribute DOMString     language;
+    readonly    attribute SourceBuffer? sourceBuffer;
+};
+
+partial interface TextTrack {
+                attribute DOMString     kind;
+                attribute DOMString     language;
+    readonly    attribute SourceBuffer? sourceBuffer;
+};
+
+enum EndOfStreamError {
+    "network",
+    "decode"
+};
+enum AppendMode {
+    "segments",
+    "sequence"
+};
+
+enum ReadyState {
+    "closed",
+    "open",
+    "ended"
+};
+
+</script>
+<script>
+"use strict";
+var mediaSource;
+var sourceBuffer;
+var video = document.createElement("video");
+var idlCheck = function() {
+  var idlArray = new IdlArray();
+  [].forEach.call(document.querySelectorAll("script[type=text\\/plain]"), function(node) {
+    if (node.className == "untested") {
+      idlArray.add_untested_idls(node.textContent);
+    } else {
+      idlArray.add_idls(node.textContent);
+    }
+  });
+  idlArray.add_objects({
+    MediaSource: ['mediaSource'],
+    SourceBuffer: ['sourceBuffer'],
+    SourceBufferList: ['mediaSource.sourceBuffers'],
+    VideoPlaybackQuality: ['video.getVideoPlaybackQuality()'],
+  });
+  idlArray.test();
+}
+mediaSource = new MediaSource();
+video.src = URL.createObjectURL(mediaSource);
+mediaSource.addEventListener("sourceopen", function () {
+  var defaultType ='video/webm;codecs="vp8,vorbis"';
+  if (video.canPlayType(defaultType)) {
+    sourceBuffer = mediaSource.addSourceBuffer(defaultType);
+  } else {
+    sourceBuffer = mediaSource.addSourceBuffer('video/mp4');
+  }
+  sourceBuffer.addEventListener("updateend", function (e) {
+    mediaSource.endOfStream();
+    idlCheck();
+  });
+  sourceBuffer.appendBuffer(new ArrayBuffer());
+});
+</script>
diff --git a/src/third_party/web_platform_tests/media-source/manifest.txt b/src/third_party/web_platform_tests/media-source/manifest.txt
new file mode 100644
index 0000000..d8714ca
--- /dev/null
+++ b/src/third_party/web_platform_tests/media-source/manifest.txt
@@ -0,0 +1,32 @@
+mediasource-addsourcebuffer.html
+mediasource-append-buffer.html
+mediasource-appendwindow.html
+mediasource-buffered.html
+mediasource-closed.html
+mediasource-config-change-mp4-a-bitrate.html
+mediasource-config-change-mp4-av-audio-bitrate.html
+mediasource-config-change-mp4-av-framesize.html
+mediasource-config-change-mp4-av-video-bitrate.html
+mediasource-config-change-mp4-v-bitrate.html
+mediasource-config-change-mp4-v-framerate.html
+mediasource-config-change-mp4-v-framesize.html
+mediasource-config-change-webm-a-bitrate.html
+mediasource-config-change-webm-av-audio-bitrate.html
+mediasource-config-change-webm-av-framesize.html
+mediasource-config-change-webm-av-video-bitrate.html
+mediasource-config-change-webm-v-bitrate.html
+mediasource-config-change-webm-v-framerate.html
+mediasource-config-change-webm-v-framesize.html
+mediasource-duration.html
+mediasource-endofstream-invaliderror.html
+mediasource-getvideoplaybackquality.html
+mediasource-is-type-supported.html
+mediasource-multiple-attach.html
+mediasource-play.html
+mediasource-play-then-seek-back.html
+mediasource-redundant-seek.html
+mediasource-remove.html
+mediasource-seek-beyond-duration.html
+mediasource-seek-during-pending-seek.html
+mediasource-sourcebufferlist.html
+mediasource-sourcebuffer-mode.html
diff --git a/src/third_party/web_platform_tests/media-source/mediasource-addsourcebuffer.html b/src/third_party/web_platform_tests/media-source/mediasource-addsourcebuffer.html
new file mode 100644
index 0000000..61f67f4
--- /dev/null
+++ b/src/third_party/web_platform_tests/media-source/mediasource-addsourcebuffer.html
@@ -0,0 +1,153 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <title>MediaSource.addSourceBuffer() test cases</title>
+        <script src="/resources/testharness.js"></script>
+        <script src="/resources/testharnessreport.js"></script>
+        <script src="mediasource-util.js"></script>
+    </head>
+    <body>
+        <div id="log"></div>
+        <script>
+          mediasource_test(function(test, mediaElement, mediaSource)
+          {
+              mediaSource.endOfStream();
+              assert_throws("InvalidStateError",
+                          function() { mediaSource.addSourceBuffer(MediaSourceUtil.AUDIO_VIDEO_TYPE); },
+                          "addSourceBuffer() threw an exception when in 'ended' state.");
+              test.done();
+          }, "Test addSourceBuffer() in 'ended' state.");
+
+          mediasource_test(function(test, mediaElement, mediaSource)
+          {
+              assert_throws("InvalidAccessError",
+                          function() { mediaSource.addSourceBuffer(""); },
+                          "addSourceBuffer() threw an exception when passed an empty string.");
+              test.done();
+          }, "Test addSourceBuffer() with empty type");
+
+          mediasource_test(function(test, mediaElement, mediaSource)
+          {
+              assert_throws("NotSupportedError",
+                          function() { mediaSource.addSourceBuffer(null); },
+                          "addSourceBuffer() threw an exception when passed null.");
+              test.done();
+          }, "Test addSourceBuffer() with null");
+
+          mediasource_test(function(test, mediaElement, mediaSource)
+          {
+              assert_throws("NotSupportedError",
+                          function() { mediaSource.addSourceBuffer("invalidType"); },
+                          "addSourceBuffer() threw an exception for an unsupported type.");
+              test.done();
+          }, "Test addSourceBuffer() with unsupported type");
+
+
+          mediasource_test(function(test, mediaElement, mediaSource)
+          {
+              var mimetype = 'video/webm;codecs="vp8,vorbis"';
+
+              assert_true(MediaSource.isTypeSupported(mimetype), mimetype + " is supported");
+
+              var sourceBuffer = mediaSource.addSourceBuffer(mimetype);
+              assert_true(sourceBuffer != null, "New SourceBuffer returned");
+              assert_equals(mediaSource.sourceBuffers[0], sourceBuffer, "SourceBuffer is in mediaSource.sourceBuffers");
+              assert_equals(mediaSource.activeSourceBuffers.length, 0, "SourceBuffer is not in mediaSource.activeSourceBuffers");
+              test.done();
+          }, "Test addSourceBuffer() with Vorbis and VP8");
+
+          mediasource_test(function(test, mediaElement, mediaSource)
+          {
+              var videoMimetype = 'video/webm;codecs="vp8"';
+              var audioMimetype = 'audio/webm;codecs="vorbis"';
+
+              assert_true(MediaSource.isTypeSupported(videoMimetype), videoMimetype + " is supported");
+              assert_true(MediaSource.isTypeSupported(audioMimetype), audioMimetype + " is supported");
+
+              var sourceBufferA = mediaSource.addSourceBuffer(videoMimetype);
+              var sourceBufferB = mediaSource.addSourceBuffer(audioMimetype);
+              assert_equals(mediaSource.sourceBuffers[0], sourceBufferA, "sourceBufferA is in mediaSource.sourceBuffers");
+              assert_equals(mediaSource.activeSourceBuffers.length, 0, "SourceBufferA is not in mediaSource.activeSourceBuffers");
+              assert_equals(mediaSource.sourceBuffers[1], sourceBufferB, "sourceBufferB is in mediaSource.sourceBuffers");
+              assert_equals(mediaSource.activeSourceBuffers.length, 0, "SourceBufferB is not in mediaSource.activeSourceBuffers");
+              test.done();
+          }, "Test addSourceBuffer() with Vorbis and VP8 in separate SourceBuffers");
+
+          mediasource_test(function(test, mediaElement, mediaSource)
+          {
+              var mimetype = MediaSourceUtil.VIDEO_ONLY_TYPE;
+
+              assert_true(MediaSource.isTypeSupported(mimetype), mimetype + " is supported");
+
+              var sourceBuffer = mediaSource.addSourceBuffer(mimetype);
+              assert_true(sourceBuffer != null, "New SourceBuffer returned");
+              assert_equals(mediaSource.sourceBuffers[0], sourceBuffer, "SourceBuffer is in mediaSource.sourceBuffers");
+              assert_equals(mediaSource.activeSourceBuffers.length, 0, "SourceBuffer is in mediaSource.activeSourceBuffers");
+              test.done();
+          }, "Test addSourceBuffer() video only");
+
+          mediasource_test(function(test, mediaElement, mediaSource)
+          {
+              var mimetype = MediaSourceUtil.AUDIO_ONLY_TYPE;
+
+              assert_true(MediaSource.isTypeSupported(mimetype), mimetype + " is supported");
+
+              var sourceBuffer = mediaSource.addSourceBuffer(mimetype);
+              assert_true(sourceBuffer != null, "New SourceBuffer returned");
+              assert_equals(mediaSource.sourceBuffers[0], sourceBuffer, "SourceBuffer is in mediaSource.sourceBuffers");
+              assert_equals(mediaSource.activeSourceBuffers.length, 0, "SourceBuffer is in mediaSource.activeSourceBuffers");
+              test.done();
+          }, "Test addSourceBuffer() audio only");
+
+          mediasource_test(function(test, mediaElement, mediaSource)
+          {
+              var mimetype = 'video/mp4;codecs="avc1.4D4001,mp4a.40.2"';
+
+              assert_true(MediaSource.isTypeSupported(mimetype), mimetype + " is supported");
+
+              var sourceBuffer = mediaSource.addSourceBuffer(mimetype);
+              assert_true(sourceBuffer != null, "New SourceBuffer returned");
+              assert_equals(mediaSource.sourceBuffers[0], sourceBuffer, "SourceBuffer is in mediaSource.sourceBuffers");
+              assert_equals(mediaSource.activeSourceBuffers.length, 0, "SourceBuffer is not in mediaSource.activeSourceBuffers");
+              test.done();
+          }, "Test addSourceBuffer() with AAC and H.264");
+
+          mediasource_test(function(test, mediaElement, mediaSource)
+          {
+              var videoMimetype = 'video/mp4;codecs="avc1.4D4001"';
+              var audioMimetype = 'audio/mp4;codecs="mp4a.40.2"';
+
+              assert_true(MediaSource.isTypeSupported(videoMimetype), videoMimetype + " is supported");
+              assert_true(MediaSource.isTypeSupported(audioMimetype), audioMimetype + " is supported");
+
+              var sourceBufferA = mediaSource.addSourceBuffer(videoMimetype);
+              var sourceBufferB = mediaSource.addSourceBuffer(audioMimetype);
+              assert_equals(mediaSource.sourceBuffers[0], sourceBufferA, "sourceBufferA is in mediaSource.sourceBuffers");
+              assert_equals(mediaSource.activeSourceBuffers.length, 0, "SourceBufferA is not in mediaSource.activeSourceBuffers");
+              assert_equals(mediaSource.sourceBuffers[1], sourceBufferB, "sourceBufferB is in mediaSource.sourceBuffers");
+              assert_equals(mediaSource.activeSourceBuffers.length, 0, "SourceBufferB is not in mediaSource.activeSourceBuffers");
+              test.done();
+          }, "Test addSourceBuffer() with AAC and H.264 in separate SourceBuffers");
+
+          mediasource_test(function(test, mediaElement, mediaSource)
+          {
+              var reachedLimit = false;
+
+             // The 20 here is an arbitrary upper limit to make sure the test terminates. This test
+             // assumes that implementations won't support more than 20 SourceBuffers simultaneously.
+             for (var i = 0; i < 20; ++i) {
+                 try {
+                     mediaSource.addSourceBuffer(MediaSourceUtil.AUDIO_VIDEO_TYPE);
+                 } catch(e) {
+                     assert_equals(e.name, "QuotaExceededError");
+                     reachedLimit = true;
+                     break;
+                 }
+             }
+             assert_true(reachedLimit, "Reached SourceBuffer limit.");
+             test.done();
+          }, "Test addSourceBuffer() QuotaExceededError.");
+
+        </script>
+    </body>
+</html>
diff --git a/src/third_party/web_platform_tests/media-source/mediasource-append-buffer.html b/src/third_party/web_platform_tests/media-source/mediasource-append-buffer.html
new file mode 100644
index 0000000..ac2c487
--- /dev/null
+++ b/src/third_party/web_platform_tests/media-source/mediasource-append-buffer.html
@@ -0,0 +1,538 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <title>SourceBuffer.appendBuffer() test cases</title>
+        <script src="/resources/testharness.js"></script>
+        <script src="/resources/testharnessreport.js"></script>
+        <script src="mediasource-util.js"></script>
+    </head>
+    <body>
+        <div id="log"></div>
+        <script>
+          mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
+          {
+              mediaElement.addEventListener('error', test.unreached_func("Unexpected event 'error'"));
+
+              test.expectEvent(sourceBuffer, "updatestart", "Append started.");
+              test.expectEvent(sourceBuffer, "update", "Append success.");
+              test.expectEvent(sourceBuffer, "updateend", "Append ended.");
+              sourceBuffer.appendBuffer(mediaData);
+
+              assert_true(sourceBuffer.updating, "updating attribute is true");
+
+              test.waitForExpectedEvents(function()
+              {
+                 assert_false(sourceBuffer.updating, "updating attribute is false");
+                 test.done();
+              });
+          }, "Test SourceBuffer.appendBuffer() event dispatching.");
+
+          mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
+          {
+              mediaElement.addEventListener('error', test.unreached_func("Unexpected event 'error'"));
+
+              test.expectEvent(sourceBuffer, "updatestart", "Append started.");
+              test.expectEvent(sourceBuffer, "update", "Append success.");
+              test.expectEvent(sourceBuffer, "updateend", "Append ended.");
+              sourceBuffer.appendBuffer(mediaData);
+
+              assert_true(sourceBuffer.updating, "updating attribute is true");
+
+              assert_throws("InvalidStateError",
+                  function() { sourceBuffer.appendBuffer(mediaData); },
+                  "appendBuffer() throws an exception there is a pending append.");
+
+              assert_true(sourceBuffer.updating, "updating attribute is true");
+
+              test.waitForExpectedEvents(function()
+              {
+                  assert_false(sourceBuffer.updating, "updating attribute is false");
+                  test.done();
+              });
+          }, "Test SourceBuffer.appendBuffer() call during a pending appendBuffer().");
+
+          mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
+          {
+              mediaElement.addEventListener('error', test.unreached_func("Unexpected event 'error'"));
+
+              test.expectEvent(sourceBuffer, "updatestart", "Append started.");
+              test.expectEvent(sourceBuffer, "abort", "Append aborted.");
+              test.expectEvent(sourceBuffer, "updateend", "Append ended.");
+              sourceBuffer.appendBuffer(mediaData);
+
+              assert_true(sourceBuffer.updating, "updating attribute is true");
+
+              sourceBuffer.abort();
+
+              assert_false(sourceBuffer.updating, "updating attribute is false");
+
+              test.waitForExpectedEvents(function()
+              {
+                  assert_false(sourceBuffer.updating, "updating attribute is false");
+                  test.done();
+              });
+          }, "Test SourceBuffer.abort() call during a pending appendBuffer().");
+
+          mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
+          {
+              mediaElement.addEventListener('error', test.unreached_func("Unexpected event 'error'"));
+
+              test.expectEvent(sourceBuffer, "updatestart", "Append started.");
+              test.expectEvent(sourceBuffer, "update", "Append success.");
+              test.expectEvent(sourceBuffer, "updateend", "Append ended.");
+              sourceBuffer.appendBuffer(mediaData);
+              assert_true(sourceBuffer.updating, "updating attribute is true");
+
+              test.waitForExpectedEvents(function()
+              {
+                  assert_false(sourceBuffer.updating, "updating attribute is false");
+
+                  test.expectEvent(mediaSource, "sourceended", "MediaSource sourceended event");
+                  mediaSource.endOfStream();
+                  assert_equals(mediaSource.readyState, "ended", "MediaSource readyState is 'ended'");
+              });
+
+              test.waitForExpectedEvents(function()
+              {
+                  assert_equals(mediaSource.readyState, "ended", "MediaSource readyState is 'ended'");
+
+                  test.expectEvent(mediaSource, "sourceopen", "MediaSource sourceopen event");
+                  test.expectEvent(sourceBuffer, "updatestart", "Append started.");
+                  test.expectEvent(sourceBuffer, "update", "Append success.");
+                  test.expectEvent(sourceBuffer, "updateend", "Append ended.");
+                  sourceBuffer.appendBuffer(mediaData);
+
+                  assert_equals(mediaSource.readyState, "open", "MediaSource readyState is 'open'");
+                  assert_true(sourceBuffer.updating, "updating attribute is true");
+              });
+
+              test.waitForExpectedEvents(function()
+              {
+                  assert_equals(mediaSource.readyState, "open", "MediaSource readyState is 'open'");
+                  assert_false(sourceBuffer.updating, "updating attribute is false");
+                  test.done();
+              });
+          }, "Test SourceBuffer.appendBuffer() triggering an 'ended' to 'open' transition.");
+
+          mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
+          {
+              test.expectEvent(sourceBuffer, "updatestart", "Append started.");
+              test.expectEvent(sourceBuffer, "update", "Append success.");
+              test.expectEvent(sourceBuffer, "updateend", "Append ended.");
+              sourceBuffer.appendBuffer(mediaData);
+              assert_true(sourceBuffer.updating, "updating attribute is true");
+
+              test.waitForExpectedEvents(function()
+              {
+                  assert_false(sourceBuffer.updating, "updating attribute is false");
+
+                  test.expectEvent(mediaSource, "sourceended", "MediaSource sourceended event");
+                  mediaSource.endOfStream();
+                  assert_equals(mediaSource.readyState, "ended", "MediaSource readyState is 'ended'");
+              });
+
+              test.waitForExpectedEvents(function()
+              {
+                  assert_equals(mediaSource.readyState, "ended", "MediaSource readyState is 'ended'");
+
+                  test.expectEvent(mediaSource, "sourceopen", "MediaSource sourceopen event");
+                  test.expectEvent(sourceBuffer, "updatestart", "Append started.");
+                  test.expectEvent(sourceBuffer, "update", "Append success.");
+                  test.expectEvent(sourceBuffer, "updateend", "Append ended.");
+                  sourceBuffer.appendBuffer(new Uint8Array(0));
+
+                  assert_equals(mediaSource.readyState, "open", "MediaSource readyState is 'open'");
+                  assert_true(sourceBuffer.updating, "updating attribute is true");
+              });
+
+              test.waitForExpectedEvents(function()
+              {
+                  assert_equals(mediaSource.readyState, "open", "MediaSource readyState is 'open'");
+                  assert_false(sourceBuffer.updating, "updating attribute is false");
+                  test.done();
+              });
+          }, "Test zero byte SourceBuffer.appendBuffer() call triggering an 'ended' to 'open' transition.");
+
+          mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
+          {
+              mediaElement.addEventListener('error', test.unreached_func("Unexpected event 'error'"));
+
+              test.expectEvent(sourceBuffer, "updatestart", "Append started.");
+              test.expectEvent(sourceBuffer, "abort", "Append aborted.");
+              test.expectEvent(sourceBuffer, "updateend", "Append ended.");
+              sourceBuffer.appendBuffer(mediaData);
+
+              assert_true(sourceBuffer.updating, "updating attribute is true");
+              assert_equals(mediaSource.activeSourceBuffers.length, 0, "activeSourceBuffers.length");
+
+              test.expectEvent(mediaSource.sourceBuffers, "removesourcebuffer", "sourceBuffers");
+              mediaSource.removeSourceBuffer(sourceBuffer);
+
+              assert_false(sourceBuffer.updating, "updating attribute is false");
+
+              assert_throws("InvalidStateError",
+                  function() { sourceBuffer.appendBuffer(mediaData); },
+                  "appendBuffer() throws an exception because it isn't attached to the mediaSource anymore.");
+
+              test.waitForExpectedEvents(function()
+              {
+                  assert_false(sourceBuffer.updating, "updating attribute is false");
+                  test.done();
+              });
+          }, "Test MediaSource.removeSourceBuffer() call during a pending appendBuffer().");
+
+          mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
+          {
+              mediaElement.addEventListener('error', test.unreached_func("Unexpected event 'error'"));
+
+              test.expectEvent(sourceBuffer, "updatestart", "Append started.");
+              test.expectEvent(sourceBuffer, "updateend", "Append ended.");
+              sourceBuffer.appendBuffer(mediaData);
+
+              assert_true(sourceBuffer.updating, "updating attribute is true");
+
+              assert_throws("InvalidStateError",
+                  function() { mediaSource.duration = 1.0; },
+                  "set duration throws an exception when updating attribute is true.");
+
+              test.waitForExpectedEvents(function()
+              {
+                  assert_false(sourceBuffer.updating, "updating attribute is false");
+                  test.done();
+              });
+          }, "Test set MediaSource.duration during a pending appendBuffer() for one of its SourceBuffers.");
+
+          mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
+          {
+              mediaElement.addEventListener("error", test.unreached_func("Unexpected event 'error'"));
+              mediaSource.addEventListener("sourceended", test.unreached_func("Unexpected event 'sourceended'"));
+
+              test.expectEvent(sourceBuffer, "updatestart", "Append started.");
+              test.expectEvent(sourceBuffer, "updateend", "Append ended.");
+              sourceBuffer.appendBuffer(mediaData);
+
+              assert_true(sourceBuffer.updating, "updating attribute is true");
+
+              assert_throws("InvalidStateError",
+                  function() { mediaSource.endOfStream(); },
+                  "endOfStream() throws an exception when updating attribute is true.");
+
+              assert_equals(mediaSource.readyState, "open");
+
+              test.waitForExpectedEvents(function()
+              {
+                  assert_false(sourceBuffer.updating, "updating attribute is false");
+                  assert_equals(mediaSource.readyState, "open");
+                  test.done();
+              });
+          }, "Test MediaSource.endOfStream() during a pending appendBuffer() for one of its SourceBuffers.");
+
+          mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
+          {
+              mediaElement.addEventListener('error', test.unreached_func("Unexpected event 'error'"));
+
+              test.expectEvent(sourceBuffer, "updatestart", "Append started.");
+              test.expectEvent(sourceBuffer, "updateend", "Append ended.");
+              sourceBuffer.appendBuffer(mediaData);
+
+              assert_true(sourceBuffer.updating, "updating attribute is true");
+
+              assert_throws("InvalidStateError",
+                  function() { sourceBuffer.timestampOffset = 10.0; },
+                  "set timestampOffset throws an exception when updating attribute is true.");
+
+              test.waitForExpectedEvents(function()
+              {
+                  assert_false(sourceBuffer.updating, "updating attribute is false");
+                  test.done();
+              });
+          }, "Test set SourceBuffer.timestampOffset during a pending appendBuffer().");
+
+          mediasource_test(function(test, mediaElement, mediaSource)
+          {
+              var sourceBuffer = mediaSource.addSourceBuffer(MediaSourceUtil.VIDEO_ONLY_TYPE);
+
+              test.expectEvent(sourceBuffer, "updatestart", "Append started.");
+              test.expectEvent(sourceBuffer, "update", "Append success.");
+              test.expectEvent(sourceBuffer, "updateend", "Append ended.");
+              sourceBuffer.appendBuffer(new Uint8Array(0));
+
+              assert_true(sourceBuffer.updating, "updating attribute is true");
+
+              test.waitForExpectedEvents(function()
+              {
+                  assert_false(sourceBuffer.updating, "updating attribute is false");
+                  test.done();
+              });
+          }, "Test appending an empty ArrayBufferView.");
+
+          mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
+          {
+              test.expectEvent(sourceBuffer, "updatestart", "Append started.");
+              test.expectEvent(sourceBuffer, "update", "Append success.");
+              test.expectEvent(sourceBuffer, "updateend", "Append ended.");
+
+              var arrayBufferView = new Uint8Array(mediaData);
+
+              assert_equals(arrayBufferView.length, mediaData.length, "arrayBufferView.length before transfer.");
+
+              // Send the buffer as in a message so it gets neutered.
+              window.postMessage( "test", "*", [arrayBufferView.buffer]);
+
+              assert_equals(arrayBufferView.length, 0, "arrayBufferView.length after transfer.");
+
+              sourceBuffer.appendBuffer(arrayBufferView);
+
+              assert_true(sourceBuffer.updating, "updating attribute is true");
+
+              test.waitForExpectedEvents(function()
+              {
+                 assert_false(sourceBuffer.updating, "updating attribute is false");
+                 test.done();
+              });
+          }, "Test appending a neutered ArrayBufferView.");
+
+          mediasource_test(function(test, mediaElement, mediaSource)
+          {
+              var sourceBuffer = mediaSource.addSourceBuffer(MediaSourceUtil.VIDEO_ONLY_TYPE);
+
+              test.expectEvent(sourceBuffer, "updatestart", "Append started.");
+              test.expectEvent(sourceBuffer, "update", "Append success.");
+              test.expectEvent(sourceBuffer, "updateend", "Append ended.");
+              sourceBuffer.appendBuffer(new ArrayBuffer(0));
+
+              assert_true(sourceBuffer.updating, "updating attribute is true");
+
+              test.waitForExpectedEvents(function()
+              {
+                  assert_false(sourceBuffer.updating, "updating attribute is false");
+                  test.done();
+              });
+          }, "Test appending an empty ArrayBuffer.");
+
+          mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
+          {
+              test.expectEvent(sourceBuffer, "updatestart", "Append started.");
+              test.expectEvent(sourceBuffer, "update", "Append success.");
+              test.expectEvent(sourceBuffer, "updateend", "Append ended.");
+
+              var arrayBuffer = mediaData.buffer.slice(0);
+
+              assert_equals(arrayBuffer.byteLength, mediaData.buffer.byteLength, "arrayBuffer.byteLength before transfer.");
+
+              // Send the buffer as in a message so it gets neutered.
+              window.postMessage( "test", "*", [arrayBuffer]);
+
+              assert_equals(arrayBuffer.byteLength, 0, "arrayBuffer.byteLength after transfer.");
+
+              sourceBuffer.appendBuffer(arrayBuffer);
+
+              assert_true(sourceBuffer.updating, "updating attribute is true");
+
+              test.waitForExpectedEvents(function()
+              {
+                 assert_false(sourceBuffer.updating, "updating attribute is false");
+                 test.done();
+              });
+          }, "Test appending a neutered ArrayBuffer.");
+
+          mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
+          {
+              var initSegment = MediaSourceUtil.extractSegmentData(mediaData, segmentInfo.init);
+              var halfIndex = (initSegment.length + 1) / 2;
+              var partialInitSegment = initSegment.subarray(0, halfIndex);
+              var remainingInitSegment = initSegment.subarray(halfIndex);
+              var mediaSegment = MediaSourceUtil.extractSegmentData(mediaData, segmentInfo.media[0]);
+
+              test.expectEvent(sourceBuffer, "updateend", "partialInitSegment append ended.");
+              sourceBuffer.appendBuffer(partialInitSegment);
+
+              test.waitForExpectedEvents(function()
+              {
+                  assert_equals(mediaElement.readyState, mediaElement.HAVE_NOTHING);
+                  assert_equals(mediaSource.duration, Number.NaN);
+                  test.expectEvent(sourceBuffer, "updateend", "remainingInitSegment append ended.");
+                  test.expectEvent(mediaElement, "loadedmetadata", "loadedmetadata event received.");
+                  sourceBuffer.appendBuffer(remainingInitSegment);
+              });
+
+              test.waitForExpectedEvents(function()
+              {
+                  assert_equals(mediaElement.readyState, mediaElement.HAVE_METADATA);
+                  assert_equals(mediaSource.duration, segmentInfo.duration);
+                  test.expectEvent(sourceBuffer, "updateend", "mediaSegment append ended.");
+                  test.expectEvent(mediaElement, "loadeddata", "loadeddata fired.");
+                  sourceBuffer.appendBuffer(mediaSegment);
+              });
+
+              test.waitForExpectedEvents(function()
+              {
+                  assert_greater_than_equal(mediaElement.readyState, mediaElement.HAVE_CURRENT_DATA);
+                  assert_equals(sourceBuffer.updating, false);
+                  assert_equals(mediaSource.readyState, "open");
+                  test.done();
+              });
+          }, "Test appendBuffer with partial init segments.");
+
+          mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
+          {
+              var initSegment = MediaSourceUtil.extractSegmentData(mediaData, segmentInfo.init);
+              var mediaSegment = MediaSourceUtil.extractSegmentData(mediaData, segmentInfo.media[0]);
+              var halfIndex = (mediaSegment.length + 1) / 2;
+              var partialMediaSegment = mediaSegment.subarray(0, halfIndex);
+              var remainingMediaSegment = mediaSegment.subarray(halfIndex);
+
+              test.expectEvent(sourceBuffer, "updateend", "InitSegment append ended.");
+              test.expectEvent(mediaElement, "loadedmetadata", "loadedmetadata done.");
+              sourceBuffer.appendBuffer(initSegment);
+
+              test.waitForExpectedEvents(function()
+              {
+                  assert_equals(mediaElement.readyState, mediaElement.HAVE_METADATA);
+                  assert_equals(mediaSource.duration, segmentInfo.duration);
+                  test.expectEvent(sourceBuffer, "updateend", "partial media segment append ended.");
+                  sourceBuffer.appendBuffer(partialMediaSegment);
+              });
+
+              test.waitForExpectedEvents(function()
+              {
+                  test.expectEvent(sourceBuffer, "updateend", "mediaSegment append ended.");
+                  test.expectEvent(mediaElement, "loadeddata", "loadeddata fired.");
+                  sourceBuffer.appendBuffer(remainingMediaSegment);
+              });
+
+              test.waitForExpectedEvents(function()
+              {
+                  assert_greater_than_equal(mediaElement.readyState, mediaElement.HAVE_CURRENT_DATA);
+                  assert_equals(mediaSource.readyState, "open");
+                  assert_equals(sourceBuffer.updating, false);
+                  test.done();
+              });
+          }, "Test appendBuffer with partial media segments.");
+
+          mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
+          {
+              var initSegment = MediaSourceUtil.extractSegmentData(mediaData, segmentInfo.init);
+              var partialInitSegment = initSegment.subarray(0, initSegment.length / 2);
+              var mediaSegment = MediaSourceUtil.extractSegmentData(mediaData, segmentInfo.media[0]);
+
+              test.expectEvent(sourceBuffer, "updateend", "partialInitSegment append ended.");
+              sourceBuffer.appendBuffer(partialInitSegment);
+
+              test.waitForExpectedEvents(function()
+              {
+                  // Call abort to reset the parser.
+                  sourceBuffer.abort();
+
+                  // Append the full intiialization segment.
+                  test.expectEvent(sourceBuffer, "updateend", "initSegment append ended.");
+                  sourceBuffer.appendBuffer(initSegment);
+              });
+
+              test.waitForExpectedEvents(function()
+              {
+                  test.expectEvent(sourceBuffer, "updateend", "mediaSegment append ended.");
+                  test.expectEvent(mediaElement, "loadeddata", "loadeddata fired.");
+                  sourceBuffer.appendBuffer(mediaSegment);
+              });
+
+              test.waitForExpectedEvents(function()
+              {
+                  test.done();
+              });
+          }, "Test abort in the middle of an initialization segment.");
+
+          mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
+          {
+              test.expectEvent(mediaSource.sourceBuffers, "removesourcebuffer", "SourceBuffer removed.");
+              mediaSource.removeSourceBuffer(sourceBuffer);
+              test.waitForExpectedEvents(function()
+              {
+                  assert_throws("InvalidStateError",
+                      function() { sourceBuffer.abort(); },
+                      "sourceBuffer.abort() throws an exception for InvalidStateError.");
+
+                  test.done();
+              });
+          }, "Test abort after removing sourcebuffer.");
+
+          mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
+          {
+              var initSegment = MediaSourceUtil.extractSegmentData(mediaData, segmentInfo.init);
+              var mediaSegment = MediaSourceUtil.extractSegmentData(mediaData, segmentInfo.media[0]);
+
+              test.expectEvent(sourceBuffer, "updateend", "initSegment append ended.");
+              sourceBuffer.appendBuffer(initSegment);
+
+              test.waitForExpectedEvents(function()
+              {
+                  assert_equals(mediaSource.readyState, "open", "readyState is open after init segment appended.");
+                  test.expectEvent(sourceBuffer, "updateend", "mediaSegment append ended.");
+                  sourceBuffer.appendBuffer(mediaSegment);
+              });
+
+              test.waitForExpectedEvents(function()
+              {
+                  assert_equals(sourceBuffer.buffered.length, 1, "sourceBuffer has a buffered range");
+                  assert_equals(mediaSource.readyState, "open", "readyState is open after media segment appended.");
+                  test.expectEvent(mediaSource, "sourceended", "source ended");
+                  mediaSource.endOfStream();
+              });
+
+              test.waitForExpectedEvents(function()
+              {
+                  assert_equals(mediaSource.readyState, "ended", "readyState is ended.");
+                  assert_throws("InvalidStateError",
+                      function() { sourceBuffer.abort(); },
+                      "sourceBuffer.abort() throws an exception for InvalidStateError.");
+                  test.done();
+              });
+
+          }, "Test abort after readyState is ended following init segment and media segment.");
+
+          mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
+          {
+              test.expectEvent(sourceBuffer, "updatestart", "Append started.");
+              test.expectEvent(sourceBuffer, "updateend", "Append ended.");
+              sourceBuffer.appendWindowStart = 1;
+              sourceBuffer.appendWindowEnd = 100;
+              sourceBuffer.appendBuffer(mediaData);
+
+              test.waitForExpectedEvents(function()
+              {
+                  assert_false(sourceBuffer.updating, "updating attribute is false");
+                  sourceBuffer.abort();
+                  assert_equals(sourceBuffer.appendWindowStart, 0, "appendWindowStart is reset to 0");
+                  assert_equals(sourceBuffer.appendWindowEnd, Number.POSITIVE_INFINITY,
+                      "appendWindowEnd is reset to +INFINITY");
+                  test.done();
+              });
+          }, "Test abort after appendBuffer update ends.");
+
+          mediasource_test(function(test, mediaElement, mediaSource)
+          {
+              var sourceBuffer = mediaSource.addSourceBuffer(MediaSourceUtil.VIDEO_ONLY_TYPE);
+
+              test.expectEvent(sourceBuffer, "updatestart", "Append started.");
+              test.expectEvent(sourceBuffer, "update", "Append success.");
+              test.expectEvent(sourceBuffer, "updateend", "Append ended.");
+
+              assert_throws( { name: "TypeError"} ,
+                  function() { sourceBuffer.appendBuffer(null); },
+                  "appendBuffer(null) throws an exception.");
+              test.done();
+          }, "Test appending null.");
+
+          mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
+          {
+              mediaSource.removeSourceBuffer(sourceBuffer);
+
+              assert_throws( { name: "InvalidStateError"} ,
+                  function() { sourceBuffer.appendBuffer(mediaData); },
+                  "appendBuffer() throws an exception when called after removeSourceBuffer().");
+              test.done();
+          }, "Test appending after removeSourceBuffer().");
+
+        </script>
+    </body>
+</html>
diff --git a/src/third_party/web_platform_tests/media-source/mediasource-appendwindow.html b/src/third_party/web_platform_tests/media-source/mediasource-appendwindow.html
new file mode 100644
index 0000000..2a6fb42
--- /dev/null
+++ b/src/third_party/web_platform_tests/media-source/mediasource-appendwindow.html
@@ -0,0 +1,175 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <title>SourceBuffer.appendWindowStart and SourceBuffer.appendWindowEnd test cases.</title>
+        <script src="/resources/testharness.js"></script>
+        <script src="/resources/testharnessreport.js"></script>
+        <script src="mediasource-util.js"></script>
+    </head>
+    <body>
+        <div id="log"></div>
+        <script>
+          mediasource_test(function(test, mediaElement, mediaSource)
+          {
+              var sourceBuffer = mediaSource.addSourceBuffer(MediaSourceUtil.AUDIO_VIDEO_TYPE);
+              assert_true(sourceBuffer != null, "New SourceBuffer returned");
+
+              sourceBuffer.appendWindowStart = 100.0;
+              sourceBuffer.appendWindowEnd = 500.0;
+              assert_equals(sourceBuffer.appendWindowStart, 100.0, "appendWindowStart is correctly set'");
+              assert_equals(sourceBuffer.appendWindowEnd, 500.0, "appendWindowEnd is correctly set'");
+
+              sourceBuffer.appendWindowStart = 200.0;
+              sourceBuffer.appendWindowEnd = 400.0;
+              assert_equals(sourceBuffer.appendWindowStart, 200.0, "appendWindowStart is correctly reset'");
+              assert_equals(sourceBuffer.appendWindowEnd, 400.0, "appendWindowEnd is correctly reset'");
+              test.done();
+          }, "Test correctly reset appendWindowStart and appendWindowEnd values");
+
+          mediasource_test(function(test, mediaElement, mediaSource)
+          {
+              var sourceBuffer = mediaSource.addSourceBuffer(MediaSourceUtil.AUDIO_VIDEO_TYPE);
+              assert_true(sourceBuffer != null, "New SourceBuffer returned");
+              sourceBuffer.appendWindowEnd = 500.0;
+
+              assert_throws(new TypeError(),
+                  function() { sourceBuffer.appendWindowStart = Number.NEGATIVE_INFINITY; },
+                  "set appendWindowStart throws an exception for Number.NEGATIVE_INFINITY.");
+
+              assert_throws(new TypeError(),
+                  function() { sourceBuffer.appendWindowStart = Number.POSITIVE_INFINITY; },
+                  "set appendWindowStart throws an exception for Number.POSITIVE_INFINITY.");
+
+              assert_throws(new TypeError(),
+                  function() { sourceBuffer.appendWindowStart = Number.NaN; },
+                  "set appendWindowStart throws an exception for Number.NaN.");
+
+              assert_throws("InvalidAccessError",
+                  function() { sourceBuffer.appendWindowStart = 600.0; },
+                  "set appendWindowStart throws an exception when greater than appendWindowEnd.");
+
+              assert_throws("InvalidAccessError",
+                  function() { sourceBuffer.appendWindowStart = sourceBuffer.appendWindowEnd; },
+                  "set appendWindowStart throws an exception when equal to appendWindowEnd.");
+
+              assert_throws("InvalidAccessError",
+                  function() { sourceBuffer.appendWindowEnd = sourceBuffer.appendWindowStart; },
+                  "set appendWindowEnd throws an exception when equal to appendWindowStart.");
+
+              assert_throws("InvalidAccessError",
+                  function() { sourceBuffer.appendWindowEnd = sourceBuffer.appendWindowStart - 1; },
+                  "set appendWindowEnd throws an exception if less than appendWindowStart.");
+
+              assert_throws("InvalidAccessError",
+                  function() { sourceBuffer.appendWindowStart = -100.0; },
+                  "set appendWindowStart throws an exception when less than 0.");
+
+              assert_throws("InvalidAccessError",
+                  function() { sourceBuffer.appendWindowEnd = -100.0; },
+                  "set appendWindowEnd throws an exception when less than 0.");
+
+              assert_throws("InvalidAccessError",
+                  function() { sourceBuffer.appendWindowEnd = Number.NaN; },
+                  "set appendWindowEnd throws an exception if NaN.");
+
+              assert_throws("InvalidAccessError",
+                  function() { sourceBuffer.appendWindowEnd = undefined; },
+                  "set appendWindowEnd throws an exception if undefined.");
+
+              assert_throws({name: "TypeError"},
+                  function() { sourceBuffer.appendWindowStart = undefined; },
+                  "set appendWindowStart throws an exception if undefined.");
+
+              test.done();
+          }, "Test set wrong values to appendWindowStart and appendWindowEnd.");
+
+          mediasource_test(function(test, mediaElement, mediaSource)
+          {
+              var sourceBuffer = mediaSource.addSourceBuffer(MediaSourceUtil.AUDIO_VIDEO_TYPE);
+              assert_true(sourceBuffer != null, "New SourceBuffer returned");
+
+              sourceBuffer.appendWindowStart = "";
+              assert_true(sourceBuffer.appendWindowStart == 0, "appendWindowStart is 0");
+
+              sourceBuffer.appendWindowStart = "10";
+              assert_true(sourceBuffer.appendWindowStart == 10, "appendWindowStart is 10");
+
+              sourceBuffer.appendWindowStart = null;
+              assert_true(sourceBuffer.appendWindowStart == 0, "appendWindowStart is 0");
+
+              sourceBuffer.appendWindowStart = true;
+              assert_true(sourceBuffer.appendWindowStart == 1, "appendWindowStart is 1");
+
+              sourceBuffer.appendWindowStart = false;
+              assert_true(sourceBuffer.appendWindowStart == 0, "appendWindowStart is 0");
+
+              sourceBuffer.appendWindowEnd = "100";
+              assert_true(sourceBuffer.appendWindowEnd == 100, "appendWindowEnd is 100");
+
+              test.done();
+
+          }, "Test set correct values to appendWindowStart and appendWindowEnd.");
+
+          mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
+          {
+              mediaSource.removeSourceBuffer(sourceBuffer);
+              assert_throws("InvalidStateError",
+                  function() { sourceBuffer.appendWindowStart = 100.0; },
+                  "set appendWindowStart throws an exception when mediasource object is not associated with a buffer.");
+
+              assert_throws("InvalidStateError",
+                  function() { sourceBuffer.appendWindowEnd = 500.0; },
+                  "set appendWindowEnd throws an exception when mediasource object is not associated with a buffer.");
+              test.done();
+
+          }, "Test appendwindow throw error when mediasource object is not associated with a sourebuffer.");
+
+          mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
+          {
+              test.expectEvent(sourceBuffer, "updateend", "sourceBuffer");
+              sourceBuffer.appendBuffer(mediaData);
+              assert_true(sourceBuffer.updating, "updating attribute is true");
+
+              assert_throws("InvalidStateError",
+                  function() { sourceBuffer.appendWindowStart = 100.0; },
+                  "set appendWindowStart throws an exception when there is a pending append.");
+
+              assert_throws("InvalidStateError",
+                  function() { sourceBuffer.appendWindowEnd = 500.0; },
+                  "set appendWindowEnd throws an exception when there is a pending append.");
+
+              test.waitForExpectedEvents(function()
+              {
+                  assert_false(sourceBuffer.updating, "updating attribute is false");
+                  test.done();
+              });
+          }, "Test set appendWindowStart and appendWindowEnd when source buffer updating.");
+
+          mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
+          {
+              test.expectEvent(sourceBuffer, "updateend", "sourceBuffer");
+              sourceBuffer.appendBuffer(mediaData);
+              assert_true(sourceBuffer.updating, "updating attribute is true");
+
+              sourceBuffer.abort();
+              assert_equals(sourceBuffer.appendWindowStart, 0, "appendWindowStart is 0 after an abort'");
+              assert_equals(sourceBuffer.appendWindowEnd, Number.POSITIVE_INFINITY,
+                            "appendWindowStart is POSITIVE_INFINITY after an abort");
+              test.waitForExpectedEvents(function()
+              {
+                  assert_false(sourceBuffer.updating, "updating attribute is false");
+                  test.done();
+              });
+          }, "Test appendWindowStart and appendWindowEnd value after a sourceBuffer.abort().");
+
+          mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
+          {
+               assert_equals(sourceBuffer.appendWindowStart, 0, "appendWindowStart is 0 initially");
+               assert_equals(sourceBuffer.appendWindowEnd, Number.POSITIVE_INFINITY,
+                            "appendWindowStart is POSITIVE_INFINITY initially");
+               test.done();
+          }, "Test read appendWindowStart and appendWindowEnd initial values.");
+
+       </script>
+    </body>
+</html>
diff --git a/src/third_party/web_platform_tests/media-source/mediasource-buffered.html b/src/third_party/web_platform_tests/media-source/mediasource-buffered.html
new file mode 100644
index 0000000..4723bd6
--- /dev/null
+++ b/src/third_party/web_platform_tests/media-source/mediasource-buffered.html
@@ -0,0 +1,219 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <title>SourceBuffer.buffered test cases.</title>
+        <script src="/resources/testharness.js"></script>
+        <script src="/resources/testharnessreport.js"></script>
+        <script src="mediasource-util.js"></script>
+    </head>
+    <body>
+        <div id="log"></div>
+        <script>
+            var subType = MediaSourceUtil.getSubType(MediaSourceUtil.AUDIO_ONLY_TYPE);
+
+            var manifestFilenameA = subType + "/test-a-128k-44100Hz-1ch-manifest.json";
+            var manifestFilenameB = subType + "/test-v-128k-320x240-30fps-10kfr-manifest.json";
+
+            var expectationsA = {
+              webm: "{ [0.000, 2.023) }",
+              mp4: "{ [0.000, 2.043) }",
+            };
+
+            var expectationsB = {
+              webm: "{ [0.000, 2.001) }",
+              mp4: "{ [0.000, 2.000) }",
+            };
+
+            function mediaSourceDemuxedTest(callback, description)
+            {
+                mediasource_test(function(test, mediaElement, mediaSource)
+                {
+                    mediaElement.pause();
+                    mediaElement.addEventListener("error", test.unreached_func("Unexpected event 'error'"));
+                    mediaElement.addEventListener("ended", test.step_func_done());
+
+                    MediaSourceUtil.fetchManifestAndData(test, manifestFilenameA, function(typeA, dataA)
+                    {
+                        MediaSourceUtil.fetchManifestAndData(test, manifestFilenameB, function(typeB, dataB)
+                        {
+                            mediaSource.addSourceBuffer(typeA);
+                            mediaSource.addSourceBuffer(typeB);
+                            assert_equals(mediaSource.sourceBuffers.length, 2);
+
+                            callback(test, mediaElement, mediaSource, dataA, dataB);
+                        });
+                    });
+                }, description);
+            };
+
+            function appendData(test, mediaSource, dataA, dataB, callback)
+            {
+                var sourceBufferA = mediaSource.sourceBuffers[0];
+                var sourceBufferB = mediaSource.sourceBuffers[1];
+
+                test.expectEvent(sourceBufferA, "update");
+                test.expectEvent(sourceBufferA, "updateend");
+                sourceBufferA.appendBuffer(dataA);
+
+                test.expectEvent(sourceBufferB, "update");
+                test.expectEvent(sourceBufferB, "updateend");
+                sourceBufferB.appendBuffer(dataB);
+
+                test.waitForExpectedEvents(function()
+                {
+                     callback();
+                });
+            }
+
+            mediaSourceDemuxedTest(function(test, mediaElement, mediaSource, dataA, dataB) {
+                test.expectEvent(mediaElement, "loadedmetadata");
+                appendData(test, mediaSource, dataA, dataB, function()
+                {
+                    assertBufferedEquals(mediaSource.activeSourceBuffers[0], expectationsA[subType], "mediaSource.activeSourceBuffers[0]");
+                    assertBufferedEquals(mediaSource.activeSourceBuffers[1], expectationsB[subType], "mediaSource.activeSourceBuffers[1]");
+                    assertBufferedEquals(mediaElement, expectationsB[subType], "mediaElement.buffered");
+
+                    mediaSource.endOfStream();
+
+                    assertBufferedEquals(mediaSource.activeSourceBuffers[0], expectationsA[subType], "mediaSource.activeSourceBuffers[0]");
+                    assertBufferedEquals(mediaSource.activeSourceBuffers[1], expectationsB[subType], "mediaSource.activeSourceBuffers[1]");
+                    assertBufferedEquals(mediaElement, expectationsA[subType], "mediaElement.buffered");
+
+                    test.done();
+                });
+            }, "Demuxed content with different lengths");
+
+            mediasource_test(function(test, mediaElement, mediaSource)
+            {
+                mediaElement.pause();
+                mediaElement.addEventListener("error", test.unreached_func("Unexpected event 'error'"));
+                mediaElement.addEventListener("ended", test.step_func_done());
+
+                MediaSourceUtil.fetchManifestAndData(test, subType + "/test-av-384k-44100Hz-1ch-320x240-30fps-10kfr-manifest.json", function(type, data)
+                {
+                    var sourceBuffer = mediaSource.addSourceBuffer(type);
+                    test.expectEvent(sourceBuffer, "update");
+                    test.expectEvent(sourceBuffer, "updateend");
+                    sourceBuffer.appendBuffer(data);
+
+                    test.waitForExpectedEvents(function()
+                    {
+                        var expectationsAV = {
+                            webm: ["{ [0.000, 2.003) }", "{ [0.000, 2.023) }"],
+                            mp4: ["{ [0.000, 2.000) }", "{ [0.000, 2.043) }"],
+                        };
+
+                        var expectedBeforeEndOfStream = expectationsAV[subType][0];
+                        var expectedAfterEndOfStream = expectationsAV[subType][1];
+
+                        assertBufferedEquals(mediaSource.activeSourceBuffers[0], expectedBeforeEndOfStream, "mediaSource.activeSourceBuffers[0]");
+                        assertBufferedEquals(mediaElement, expectedBeforeEndOfStream, "mediaElement.buffered");
+
+                        mediaSource.endOfStream();
+
+                        assertBufferedEquals(mediaSource.activeSourceBuffers[0], expectedAfterEndOfStream, "mediaSource.activeSourceBuffers[0]");
+                        assertBufferedEquals(mediaElement, expectedAfterEndOfStream, "mediaElement.buffered");
+
+                        test.done();
+                    });
+                });
+            }, "Muxed content with different lengths");
+
+            mediaSourceDemuxedTest(function(test, mediaElement, mediaSource, dataA, dataB) {
+                var dataBSize = {
+                    webm: 318,
+                    mp4: 835,
+                };
+                test.expectEvent(mediaElement, "loadedmetadata");
+                appendData(test, mediaSource, dataA, dataB.subarray(0, dataBSize[subType]), function()
+                {
+                    assertBufferedEquals(mediaSource.activeSourceBuffers[0], expectationsA[subType], "mediaSource.activeSourceBuffers[0]");
+                    assertBufferedEquals(mediaSource.activeSourceBuffers[1], "{ }", "mediaSource.activeSourceBuffers[1]");
+                    assertBufferedEquals(mediaElement, "{ }", "mediaElement.buffered");
+
+                    mediaSource.endOfStream();
+
+                    assertBufferedEquals(mediaSource.activeSourceBuffers[0], expectationsA[subType], "mediaSource.activeSourceBuffers[0]");
+                    assertBufferedEquals(mediaSource.activeSourceBuffers[1], "{ }", "mediaSource.activeSourceBuffers[1]");
+                    assertBufferedEquals(mediaElement, "{ }", "mediaElement.buffered");
+
+                    test.done();
+                });
+            }, "Demuxed content with an empty buffered range on one SourceBuffer");
+
+            mediasource_test(function(test, mediaElement, mediaSource)
+            {
+                mediaElement.pause();
+                mediaElement.addEventListener("error", test.unreached_func("Unexpected event 'error'"));
+                mediaElement.addEventListener("ended", test.step_func_done());
+
+                MediaSourceUtil.fetchManifestAndData(test, subType + "/test-av-384k-44100Hz-1ch-320x240-30fps-10kfr-manifest.json", function(type, data)
+                {
+                    var sourceBuffer = mediaSource.addSourceBuffer(type);
+                    test.expectEvent(mediaElement, "loadedmetadata");
+                    test.expectEvent(sourceBuffer, "update");
+                    test.expectEvent(sourceBuffer, "updateend");
+                    sourceBuffer.appendBuffer(data.subarray(0, 4052));
+
+                    test.waitForExpectedEvents(function()
+                    {
+                        assertBufferedEquals(mediaSource.activeSourceBuffers[0], "{ }", "mediaSource.activeSourceBuffers[0]");
+                        assertBufferedEquals(mediaElement, "{ }", "mediaElement.buffered");
+
+                        mediaSource.endOfStream();
+
+                        assertBufferedEquals(mediaSource.activeSourceBuffers[0], "{ }", "mediaSource.activeSourceBuffers[0]");
+                        assertBufferedEquals(mediaElement, "{ }", "mediaElement.buffered");
+
+                        test.done();
+                    });
+                });
+            }, "Muxed content empty buffered ranges.");
+
+            mediasource_test(function(test, mediaElement, mediaSource)
+            {
+                mediaElement.pause();
+                mediaElement.addEventListener("error", test.unreached_func("Unexpected event 'error'"));
+                mediaElement.addEventListener("ended", test.step_func_done());
+
+                var sourceBuffer = mediaSource.addSourceBuffer(MediaSourceUtil.AUDIO_ONLY_TYPE);
+
+                assertBufferedEquals(mediaSource.sourceBuffers[0], "{ }", "mediaSource.sourceBuffers[0]");
+                assertBufferedEquals(mediaElement, "{ }", "mediaElement.buffered");
+                test.done();
+
+            }, "Get buffered range when sourcebuffer is empty.");
+
+            mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
+            {
+                var initSegment = MediaSourceUtil.extractSegmentData(mediaData, segmentInfo.init);
+
+                test.expectEvent(mediaElement, "loadedmetadata");
+                test.expectEvent(sourceBuffer, "updateend", "initSegment append ended.");
+                sourceBuffer.appendBuffer(initSegment);
+                test.waitForExpectedEvents(function()
+                {
+                    assertBufferedEquals(mediaSource.sourceBuffers[0], "{ }", "mediaSource.sourceBuffers[0]");
+                    assertBufferedEquals(mediaSource.activeSourceBuffers[0], "{ }", "mediaSource.activeSourceBuffers[0]");
+                    assertBufferedEquals(mediaElement, "{ }", "mediaElement.buffered");
+                    test.done();
+                });
+
+            }, "Get buffered range when only init segment is appended.");
+
+            mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
+            {
+                test.expectEvent(mediaSource.sourceBuffers, "removesourcebuffer", "SourceBuffer removed.");
+                mediaSource.removeSourceBuffer(sourceBuffer);
+
+                test.waitForExpectedEvents(function()
+                {
+                    assert_throws("InvalidStateError",
+                        function() { sourceBuffer.buffered; },
+                        "get sourceBuffer.buffered throws an exception for InvalidStateError.");
+                    test.done();
+                });
+            }, "Get buffered range after removing sourcebuffer.");
+        </script>
+    </body>
+</html>
diff --git a/src/third_party/web_platform_tests/media-source/mediasource-closed.html b/src/third_party/web_platform_tests/media-source/mediasource-closed.html
new file mode 100644
index 0000000..4f0dcca
--- /dev/null
+++ b/src/third_party/web_platform_tests/media-source/mediasource-closed.html
@@ -0,0 +1,139 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <title>MediaSource.readyState equals "closed" test cases.</title>
+        <script src="/resources/testharness.js"></script>
+        <script src="/resources/testharnessreport.js"></script>
+        <script src="mediasource-util.js"></script>
+    </head>
+    <body>
+        <div id="log"></div>
+        <script>
+          test(function ()
+          {
+              var mediaSource = new MediaSource();
+              assert_equals(mediaSource.sourceBuffers.length, 0, "sourceBuffers is empty");
+              assert_equals(mediaSource.activeSourceBuffers.length, 0, "activeSourceBuffers is empty");
+              assert_equals(mediaSource.readyState, "closed", "readyState is 'closed'");
+              assert_true(isNaN(mediaSource.duration), "duration is NaN");
+          }, "Test attribute values on a closed MediaSource object.");
+
+          test(function ()
+          {
+              var mediaSource = new MediaSource();
+              assert_throws("InvalidStateError",
+                  function() { mediaSource.addSourceBuffer(MediaSourceUtil.VIDEO_ONLY_TYPE); },
+                  "addSourceBuffer() throws an exception when closed.");
+          }, "Test addSourceBuffer() while closed.");
+
+          mediasource_test(function(test, mediaElement, mediaSource)
+          {
+              var sourceBuffer = mediaSource.addSourceBuffer(MediaSourceUtil.AUDIO_ONLY_TYPE);
+
+              // Setup a handler to run when the MediaSource closes.
+              mediaSource.addEventListener('sourceclose', test.step_func(function (event)
+              {
+                  assert_equals(mediaSource.sourceBuffers.length, 0, "sourceBuffers is empty");
+                  assert_equals(mediaSource.activeSourceBuffers.length, 0, "activeSourceBuffers is empty");
+                  assert_equals(mediaSource.readyState, "closed", "readyState is 'closed'");
+                  assert_throws("NotFoundError",
+                      function() { mediaSource.removeSourceBuffer(sourceBuffer); },
+                      "removeSourceBuffer() throws an exception when closed.");
+                  test.done();
+              }));
+
+              // Trigger the MediaSource to close.
+              mediaElement.src = "";
+          }, "Test removeSourceBuffer() while closed.");
+
+          test(function ()
+          {
+              var mediaSource = new MediaSource();
+              assert_throws("InvalidStateError",
+                  function() { mediaSource.endOfStream(); },
+                  "endOfStream() throws an exception when closed.");
+          }, "Test endOfStream() while closed.");
+
+          test(function ()
+          {
+              var mediaSource = new MediaSource();
+              assert_throws("InvalidStateError",
+                  function() { mediaSource.endOfStream("decode"); },
+                  "endOfStream(decode) throws an exception when closed.");
+          }, "Test endOfStream(decode) while closed.");
+
+          test(function ()
+          {
+              var mediaSource = new MediaSource();
+              assert_throws("InvalidStateError",
+                  function() { mediaSource.endOfStream("network"); },
+                  "endOfStream(network) throws an exception when closed.");
+          }, "Test endOfStream(network) while closed.");
+
+          test(function ()
+          {
+              var mediaSource = new MediaSource();
+              assert_throws("InvalidStateError",
+                  function() { mediaSource.duration = 10; },
+                  "Setting duration throws an exception when closed.");
+          }, "Test setting duration while closed.");
+
+          mediasource_test(function(test, mediaElement, mediaSource)
+          {
+              var sourceBuffer = mediaSource.addSourceBuffer(MediaSourceUtil.AUDIO_ONLY_TYPE);
+
+              assert_equals(mediaSource.readyState, "open", "readyState is 'open'");
+              // Setup a handler to run when the MediaSource closes.
+              mediaSource.addEventListener("sourceclose", test.step_func(function (event)
+              {
+                  assert_equals(mediaSource.readyState, "closed", "readyState is 'closed'");
+                  assert_throws("InvalidStateError",
+                      function() { mediaSource.duration = 10; },
+                      "Setting duration when closed throws an exception");
+                  test.done();
+              }));
+
+              // Trigger the MediaSource to close.
+              mediaElement.src = "";
+          }, "Test setting duration while open->closed.");
+
+           mediasource_test(function(test, mediaElement, mediaSource)
+          {
+              var sourceBuffer = mediaSource.addSourceBuffer(MediaSourceUtil.AUDIO_ONLY_TYPE);
+
+              assert_equals(mediaSource.readyState, "open", "readyState is 'open'");
+              // Setup a handler to run when the MediaSource closes.
+              mediaSource.addEventListener("sourceclose", test.step_func(function (event)
+              {
+                  assert_equals(mediaSource.readyState, "closed", "readyState is 'closed'");
+                  assert_true(isNaN(mediaSource.duration), "duration is NaN");
+                  test.done();
+              }));
+
+              // Trigger the MediaSource to close.
+              mediaElement.src = "";
+          }, "Test getting duration while open->closed.");
+
+          mediasource_test(function(test, mediaElement, mediaSource)
+          {
+              var sourceBuffer = mediaSource.addSourceBuffer(MediaSourceUtil.AUDIO_ONLY_TYPE);
+
+              assert_equals(mediaSource.readyState, "open", "readyState is open");
+
+              // Setup a handler to run when the MediaSource closes.
+              mediaSource.addEventListener("sourceclose", test.step_func(function (event)
+              {
+                  assert_equals(mediaSource.readyState, "closed", "readyState is closed");
+                  assert_throws("InvalidStateError",
+                    function() { sourceBuffer.abort(); },
+                    "sourceBuffer.abort() throws INVALID_STATE_ERROR");
+                  test.done();
+              }));
+
+              // Trigger the MediaSource to close.
+              mediaElement.src = "";
+          }, "Test sourcebuffer.abort when closed.");
+
+        </script>
+    </body>
+</html>
diff --git a/src/third_party/web_platform_tests/media-source/mediasource-config-change-mp4-a-bitrate.html b/src/third_party/web_platform_tests/media-source/mediasource-config-change-mp4-a-bitrate.html
new file mode 100644
index 0000000..865fadd
--- /dev/null
+++ b/src/third_party/web_platform_tests/media-source/mediasource-config-change-mp4-a-bitrate.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <title>MP4 audio-only bitrate change.</title>
+        <script src="/resources/testharness.js"></script>
+        <script src="/resources/testharnessreport.js"></script>
+        <script src="mediasource-util.js"></script>
+        <script src="mediasource-config-changes.js"></script>
+    </head>
+    <body>
+        <div id="log"></div>
+        <script>
+            mediaSourceConfigChangeTest("mp4", "a-128k-44100Hz-1ch", "a-192k-44100Hz-1ch", "Tests mp4 audio-only bitrate changes.");
+        </script>
+    </body>
+</html>
diff --git a/src/third_party/web_platform_tests/media-source/mediasource-config-change-mp4-av-audio-bitrate.html b/src/third_party/web_platform_tests/media-source/mediasource-config-change-mp4-av-audio-bitrate.html
new file mode 100644
index 0000000..75d6e41
--- /dev/null
+++ b/src/third_party/web_platform_tests/media-source/mediasource-config-change-mp4-av-audio-bitrate.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <title>MP4 muxed audio &amp; video with an audio bitrate change.</title>
+        <script src="/resources/testharness.js"></script>
+        <script src="/resources/testharnessreport.js"></script>
+        <script src="mediasource-util.js"></script>
+        <script src="mediasource-config-changes.js"></script>
+    </head>
+    <body>
+        <div id="log"></div>
+        <script>
+            mediaSourceConfigChangeTest("mp4", "av-384k-44100Hz-1ch-640x480-30fps-10kfr", "av-448k-44100Hz-1ch-640x480-30fps-10kfr", "Tests mp4 audio bitrate changes in multiplexed content.");
+        </script>
+    </body>
+</html>
diff --git a/src/third_party/web_platform_tests/media-source/mediasource-config-change-mp4-av-framesize.html b/src/third_party/web_platform_tests/media-source/mediasource-config-change-mp4-av-framesize.html
new file mode 100644
index 0000000..33dd51a
--- /dev/null
+++ b/src/third_party/web_platform_tests/media-source/mediasource-config-change-mp4-av-framesize.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <title>MP4 muxed audio &amp; video with a video frame size change.</title>
+        <script src="/resources/testharness.js"></script>
+        <script src="/resources/testharnessreport.js"></script>
+        <script src="mediasource-util.js"></script>
+        <script src="mediasource-config-changes.js"></script>
+    </head>
+    <body>
+        <div id="log"></div>
+        <script>
+            mediaSourceConfigChangeTest("mp4", "av-384k-44100Hz-1ch-320x240-30fps-10kfr", "av-384k-44100Hz-1ch-640x480-30fps-10kfr", "Tests mp4 frame size changes in multiplexed content.");
+        </script>
+    </body>
+</html>
diff --git a/src/third_party/web_platform_tests/media-source/mediasource-config-change-mp4-av-video-bitrate.html b/src/third_party/web_platform_tests/media-source/mediasource-config-change-mp4-av-video-bitrate.html
new file mode 100644
index 0000000..fce3555
--- /dev/null
+++ b/src/third_party/web_platform_tests/media-source/mediasource-config-change-mp4-av-video-bitrate.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <title>MP4 muxed audio &amp; video with a video bitrate change.</title>
+        <script src="/resources/testharness.js"></script>
+        <script src="/resources/testharnessreport.js"></script>
+        <script src="mediasource-util.js"></script>
+        <script src="mediasource-config-changes.js"></script>
+    </head>
+    <body>
+        <div id="log"></div>
+        <script>
+            mediaSourceConfigChangeTest("mp4", "av-384k-44100Hz-1ch-640x480-30fps-10kfr", "av-640k-44100Hz-1ch-640x480-30fps-10kfr", "Tests mp4 video bitrate changes in multiplexed content.");
+        </script>
+    </body>
+</html>
diff --git a/src/third_party/web_platform_tests/media-source/mediasource-config-change-mp4-v-bitrate.html b/src/third_party/web_platform_tests/media-source/mediasource-config-change-mp4-v-bitrate.html
new file mode 100644
index 0000000..ce1977a
--- /dev/null
+++ b/src/third_party/web_platform_tests/media-source/mediasource-config-change-mp4-v-bitrate.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <title>MP4 video-only bitrate change.</title>
+        <script src="/resources/testharness.js"></script>
+        <script src="/resources/testharnessreport.js"></script>
+        <script src="mediasource-util.js"></script>
+        <script src="mediasource-config-changes.js"></script>
+    </head>
+    <body>
+        <div id="log"></div>
+        <script>
+            mediaSourceConfigChangeTest("mp4", "v-128k-320x240-30fps-10kfr", "v-256k-320x240-30fps-10kfr", "Tests mp4 video-only bitrate changes.");
+        </script>
+    </body>
+</html>
diff --git a/src/third_party/web_platform_tests/media-source/mediasource-config-change-mp4-v-framerate.html b/src/third_party/web_platform_tests/media-source/mediasource-config-change-mp4-v-framerate.html
new file mode 100644
index 0000000..65266c4
--- /dev/null
+++ b/src/third_party/web_platform_tests/media-source/mediasource-config-change-mp4-v-framerate.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <title>MP4 video-only frame rate change.</title>
+        <script src="/resources/testharness.js"></script>
+        <script src="/resources/testharnessreport.js"></script>
+        <script src="mediasource-util.js"></script>
+        <script src="mediasource-config-changes.js"></script>
+    </head>
+    <body>
+        <div id="log"></div>
+        <script>
+            mediaSourceConfigChangeTest("mp4", "v-128k-320x240-24fps-8kfr", "v-128k-320x240-30fps-10kfr", "Tests mp4 video-only frame rate changes.");
+        </script>
+    </body>
+</html>
diff --git a/src/third_party/web_platform_tests/media-source/mediasource-config-change-mp4-v-framesize.html b/src/third_party/web_platform_tests/media-source/mediasource-config-change-mp4-v-framesize.html
new file mode 100644
index 0000000..5005903
--- /dev/null
+++ b/src/third_party/web_platform_tests/media-source/mediasource-config-change-mp4-v-framesize.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <title>MP4 video-only frame size change.</title>
+        <script src="/resources/testharness.js"></script>
+        <script src="/resources/testharnessreport.js"></script>
+        <script src="mediasource-util.js"></script>
+        <script src="mediasource-config-changes.js"></script>
+    </head>
+    <body>
+        <div id="log"></div>
+        <script>
+            mediaSourceConfigChangeTest("mp4", "v-128k-320x240-30fps-10kfr", "v-128k-640x480-30fps-10kfr", "Tests mp4 video-only frame size changes.");
+        </script>
+    </body>
+</html>
diff --git a/src/third_party/web_platform_tests/media-source/mediasource-config-change-webm-a-bitrate.html b/src/third_party/web_platform_tests/media-source/mediasource-config-change-webm-a-bitrate.html
new file mode 100644
index 0000000..99f661e
--- /dev/null
+++ b/src/third_party/web_platform_tests/media-source/mediasource-config-change-webm-a-bitrate.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <title>WebM audio-only bitrate change.</title>
+        <script src="/resources/testharness.js"></script>
+        <script src="/resources/testharnessreport.js"></script>
+        <script src="mediasource-util.js"></script>
+        <script src="mediasource-config-changes.js"></script>
+    </head>
+    <body>
+        <div id="log"></div>
+        <script>
+            mediaSourceConfigChangeTest("webm", "a-128k-44100Hz-1ch", "a-192k-44100Hz-1ch", "Tests webm audio-only bitrate changes.");
+        </script>
+    </body>
+</html>
diff --git a/src/third_party/web_platform_tests/media-source/mediasource-config-change-webm-av-audio-bitrate.html b/src/third_party/web_platform_tests/media-source/mediasource-config-change-webm-av-audio-bitrate.html
new file mode 100644
index 0000000..e3acc98
--- /dev/null
+++ b/src/third_party/web_platform_tests/media-source/mediasource-config-change-webm-av-audio-bitrate.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <title>WebM muxed audio &amp; video with an audio bitrate change.</title>
+        <script src="/resources/testharness.js"></script>
+        <script src="/resources/testharnessreport.js"></script>
+        <script src="mediasource-util.js"></script>
+        <script src="mediasource-config-changes.js"></script>
+    </head>
+    <body>
+        <div id="log"></div>
+        <script>
+            mediaSourceConfigChangeTest("webm", "av-384k-44100Hz-1ch-640x480-30fps-10kfr", "av-448k-44100Hz-1ch-640x480-30fps-10kfr", "Tests webm audio bitrate changes in multiplexed content.");
+        </script>
+    </body>
+</html>
diff --git a/src/third_party/web_platform_tests/media-source/mediasource-config-change-webm-av-framesize.html b/src/third_party/web_platform_tests/media-source/mediasource-config-change-webm-av-framesize.html
new file mode 100644
index 0000000..875bda4
--- /dev/null
+++ b/src/third_party/web_platform_tests/media-source/mediasource-config-change-webm-av-framesize.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <title>WebM muxed audio &amp; video with a video frame size change.</title>
+        <script src="/resources/testharness.js"></script>
+        <script src="/resources/testharnessreport.js"></script>
+        <script src="mediasource-util.js"></script>
+        <script src="mediasource-config-changes.js"></script>
+    </head>
+    <body>
+        <div id="log"></div>
+        <script>
+            mediaSourceConfigChangeTest("webm", "av-384k-44100Hz-1ch-320x240-30fps-10kfr", "av-384k-44100Hz-1ch-640x480-30fps-10kfr", "Tests webm frame size changes in multiplexed content.");
+        </script>
+    </body>
+</html>
diff --git a/src/third_party/web_platform_tests/media-source/mediasource-config-change-webm-av-video-bitrate.html b/src/third_party/web_platform_tests/media-source/mediasource-config-change-webm-av-video-bitrate.html
new file mode 100644
index 0000000..ca2e620
--- /dev/null
+++ b/src/third_party/web_platform_tests/media-source/mediasource-config-change-webm-av-video-bitrate.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <title>WebM muxed audio &amp; video with a video bitrate change.</title>
+        <script src="/resources/testharness.js"></script>
+        <script src="/resources/testharnessreport.js"></script>
+        <script src="mediasource-util.js"></script>
+        <script src="mediasource-config-changes.js"></script>
+    </head>
+    <body>
+        <div id="log"></div>
+        <script>
+            mediaSourceConfigChangeTest("webm", "av-384k-44100Hz-1ch-640x480-30fps-10kfr", "av-640k-44100Hz-1ch-640x480-30fps-10kfr", "Tests webm video bitrate changes in multiplexed content.");
+        </script>
+    </body>
+</html>
diff --git a/src/third_party/web_platform_tests/media-source/mediasource-config-change-webm-v-bitrate.html b/src/third_party/web_platform_tests/media-source/mediasource-config-change-webm-v-bitrate.html
new file mode 100644
index 0000000..c17f5ae
--- /dev/null
+++ b/src/third_party/web_platform_tests/media-source/mediasource-config-change-webm-v-bitrate.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <title>WebM video-only bitrate change.</title>
+        <script src="/resources/testharness.js"></script>
+        <script src="/resources/testharnessreport.js"></script>
+        <script src="mediasource-util.js"></script>
+        <script src="mediasource-config-changes.js"></script>
+    </head>
+    <body>
+        <div id="log"></div>
+        <script>
+            mediaSourceConfigChangeTest("webm", "v-128k-320x240-30fps-10kfr", "v-256k-320x240-30fps-10kfr", "Tests webm video-only bitrate changes.");
+        </script>
+    </body>
+</html>
diff --git a/src/third_party/web_platform_tests/media-source/mediasource-config-change-webm-v-framerate.html b/src/third_party/web_platform_tests/media-source/mediasource-config-change-webm-v-framerate.html
new file mode 100644
index 0000000..d66de06
--- /dev/null
+++ b/src/third_party/web_platform_tests/media-source/mediasource-config-change-webm-v-framerate.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <title>WebM video-only frame rate change.</title>
+        <script src="/resources/testharness.js"></script>
+        <script src="/resources/testharnessreport.js"></script>
+        <script src="mediasource-util.js"></script>
+        <script src="mediasource-config-changes.js"></script>
+    </head>
+    <body>
+        <div id="log"></div>
+        <script>
+            mediaSourceConfigChangeTest("webm", "v-128k-320x240-24fps-8kfr", "v-128k-320x240-30fps-10kfr", "Tests webm video-only frame rate changes.");
+        </script>
+    </body>
+</html>
diff --git a/src/third_party/web_platform_tests/media-source/mediasource-config-change-webm-v-framesize.html b/src/third_party/web_platform_tests/media-source/mediasource-config-change-webm-v-framesize.html
new file mode 100644
index 0000000..cd17671
--- /dev/null
+++ b/src/third_party/web_platform_tests/media-source/mediasource-config-change-webm-v-framesize.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <title>WebM video-only frame size change.</title>
+        <script src="/resources/testharness.js"></script>
+        <script src="/resources/testharnessreport.js"></script>
+        <script src="mediasource-util.js"></script>
+        <script src="mediasource-config-changes.js"></script>
+    </head>
+    <body>
+        <div id="log"></div>
+        <script>
+            mediaSourceConfigChangeTest("webm", "v-128k-320x240-30fps-10kfr", "v-128k-640x480-30fps-10kfr", "Tests webm video-only frame size changes.");
+        </script>
+    </body>
+</html>
diff --git a/src/third_party/web_platform_tests/media-source/mediasource-config-changes.js b/src/third_party/web_platform_tests/media-source/mediasource-config-changes.js
new file mode 100644
index 0000000..857bfb9
--- /dev/null
+++ b/src/third_party/web_platform_tests/media-source/mediasource-config-changes.js
@@ -0,0 +1,101 @@
+// Extract & return the resolution string from a filename, if any.
+function resolutionFromFilename(filename)
+{
+    resolution = filename.replace(/^.*[^0-9]([0-9]+x[0-9]+)[^0-9].*$/, "$1");
+    if (resolution != filename) {
+        return resolution;
+    }
+    return "";
+}
+
+function appendBuffer(test, sourceBuffer, data)
+{
+    test.expectEvent(sourceBuffer, "update");
+    test.expectEvent(sourceBuffer, "updateend");
+    sourceBuffer.appendBuffer(data);
+}
+
+function mediaSourceConfigChangeTest(directory, idA, idB, description)
+{
+    var manifestFilenameA = directory + "/test-" + idA + "-manifest.json";
+    var manifestFilenameB = directory + "/test-" + idB + "-manifest.json";
+    mediasource_test(function(test, mediaElement, mediaSource)
+    {
+        mediaElement.pause();
+        mediaElement.addEventListener('error', test.unreached_func("Unexpected event 'error'"));
+        var expectResizeEvents = resolutionFromFilename(manifestFilenameA) != resolutionFromFilename(manifestFilenameB);
+        var expectedResizeEventCount = 0;
+
+        MediaSourceUtil.fetchManifestAndData(test, manifestFilenameA, function(typeA, dataA)
+        {
+            MediaSourceUtil.fetchManifestAndData(test, manifestFilenameB, function(typeB, dataB)
+            {
+                assert_equals(typeA, typeB, "Media format types match");
+
+                var sourceBuffer = mediaSource.addSourceBuffer(typeA);
+
+                appendBuffer(test, sourceBuffer, dataA);
+                ++expectedResizeEventCount;
+
+                test.waitForExpectedEvents(function()
+                {
+                    // Add the second buffer starting at 0.5 second.
+                    sourceBuffer.timestampOffset = 0.5;
+                    appendBuffer(test, sourceBuffer, dataB);
+                    ++expectedResizeEventCount;
+                });
+
+                test.waitForExpectedEvents(function()
+                {
+                    // Add the first buffer starting at 1 second.
+                    sourceBuffer.timestampOffset = 1;
+                    appendBuffer(test, sourceBuffer, dataA);
+                    ++expectedResizeEventCount;
+                });
+
+                test.waitForExpectedEvents(function()
+                {
+                    // Add the second buffer starting at 1.5 second.
+                    sourceBuffer.timestampOffset = 1.5;
+                    appendBuffer(test, sourceBuffer, dataB);
+                    ++expectedResizeEventCount;
+                });
+
+                test.waitForExpectedEvents(function()
+                {
+                    assert_false(sourceBuffer.updating, "updating");
+                    assert_greater_than(mediaSource.duration, 2, "duration");
+
+                    // Truncate the presentation to a duration of 2 seconds.
+                    mediaSource.duration = 2;
+
+                    assert_true(sourceBuffer.updating, "updating");
+                    test.expectEvent(sourceBuffer, 'updatestart', 'sourceBuffer');
+                    test.expectEvent(sourceBuffer, 'update', 'sourceBuffer');
+                    test.expectEvent(sourceBuffer, 'updateend', 'sourceBuffer');
+                });
+
+                test.waitForExpectedEvents(function()
+                {
+                    assert_false(sourceBuffer.updating, "updating");
+
+                    mediaSource.endOfStream();
+
+                    assert_false(sourceBuffer.updating, "updating");
+
+                    if (expectResizeEvents) {
+                        for (var i = 0; i < expectedResizeEventCount; ++i) {
+                            test.expectEvent(mediaElement, "resize");
+                        }
+                    }
+                    test.expectEvent(mediaElement, "ended");
+                    mediaElement.play();
+                });
+
+                test.waitForExpectedEvents(function() {
+                    test.done();
+                });
+            });
+        });
+    }, description);
+};
diff --git a/src/third_party/web_platform_tests/media-source/mediasource-duration-boundaryconditions.html b/src/third_party/web_platform_tests/media-source/mediasource-duration-boundaryconditions.html
new file mode 100644
index 0000000..4521fd0
--- /dev/null
+++ b/src/third_party/web_platform_tests/media-source/mediasource-duration-boundaryconditions.html
@@ -0,0 +1,62 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <title>MediaSource.duration boundary condition test cases.</title>
+        <script src="/resources/testharness.js"></script>
+        <script src="/resources/testharnessreport.js"></script>
+        <script src="mediasource-util.js"></script>
+    </head>
+    <body>
+        <div id="log"></div>
+        <script>
+          function DurationBoundaryConditionTest(testDurationValue, expectedError, description)
+          {
+              return mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
+              {
+                  // Append initialization segment.
+                  test.expectEvent(sourceBuffer, "updateend", "sourceBuffer");
+                  test.expectEvent(mediaElement, "loadedmetadata", "mediaElement");
+                  sourceBuffer.appendBuffer(MediaSourceUtil.extractSegmentData(mediaData, segmentInfo.init));
+                  test.waitForExpectedEvents(function()
+                  {
+                      if (expectedError) {
+                          assert_throws(expectedError,
+                              function() { mediaSource.duration = testDurationValue; },
+                              "mediaSource.duration assignment throws an exception for " + testDurationValue);
+                          test.done();
+                          return;
+                      }
+
+                      mediaSource.duration = testDurationValue;
+
+                      assert_equals(mediaSource.duration, testDurationValue, "mediaSource.duration");
+                      assert_equals(mediaElement.duration, testDurationValue, "mediaElement.duration");
+
+                      test.expectEvent(mediaElement, "durationchange", "mediaElement");
+                      test.waitForExpectedEvents(function()
+                      {
+                          assert_equals(mediaSource.duration, testDurationValue, "mediaSource.duration");
+                          assert_equals(mediaElement.duration, testDurationValue, "mediaElement.duration");
+                          test.done();
+                      });
+                  });
+
+              }, description);
+          }
+
+          DurationBoundaryConditionTest(Math.pow(2, 31) - 1, null, "Set duration to 2^31 - 1");
+          DurationBoundaryConditionTest(1, null, "Set duration to 1");
+          DurationBoundaryConditionTest(Number.MAX_VALUE, null, "Set duration to Number.MAX_VALUE");
+          DurationBoundaryConditionTest(Number.MIN_VALUE, null, "Set duration to Number.MIN_VALUE");
+          DurationBoundaryConditionTest(Number.MAX_VALUE - 1, null, "Set duration to Number.MAX_VALUE - 1");
+          DurationBoundaryConditionTest(Number.MIN_VALUE - 1, "InvalidAccessError", "Set duration to Number.MIN_VALUE - 1");
+          DurationBoundaryConditionTest(Number.POSITIVE_INFINITY, null, "Set duration to Number.POSITIVE_INFINITY");
+          DurationBoundaryConditionTest(Number.NEGATIVE_INFINITY, "InvalidAccessError", "Set duration to Number.NEGATIVE_INFINITY");
+          DurationBoundaryConditionTest(-1 * Number.MAX_VALUE, "InvalidAccessError", "Set duration to lowest value.");
+          DurationBoundaryConditionTest(-101.9, "InvalidAccessError", "Set duration to a negative double.");
+          DurationBoundaryConditionTest(101.9, null, "Set duration to a positive double.");
+          DurationBoundaryConditionTest(0, null, "Set duration to zero");
+          DurationBoundaryConditionTest(NaN, "InvalidAccessError", "Set duration to NaN");
+        </script>
+    </body>
+</html>
diff --git a/src/third_party/web_platform_tests/media-source/mediasource-duration.html b/src/third_party/web_platform_tests/media-source/mediasource-duration.html
new file mode 100644
index 0000000..c0a33f3
--- /dev/null
+++ b/src/third_party/web_platform_tests/media-source/mediasource-duration.html
@@ -0,0 +1,217 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <title>MediaSource.duration &amp; HTMLMediaElement.duration test cases.</title>
+        <script src="/resources/testharness.js"></script>
+        <script src="/resources/testharnessreport.js"></script>
+        <script src="mediasource-util.js"></script>
+    </head>
+    <body>
+        <div id="log"></div>
+        <script>
+          function mediasource_truncated_duration_seek_test(testFunction, description, options)
+          {
+              return mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
+              {
+                  assert_greater_than(segmentInfo.duration, 2, 'Sufficient test media duration');
+
+                  var fullDuration = segmentInfo.duration;
+                  var seekTo = fullDuration / 2.0;
+                  var truncatedDuration = seekTo / 2.0;
+
+                  mediaElement.play();
+
+                  // Append all the segments
+                  test.expectEvent(sourceBuffer, 'updateend', 'sourceBuffer');
+                  test.expectEvent(mediaElement, 'playing', 'Playing triggered');
+                  sourceBuffer.appendBuffer(mediaData);
+
+                  test.waitForExpectedEvents(function()
+                  {
+                      assert_equals(mediaElement.duration, fullDuration, 'mediaElement fullDuration');
+                      assert_equals(mediaSource.duration, fullDuration, 'mediaSource fullDuration');
+
+                      test.expectEvent(mediaElement, 'seeking', 'seeking to seekTo');
+                      test.expectEvent(mediaElement, 'timeupdate', 'timeupdate while seeking to seekTo');
+                      test.expectEvent(mediaElement, 'seeked', 'seeked to seekTo');
+                      mediaElement.currentTime = seekTo;
+                      assert_true(mediaElement.seeking, 'mediaElement.seeking (to seekTo)');
+                  });
+
+                  test.waitForExpectedEvents(function()
+                  {
+                      assert_greater_than_equal(mediaElement.currentTime, seekTo, 'Playback time has reached seekTo');
+                      assert_equals(mediaElement.duration, fullDuration, 'mediaElement fullDuration after seekTo');
+                      assert_equals(mediaSource.duration, fullDuration, 'mediaSource fullDuration after seekTo');
+                      assert_false(mediaElement.seeking, 'mediaElement.seeking after seeked to seekTo');
+
+                      test.expectEvent(mediaElement, 'seeking', 'Seeking to truncated duration');
+
+                      assert_false(sourceBuffer.updating, 'sourceBuffer.updating');
+
+                      mediaSource.duration = truncatedDuration;
+
+                      assert_true(sourceBuffer.updating, 'sourceBuffer.updating');
+                      test.expectEvent(sourceBuffer, 'updatestart', 'sourceBuffer');
+                      test.expectEvent(sourceBuffer, 'update', 'sourceBuffer');
+                      test.expectEvent(sourceBuffer, 'updateend', 'sourceBuffer');
+
+                      assert_true(mediaElement.seeking, 'Seeking after setting truncatedDuration');
+                  });
+
+                  test.waitForExpectedEvents(function()
+                  {
+                      assert_equals(mediaElement.currentTime, truncatedDuration,
+                                    'Playback time is truncatedDuration while seeking');
+                      assert_true(mediaElement.seeking, 'mediaElement.seeking while seeking to truncatedDuration');
+                      assert_equals(mediaElement.duration, truncatedDuration,
+                                    'mediaElement truncatedDuration during seek to it');
+                      assert_equals(mediaSource.duration, truncatedDuration,
+                                    'mediaSource truncatedDuration during seek to it');
+
+                      testFunction(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData,
+                                   truncatedDuration);
+                  });
+              }, description, options);
+          }
+
+          mediasource_truncated_duration_seek_test(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer,
+                                                            mediaData, truncatedDuration)
+          {
+              // Tests that duration truncation below current playback position
+              // starts seek to new duration.
+              test.done();
+          }, 'Test seek starts on duration truncation below currentTime');
+
+          mediasource_truncated_duration_seek_test(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer,
+                                                            mediaData, truncatedDuration)
+          {
+              // The duration has been truncated at this point, and there is an
+              // outstanding seek pending.
+              test.expectEvent(sourceBuffer, 'updateend', 'updateend after appending more data');
+
+              test.expectEvent(mediaElement, 'timeupdate', 'timeupdate while finishing seek to truncatedDuration');
+              test.expectEvent(mediaElement, 'seeked', 'seeked to truncatedDuration');
+
+              // Allow seek to complete by appending more data beginning at the
+              // truncated duration timestamp.
+              sourceBuffer.timestampOffset = truncatedDuration;
+              sourceBuffer.appendBuffer(mediaData);
+
+              test.waitForExpectedEvents(function()
+              {
+                  assert_greater_than_equal(mediaElement.currentTime, truncatedDuration,
+                                            'Playback time has reached truncatedDuration');
+                  assert_approx_equals(mediaElement.duration, truncatedDuration + segmentInfo.duration, 0.05,
+                                       'mediaElement duration increased by new append');
+                  assert_equals(mediaSource.duration, mediaElement.duration,
+                                'mediaSource duration increased by new append');
+                  assert_false(mediaElement.seeking, 'mediaElement.seeking after seeked to truncatedDuration');
+
+                  test.done();
+              });
+          }, 'Test appendBuffer completes previous seek to truncated duration');
+
+          mediasource_truncated_duration_seek_test(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer,
+                                                            mediaData, truncatedDuration)
+          {
+              // The duration has been truncated at this point, and there is an
+              // outstanding seek pending.
+              test.expectEvent(mediaSource, 'sourceended', 'endOfStream acknowledged');
+
+              test.expectEvent(mediaElement, 'timeupdate', 'timeupdate while finishing seek to truncatedDuration');
+              test.expectEvent(mediaElement, 'seeked', 'seeked to truncatedDuration');
+
+              // Call endOfStream() to complete the pending seek.
+              mediaSource.endOfStream();
+
+              test.waitForExpectedEvents(function()
+              {
+                  assert_equals(mediaElement.currentTime, truncatedDuration,
+                                'Playback time has reached truncatedDuration');
+                  assert_equals(mediaElement.duration, truncatedDuration,
+                                'mediaElement truncatedDuration after seek to it');
+                  assert_equals(mediaSource.duration, truncatedDuration,
+                                'mediaSource truncatedDuration after seek to it');
+                  assert_false(mediaElement.seeking, 'mediaElement.seeking after seeked to truncatedDuration');
+
+                  test.done();
+              });
+          }, 'Test endOfStream completes previous seek to truncated duration');
+
+          mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
+          {
+              assert_greater_than(segmentInfo.duration, 2, 'Sufficient test media duration');
+
+              var fullDuration = segmentInfo.duration;
+              var newDuration = 0.5;
+
+              var expectedDurationChangeEventCount = 1;
+              var durationchangeEventCounter = 0;
+              var durationchangeEventHandler = test.step_func(function(event)
+              {
+                  assert_equals(mediaElement.duration, newDuration, 'mediaElement newDuration');
+                  assert_equals(mediaSource.duration, newDuration, 'mediaSource newDuration');
+                  durationchangeEventCounter++;
+              });
+
+              mediaElement.play();
+
+              // Append all the segments
+              test.expectEvent(sourceBuffer, 'updateend', 'sourceBuffer');
+              test.expectEvent(mediaElement, 'playing', 'Playing triggered');
+              sourceBuffer.appendBuffer(mediaData);
+
+              test.waitForExpectedEvents(function()
+              {
+                  assert_equals(mediaElement.duration, fullDuration, 'mediaElement fullDuration');
+                  assert_equals(mediaSource.duration, fullDuration, 'mediaSource fullDuration');
+                  assert_less_than(mediaElement.currentTime, newDuration / 2, 'mediaElement currentTime');
+
+                  // Media load also fires 'durationchange' event, so only start counting them now.
+                  mediaElement.addEventListener('durationchange', durationchangeEventHandler);
+
+                  assert_false(sourceBuffer.updating, "updating");
+
+                  // Truncate duration. This should result in one 'durationchange' fired.
+                  mediaSource.duration = newDuration;
+
+                  assert_true(sourceBuffer.updating, "updating");
+                  test.expectEvent(sourceBuffer, 'updatestart', 'sourceBuffer');
+                  test.expectEvent(sourceBuffer, 'update', 'sourceBuffer');
+                  test.expectEvent(sourceBuffer, 'updateend', 'sourceBuffer');
+              });
+
+              test.waitForExpectedEvents(function()
+              {
+                  assert_false(sourceBuffer.updating, "updating");
+
+                  // Set duration again to make sure it does not trigger another 'durationchange' event.
+                  mediaSource.duration = newDuration;
+
+                  // Mark endOfStream so that playback can reach 'ended' at the new duration.
+                  test.expectEvent(mediaSource, 'sourceended', 'endOfStream acknowledged');
+                  mediaSource.endOfStream();
+
+                  // endOfStream can change duration downwards slightly.
+                  // Allow for one more 'durationchange' event only in this case.
+                  var currentDuration = mediaSource.duration;
+                  if (currentDuration != newDuration) {
+                      assert_true(currentDuration > 0 && currentDuration < newDuration, 'adjusted duration');
+                      newDuration = currentDuration;
+                      ++expectedDurationChangeEventCount;
+                  }
+
+                  // Allow media to play to end while counting 'durationchange' events.
+                  test.expectEvent(mediaElement, 'ended', 'Playback ended');
+                  test.waitForExpectedEvents(function()
+                  {
+                      mediaElement.removeEventListener('durationchange', durationchangeEventHandler);
+                      assert_equals(durationchangeEventCounter, expectedDurationChangeEventCount, 'durationchanges');
+                      test.done();
+                  });
+              });
+          }, 'Test setting same duration multiple times does not fire duplicate durationchange');
+        </script>
+    </body>
+</html>
diff --git a/src/third_party/web_platform_tests/media-source/mediasource-endofstream-invaliderror.html b/src/third_party/web_platform_tests/media-source/mediasource-endofstream-invaliderror.html
new file mode 100644
index 0000000..2221d13
--- /dev/null
+++ b/src/third_party/web_platform_tests/media-source/mediasource-endofstream-invaliderror.html
@@ -0,0 +1,52 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <title>Invalid MediaSource.endOfStream() parameter test cases.</title>
+        <script src="/resources/testharness.js"></script>
+        <script src="/resources/testharnessreport.js"></script>
+        <script src="mediasource-util.js"></script>
+    </head>
+    <body>
+        <div id="log"></div>
+        <script>
+          mediasource_test(function(test, mediaElement, mediaSource)
+          {
+              mediaElement.addEventListener('error', test.unreached_func("Unexpected event 'error'"));
+              assert_equals(mediaSource.readyState, 'open');
+
+              assert_throws(new TypeError(),
+                  function() { mediaSource.endOfStream('garbage'); },
+                  'endOfStream(\'garbage\') throws TypeError');
+
+              assert_equals(mediaSource.readyState, 'open');
+              test.done();
+          }, 'Test MediaSource.endOfStream() with invalid non-empty error string.');
+
+          mediasource_test(function(test, mediaElement, mediaSource)
+          {
+              mediaElement.addEventListener('error', test.unreached_func("Unexpected event 'error'"));
+              assert_equals(mediaSource.readyState, 'open');
+
+              assert_throws(new TypeError(),
+                  function() { mediaSource.endOfStream(''); },
+                  'endOfStream(\'\') throws TypeError');
+
+              assert_equals(mediaSource.readyState, 'open');
+              test.done();
+          }, 'Test MediaSource.endOfStream() with invalid empty error string.');
+
+          mediasource_test(function(test, mediaElement, mediaSource)
+          {
+              mediaElement.addEventListener('error', test.unreached_func("Unexpected event 'error'"));
+              assert_equals(mediaSource.readyState, 'open');
+
+              assert_throws(new TypeError(),
+                  function() { mediaSource.endOfStream(null); },
+                  'endOfStream(null) throws TypeError');
+
+              assert_equals(mediaSource.readyState, 'open');
+              test.done();
+          }, 'Test MediaSource.endOfStream() with invalid null error parameter.');
+        </script>
+    </body>
+</html>
diff --git a/src/third_party/web_platform_tests/media-source/mediasource-getvideoplaybackquality.html b/src/third_party/web_platform_tests/media-source/mediasource-getvideoplaybackquality.html
new file mode 100644
index 0000000..5a3f6b1
--- /dev/null
+++ b/src/third_party/web_platform_tests/media-source/mediasource-getvideoplaybackquality.html
@@ -0,0 +1,71 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <title>HTMLVideoElement.getVideoPlaybackQuality() test cases.</title>
+        <script src="/resources/testharness.js"></script>
+        <script src="/resources/testharnessreport.js"></script>
+        <script src="mediasource-util.js"></script>
+    </head>
+    <body>
+        <div id="log"></div>
+        <script>
+          mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
+          {
+              var previousQuality = mediaElement.getVideoPlaybackQuality();
+              var timeUpdateCount = 0;
+              mediaElement.addEventListener("timeupdate", test.step_func(function (e)
+              {
+                  var videoElement = e.target;
+                  var newQuality = videoElement.getVideoPlaybackQuality();
+
+                  assert_not_equals(previousQuality, newQuality, "Verify new object");
+                  assert_greater_than(newQuality.creationTime, previousQuality.creationTime, "creationTime");
+
+                  assert_greater_than_equal(newQuality.totalVideoFrames, 0, "totalVideoFrames >= 0");
+                  assert_greater_than_equal(newQuality.totalVideoFrames, previousQuality.totalVideoFrames, "totalVideoFrames");
+
+                  assert_greater_than_equal(newQuality.droppedVideoFrames, 0, "droppedVideoFrames >= 0");
+                  assert_greater_than_equal(newQuality.droppedVideoFrames, previousQuality.droppedVideoFrames, "droppedVideoFrames");
+
+                  assert_greater_than_equal(newQuality.corruptedVideoFrames, 0, "corruptedVideoFrames >= 0");
+                  assert_greater_than_equal(newQuality.corruptedVideoFrames, previousQuality.corruptedVideoFrames, "corruptedVideoFrames");
+                  previousQuality = newQuality;
+                  timeUpdateCount++;
+              }));
+
+              mediaElement.addEventListener('error', test.unreached_func("Unexpected event 'error'"));
+
+              test.expectEvent(sourceBuffer, 'updatestart', 'sourceBuffer');
+              test.expectEvent(sourceBuffer, 'update', 'sourceBuffer');
+              test.expectEvent(sourceBuffer, 'updateend', 'sourceBuffer');
+              sourceBuffer.appendBuffer(mediaData);
+
+              test.waitForExpectedEvents(function()
+              {
+                  assert_false(sourceBuffer.updating, "updating");
+                  assert_greater_than(mediaSource.duration, 1, "duration");
+
+                  mediaSource.duration = 1;
+
+                  assert_true(sourceBuffer.updating, "updating");
+                  test.expectEvent(sourceBuffer, 'updatestart', 'sourceBuffer');
+                  test.expectEvent(sourceBuffer, 'update', 'sourceBuffer');
+                  test.expectEvent(sourceBuffer, 'updateend', 'sourceBuffer');
+              });
+
+              test.waitForExpectedEvents(function()
+              {
+                  mediaSource.endOfStream();
+                  mediaElement.play();
+                  test.expectEvent(mediaElement, 'ended', 'mediaElement');
+              });
+
+              test.waitForExpectedEvents(function()
+              {
+                  assert_greater_than(timeUpdateCount, 2, "timeUpdateCount");
+                  test.done();
+              });
+          }, "Test HTMLVideoElement.getVideoPlaybackQuality() with MediaSource API");
+        </script>
+    </body>
+</html>
diff --git a/src/third_party/web_platform_tests/media-source/mediasource-is-type-supported.html b/src/third_party/web_platform_tests/media-source/mediasource-is-type-supported.html
new file mode 100644
index 0000000..289cce2
--- /dev/null
+++ b/src/third_party/web_platform_tests/media-source/mediasource-is-type-supported.html
@@ -0,0 +1,80 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <title>MediaSource.isTypeSupported() test cases.</title>
+        <script src="/resources/testharness.js"></script>
+        <script src="/resources/testharnessreport.js"></script>
+    </head>
+    <body>
+        <div id="log"></div>
+        <script>
+          // Generate a distinct test for each type in types
+          function test_type_support(types, expectation, description)
+          {
+              for (var i = 0; i < types.length; ++i) {
+                  test(function()
+                  {
+                      assert_equals(MediaSource.isTypeSupported(types[i]),
+                                    expectation, 'supported');
+                  },  description + ' "' + types[i] + '"');
+              }
+          };
+
+          test_type_support([
+              'video',
+              'video/',
+              'video/webm',
+              'video/webm;',
+              'video/webm;codecs',
+              'video/webm;codecs=',
+              'video/webm;codecs="',
+              'video/webm;codecs=""',
+              'video/webm;codecs=","',
+              '',
+              null
+          ], false, 'Test invalid MIME format');
+
+          test_type_support([
+              'audio/webm;codecs="vp8"',
+              'audio/mp4;codecs="avc1.4d001e"',
+          ], false, 'Test invalid mismatch between major type and codec ID');
+
+          test_type_support([
+              'audio/mp4;codecs="vorbis"',
+              'audio/webm;codecs="mp4a.40.2"',
+              'video/mp4;codecs="vp8"',
+              'video/webm;codecs="mp4a.40.2"',
+              'video/mp4;codecs="vorbis"',
+              'video/webm;codecs="mp4a.40.2"',
+          ], false, 'Test invalid mismatch between minor type and codec ID');
+
+          test_type_support([
+              'audio/mp4;codecs="mp4a"',
+              'audio/mp4;codecs="mp4a.40"',
+              'audio/mp4;codecs="mp4a.40."',
+              'audio/mp4;codecs="mp4a.67.3"'
+          ], false, 'Test invalid codec ID');
+
+          test_type_support([
+              'video/webm;codecs="vp8"',
+              'video/webm;codecs="vorbis"',
+              'video/webm;codecs="vp8,vorbis"',
+              'video/webm;codecs="vorbis, vp8"',
+              'audio/webm;codecs="vorbis"',
+              'AUDIO/WEBM;CODECS="vorbis"',
+          ], true, 'Test valid WebM type');
+
+          test_type_support([
+              'video/mp4;codecs="avc1.4d001e"', // H.264 Main Profile level 3.0
+              'video/mp4;codecs="avc1.42001e"', // H.264 Baseline Profile level 3.0
+              'audio/mp4;codecs="mp4a.40.2"',   // MPEG4 AAC-LC
+              'audio/mp4;codecs="mp4a.40.5"',   // MPEG4 HE-AAC
+              'audio/mp4;codecs="mp4a.67"',     // MPEG2 AAC-LC
+              'video/mp4;codecs="mp4a.40.2"',
+              'video/mp4;codecs="avc1.4d001e,mp4a.40.2"',
+              'video/mp4;codecs="mp4a.40.2 , avc1.4d001e "',
+              'video/mp4;codecs="avc1.4d001e,mp4a.40.5"',
+          ], true, 'Test valid MP4 type');
+        </script>
+    </body>
+</html>
diff --git a/src/third_party/web_platform_tests/media-source/mediasource-multiple-attach.html b/src/third_party/web_platform_tests/media-source/mediasource-multiple-attach.html
new file mode 100644
index 0000000..d8152ff
--- /dev/null
+++ b/src/third_party/web_platform_tests/media-source/mediasource-multiple-attach.html
@@ -0,0 +1,113 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <title>Test Attaching a MediaSource to multiple HTMLMediaElements.</title>
+        <script src="/resources/testharness.js"></script>
+        <script src="/resources/testharnessreport.js"></script>
+        <script src="mediasource-util.js"></script>
+    </head>
+    <body>
+        <div id="log"></div>
+        <script>
+          function twoMediaElementTest(testFunction, description)
+          {
+              media_test(function(test)
+              {
+                  var firstMediaTag = document.createElement('video');
+                  var secondMediaTag = document.createElement('video');
+                  document.body.appendChild(firstMediaTag);
+                  document.body.appendChild(secondMediaTag);
+
+                  // Overload done() so that elements added to the document can be
+                  // removed.
+                  var removeMediaElements = true;
+                  var oldTestDone = test.done.bind(test);
+                  test.done = function()
+                  {
+                      if (removeMediaElements) {
+                          document.body.removeChild(secondMediaTag);
+                          document.body.removeChild(firstMediaTag);
+                          removeMediaElements = false;
+                      }
+                      oldTestDone();
+                  };
+
+                  testFunction(test, firstMediaTag, secondMediaTag);
+              }, description);
+          }
+
+          twoMediaElementTest(function(test, firstMediaTag, secondMediaTag)
+          {
+              // When attachment of mediaSource to two MediaElements is done
+              // without an intervening stable state, exactly one of the two
+              // MediaElements should successfully attach, and the other one
+              // should get error event due to mediaSource already in 'open'
+              // readyState.
+              var mediaSource = new MediaSource();
+              var mediaSourceURL = URL.createObjectURL(mediaSource);
+              var gotSourceOpen = false;
+              var gotError = false;
+              var doneIfFinished = test.step_func(function()
+              {
+                  if (gotSourceOpen && gotError)
+                      test.done();
+              });
+              var errorHandler = test.step_func(function(e)
+              {
+                  firstMediaTag.removeEventListener('error', errorHandler);
+                  secondMediaTag.removeEventListener('error', errorHandler);
+
+                  var eventTarget = e.target;
+                  var otherTarget;
+                  if (eventTarget == firstMediaTag) {
+                      otherTarget = secondMediaTag;
+                  } else {
+                      assert_equals(eventTarget, secondMediaTag, 'Error target check');
+                      otherTarget = firstMediaTag;
+                  }
+
+                  assert_true(eventTarget.error != null, 'Error state on one tag');
+                  assert_equals(eventTarget.error.code, MediaError.MEDIA_ERR_SRC_NOT_SUPPORTED, 'Expected error code');
+                  assert_equals(otherTarget.error, null, 'No error on other tag');
+
+                  assert_equals(eventTarget.networkState, HTMLMediaElement.NETWORK_NO_SOURCE,
+                                'Tag with error state networkState');
+                  assert_equals(otherTarget.networkState, HTMLMediaElement.NETWORK_LOADING,
+                                'Tag without error state networkState');
+
+                  gotError = true;
+                  doneIfFinished();
+              });
+
+              test.expectEvent(mediaSource, 'sourceopen', 'An attachment succeeded');
+              firstMediaTag.addEventListener('error', errorHandler);
+              secondMediaTag.addEventListener('error', errorHandler);
+
+              firstMediaTag.src = mediaSourceURL;
+              secondMediaTag.src = mediaSourceURL;
+
+              test.waitForExpectedEvents(function()
+              {
+                  assert_equals(mediaSource.readyState, 'open', 'Source is opened');
+                  gotSourceOpen = true;
+                  doneIfFinished();
+              });
+          }, 'Test exactly one succeeds when two MediaElements attach to same MediaSource');
+
+          mediasource_test(function(test, mediaElement, mediaSource) {
+              assert_equals(mediaSource.readyState, 'open', 'Source open');
+              // Set the tag's src attribute.  This should close mediaSource,
+              // reattach it to the tag, and initiate source reopening.
+              test.expectEvent(mediaSource, 'sourceopen', 'Source attached again');
+              mediaElement.src = URL.createObjectURL(mediaSource);
+              assert_equals(mediaSource.readyState, 'closed', 'Source closed');
+
+              test.waitForExpectedEvents(function()
+              {
+                  assert_equals(mediaSource.readyState, 'open', 'Source reopened');
+                  test.done();
+              });
+          }, 'Test that MediaSource can reattach if closed first');
+        </script>
+    </body>
+</html>
diff --git a/src/third_party/web_platform_tests/media-source/mediasource-play-then-seek-back.html b/src/third_party/web_platform_tests/media-source/mediasource-play-then-seek-back.html
new file mode 100644
index 0000000..bb2b747
--- /dev/null
+++ b/src/third_party/web_platform_tests/media-source/mediasource-play-then-seek-back.html
@@ -0,0 +1,57 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <title>Simple MediaSource playback &amp; seek test case.</title>
+        <script src="/resources/testharness.js"></script>
+        <script src="/resources/testharnessreport.js"></script>
+        <script src="mediasource-util.js"></script>
+    </head>
+    <body>
+        <div id="log"></div>
+        <script>
+
+            mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
+            {
+
+                mediaElement.play();
+                // Append all the segments
+                test.expectEvent(sourceBuffer, 'updateend', 'sourceBuffer');
+                test.expectEvent(mediaElement, 'playing', 'Playing triggered');
+                sourceBuffer.appendBuffer(mediaData);
+
+                function confirmPlayThenEnd()
+                {
+                    test.waitForCurrentTimeChange(mediaElement, function ()
+                    {
+                        assert_greater_than(mediaElement.currentTime, 0.0, 'Playback has started after seek.');
+                        test.done();
+                    });
+                }
+
+                function finishSeekThenPlay()
+                {
+                    assert_true(mediaElement.seeking, 'mediaElement is seeking');
+                    assert_equals(mediaElement.currentTime, 0.0, 'Current time is 0.0');
+                    test.expectEvent(mediaElement, 'seeked', 'mediaElement finished seek');
+
+                    test.waitForExpectedEvents(confirmPlayThenEnd);
+                }
+
+                function delayedPlayHandler()
+                {
+                    assert_greater_than(mediaElement.currentTime, 0.0, 'Playback has started.');
+                    test.expectEvent(mediaElement, 'seeking', 'mediaElement');
+                    mediaElement.currentTime = 0.0;
+
+                    test.waitForExpectedEvents(finishSeekThenPlay);
+                }
+
+                test.waitForExpectedEvents(function()
+                {
+                    test.waitForCurrentTimeChange(mediaElement, delayedPlayHandler);
+                });
+
+            }, 'Test playing then seeking back.');
+        </script>
+    </body>
+</html>
diff --git a/src/third_party/web_platform_tests/media-source/mediasource-play.html b/src/third_party/web_platform_tests/media-source/mediasource-play.html
new file mode 100644
index 0000000..487c030
--- /dev/null
+++ b/src/third_party/web_platform_tests/media-source/mediasource-play.html
@@ -0,0 +1,44 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <title>Simple MediaSource playback test case.</title>
+        <script src="/resources/testharness.js"></script>
+        <script src="/resources/testharnessreport.js"></script>
+        <script src="mediasource-util.js"></script>
+    </head>
+    <body>
+        <div id="log"></div>
+        <script>
+          mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
+          {
+              mediaElement.addEventListener('error', test.unreached_func("Unexpected event 'error'"));
+              mediaElement.addEventListener('ended', test.step_func_done());
+
+              test.expectEvent(sourceBuffer, 'updatestart', 'sourceBuffer');
+              test.expectEvent(sourceBuffer, 'update', 'sourceBuffer');
+              test.expectEvent(sourceBuffer, 'updateend', 'sourceBuffer');
+
+              sourceBuffer.appendBuffer(mediaData);
+
+              test.waitForExpectedEvents(function()
+              {
+                  assert_false(sourceBuffer.updating, "updating");
+                  assert_greater_than(mediaSource.duration, 1, "duration");
+
+                  mediaSource.duration = 1;
+
+                  assert_true(sourceBuffer.updating, "updating");
+                  test.expectEvent(sourceBuffer, 'updatestart', 'sourceBuffer');
+                  test.expectEvent(sourceBuffer, 'update', 'sourceBuffer');
+                  test.expectEvent(sourceBuffer, 'updateend', 'sourceBuffer');
+              });
+
+              test.waitForExpectedEvents(function()
+              {
+                  mediaSource.endOfStream();
+                  mediaElement.play();
+              });
+          }, "Test normal playback case with MediaSource API");
+        </script>
+    </body>
+</html>
diff --git a/src/third_party/web_platform_tests/media-source/mediasource-redundant-seek.html b/src/third_party/web_platform_tests/media-source/mediasource-redundant-seek.html
new file mode 100644
index 0000000..152b156
--- /dev/null
+++ b/src/third_party/web_platform_tests/media-source/mediasource-redundant-seek.html
@@ -0,0 +1,72 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <title>Test MediaSource behavior when receiving multiple seek requests during a pending seek.</title>
+        <meta name="timeout" content="long">
+        <script src="/resources/testharness.js"></script>
+        <script src="/resources/testharnessreport.js"></script>
+        <script src="mediasource-util.js"></script>
+    </head>
+    <body>
+        <div id="log"></div>
+        <script>
+
+            mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
+            {
+                mediaElement.play();
+
+                // Append all media data for complete playback.
+                test.expectEvent(sourceBuffer, 'updateend', 'sourceBuffer end update.');
+                test.expectEvent(mediaElement, 'loadedmetadata', 'Reached HAVE_METADATA');
+                test.expectEvent(mediaElement, 'playing', 'Playing media.');
+                sourceBuffer.appendBuffer(mediaData);
+
+                test.waitForExpectedEvents(function()
+                {
+                    var bufferedRanges = mediaElement.buffered;
+
+                    assert_greater_than_equal(mediaElement.duration, 4.0, 'Duration is >= 4.0s');
+                    assert_equals(bufferedRanges.length, 1, 'Just one buffered range');
+                    assert_less_than_equal(bufferedRanges.start(0), 1.0, 'Buffered range starts <= 1.0s');
+                    assert_greater_than_equal(bufferedRanges.end(0), 4.0, 'Buffered range ends >= 4.0s');
+
+                    test.expectEvent(mediaElement, 'seeking', 'seeking');
+                    test.expectEvent(mediaElement, 'timeupdate', 'timeupdate');
+                    test.expectEvent(mediaElement, 'seeked', 'seeked');
+
+                    // Request seeks.
+                    mediaElement.currentTime = 1.0;
+
+                    // This 'ephemeral' seek should be invisible to javascript, except any latency incurred in its processing.
+                    mediaElement.currentTime = 3.0;
+
+                    mediaElement.currentTime = 1.0;
+
+                    assert_true(mediaElement.seeking, 'Element is seeking');
+                    assert_equals(mediaElement.currentTime, 1.0, 'Element time is at last seek time');
+                });
+
+                test.waitForExpectedEvents(function()
+                {
+                    // No more seeking or seeked events should occur.
+                    mediaElement.addEventListener('seeking', test.unreached_func("Unexpected event 'seeking'"));
+                    mediaElement.addEventListener('seeked', test.unreached_func("Unexpected event 'seeked'"));
+
+                    assert_false(mediaElement.seeking, 'Element is not seeking');
+                    assert_greater_than_equal(mediaElement.currentTime, 1.0, 'Element time is at or after last seek time');
+                    assert_less_than(mediaElement.currentTime, 3.0, 'Element time is before the ephemeral seek time');
+
+                    var timeBeforeWait = mediaElement.currentTime;
+                    test.waitForCurrentTimeChange(mediaElement, function()
+                    {
+                        // Time should have advanced a little, but not yet reached the ephemeral seek time.
+                        assert_greater_than(mediaElement.currentTime, timeBeforeWait, 'Element time has increased');
+                        assert_less_than(mediaElement.currentTime, 3.0, 'Element time is still before the ephemeral seek time');
+                        test.done();
+                    });
+                });
+            }, 'Test redundant fully prebuffered seek');
+
+        </script>
+    </body>
+</html>
diff --git a/src/third_party/web_platform_tests/media-source/mediasource-remove.html b/src/third_party/web_platform_tests/media-source/mediasource-remove.html
new file mode 100644
index 0000000..0b9db53
--- /dev/null
+++ b/src/third_party/web_platform_tests/media-source/mediasource-remove.html
@@ -0,0 +1,293 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <title>SourceBuffer.remove() test cases.</title>
+        <script src="/resources/testharness.js"></script>
+        <script src="/resources/testharnessreport.js"></script>
+        <script src="mediasource-util.js"></script>
+    </head>
+    <body>
+        <div id="log"></div>
+        <script>
+          mediasource_test(function(test, mediaElement, mediaSource)
+          {
+              var sourceBuffer = mediaSource.addSourceBuffer(MediaSourceUtil.AUDIO_VIDEO_TYPE);
+
+              assert_throws("InvalidAccessError", function()
+              {
+                  sourceBuffer.remove(-1, 2);
+              }, "remove");
+
+              test.done();
+          }, "Test remove with an negative start.");
+
+          mediasource_test(function(test, mediaElement, mediaSource)
+          {
+              var sourceBuffer = mediaSource.addSourceBuffer(MediaSourceUtil.AUDIO_VIDEO_TYPE);
+
+              [ undefined, NaN, Infinity, -Infinity ].forEach(function(item)
+              {
+                  assert_throws(new TypeError(), function()
+                  {
+                      sourceBuffer.remove(item, 2);
+                  }, "remove");
+              });
+
+              test.done();
+          }, "Test remove with non-finite start.");
+
+          mediasource_test(function(test, mediaElement, mediaSource)
+          {
+              var sourceBuffer = mediaSource.addSourceBuffer(MediaSourceUtil.AUDIO_VIDEO_TYPE);
+
+              mediaSource.duration = 10;
+
+              assert_throws("InvalidAccessError", function()
+              {
+                  sourceBuffer.remove(11, 12);
+              }, "remove");
+
+              test.done();
+          }, "Test remove with a start beyond the duration.");
+
+          mediasource_test(function(test, mediaElement, mediaSource)
+          {
+              var sourceBuffer = mediaSource.addSourceBuffer(MediaSourceUtil.AUDIO_VIDEO_TYPE);
+
+              mediaSource.duration = 10;
+
+              assert_throws("InvalidAccessError", function()
+              {
+                  sourceBuffer.remove(2, 1);
+              }, "remove");
+
+              test.done();
+          }, "Test remove with a start larger than the end.");
+
+          mediasource_test(function(test, mediaElement, mediaSource)
+          {
+              var sourceBuffer = mediaSource.addSourceBuffer(MediaSourceUtil.AUDIO_VIDEO_TYPE);
+
+              assert_throws("InvalidAccessError", function()
+              {
+                  sourceBuffer.remove(0, Number.NEGATIVE_INFINITY);
+              }, "remove");
+
+              test.done();
+          }, "Test remove with a NEGATIVE_INFINITY end.");
+
+          mediasource_test(function(test, mediaElement, mediaSource)
+          {
+              var sourceBuffer = mediaSource.addSourceBuffer(MediaSourceUtil.AUDIO_VIDEO_TYPE);
+
+              assert_throws("InvalidAccessError", function()
+              {
+                  sourceBuffer.remove(0, Number.NaN);
+              }, "remove");
+
+              test.done();
+          }, "Test remove with a NaN end.");
+
+          mediasource_test(function(test, mediaElement, mediaSource)
+          {
+              var sourceBuffer = mediaSource.addSourceBuffer(MediaSourceUtil.AUDIO_VIDEO_TYPE);
+
+              mediaSource.duration = 10;
+
+              mediaSource.removeSourceBuffer(sourceBuffer);
+
+              assert_throws("InvalidStateError", function()
+              {
+                  sourceBuffer.remove(1, 2);
+              }, "remove");
+
+              test.done();
+          }, "Test remove after SourceBuffer removed from mediaSource.");
+
+
+          mediasource_test(function(test, mediaElement, mediaSource)
+          {
+              var sourceBuffer = mediaSource.addSourceBuffer(MediaSourceUtil.AUDIO_VIDEO_TYPE);
+
+              mediaSource.duration = 10;
+
+              test.expectEvent(sourceBuffer, "updatestart");
+              test.expectEvent(sourceBuffer, "update");
+              test.expectEvent(sourceBuffer, "updateend");
+              sourceBuffer.remove(1, 2);
+
+              assert_true(sourceBuffer.updating, "updating");
+
+              assert_throws("InvalidStateError", function()
+              {
+                  sourceBuffer.remove(3, 4);
+              }, "remove");
+
+              test.waitForExpectedEvents(function()
+              {
+                  test.done();
+              });
+          }, "Test remove while update pending.");
+
+          mediasource_test(function(test, mediaElement, mediaSource)
+          {
+              var sourceBuffer = mediaSource.addSourceBuffer(MediaSourceUtil.AUDIO_VIDEO_TYPE);
+
+              mediaSource.duration = 10;
+
+              test.expectEvent(sourceBuffer, "updatestart");
+              test.expectEvent(sourceBuffer, "abort");
+              test.expectEvent(sourceBuffer, "updateend");
+              sourceBuffer.remove(1, 2);
+
+              assert_true(sourceBuffer.updating, "updating");
+
+              sourceBuffer.abort();
+
+              assert_false(sourceBuffer.updating, "updating");
+
+              test.waitForExpectedEvents(function()
+              {
+                  test.done();
+              });
+          }, "Test aborting a remove operation.");
+
+          mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
+          {
+              sourceBuffer.appendBuffer(mediaData);
+
+              test.expectEvent(sourceBuffer, "updatestart");
+              test.expectEvent(sourceBuffer, "update");
+              test.expectEvent(sourceBuffer, "updateend");
+
+              test.waitForExpectedEvents(function()
+              {
+                  assert_less_than(mediaSource.duration, 10)
+
+                  mediaSource.duration = 10;
+
+                  sourceBuffer.remove(mediaSource.duration, mediaSource.duration + 2);
+
+                  assert_true(sourceBuffer.updating, "updating");
+                  test.expectEvent(sourceBuffer, "updatestart");
+                  test.expectEvent(sourceBuffer, "update");
+                  test.expectEvent(sourceBuffer, "updateend");
+              });
+
+              test.waitForExpectedEvents(function()
+              {
+                  test.done();
+              });
+
+          }, "Test remove with a start at the duration.");
+
+          mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
+          {
+              test.expectEvent(sourceBuffer, "updatestart");
+              test.expectEvent(sourceBuffer, "update");
+              test.expectEvent(sourceBuffer, "updateend");
+              sourceBuffer.appendBuffer(mediaData);
+
+              test.waitForExpectedEvents(function()
+              {
+                  mediaSource.endOfStream();
+
+                  assert_equals(mediaSource.readyState, "ended");
+
+                  test.expectEvent(sourceBuffer, "updatestart");
+                  test.expectEvent(sourceBuffer, "update");
+                  test.expectEvent(sourceBuffer, "updateend");
+                  sourceBuffer.remove(1, 2);
+
+                  assert_true(sourceBuffer.updating, "updating");
+                  assert_equals(mediaSource.readyState, "open");
+              });
+
+              test.waitForExpectedEvents(function()
+              {
+                  assert_false(sourceBuffer.updating, "updating");
+                  test.done();
+              });
+          }, "Test remove transitioning readyState from 'ended' to 'open'.");
+
+          function removeAppendedDataTests(callback, description)
+          {
+              mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
+              {
+                  test.expectEvent(sourceBuffer, "updatestart");
+                  test.expectEvent(sourceBuffer, "update");
+                  test.expectEvent(sourceBuffer, "updateend");
+                  sourceBuffer.appendBuffer(mediaData);
+
+                  test.waitForExpectedEvents(function()
+                  {
+                      mediaSource.endOfStream();
+                      assert_false(sourceBuffer.updating, "updating");
+
+                      var duration = mediaElement.duration.toFixed(3);
+                      var subType = MediaSourceUtil.getSubType(segmentInfo.type);
+
+                      assertBufferedEquals(sourceBuffer, "{ [0.000, " + duration + ") }", "Initial buffered range.");
+                      callback(test, mediaSource, sourceBuffer, duration, subType);
+                  });
+              }, description);
+          };
+          function removeAndCheckBufferedRanges(test, mediaSource, sourceBuffer, start, end, expected)
+          {
+              test.expectEvent(sourceBuffer, "updatestart");
+              test.expectEvent(sourceBuffer, "update");
+              test.expectEvent(sourceBuffer, "updateend");
+              sourceBuffer.remove(start, end);
+
+              test.waitForExpectedEvents(function()
+              {
+                  mediaSource.endOfStream();
+                  assert_false(sourceBuffer.updating, "updating");
+
+                  assertBufferedEquals(sourceBuffer, expected, "Buffered ranges after remove().");
+                  test.done();
+              });
+          }
+
+          removeAppendedDataTests(function(test, mediaSource, sourceBuffer, duration, subType)
+          {
+              removeAndCheckBufferedRanges(test, mediaSource, sourceBuffer, 0, Number.POSITIVE_INFINITY, "{ }");
+          }, "Test removing all appended data.");
+
+          removeAppendedDataTests(function(test, mediaSource, sourceBuffer, duration, subType)
+          {
+              var expectations = {
+                webm: ("{ [3.187, " + duration + ") }"),
+                mp4: ("{ [3.154, " + duration + ") }"),
+              };
+
+              // Note: Range doesn't start exactly at the end of the remove range because there isn't
+              // a keyframe there. The resulting range starts at the first keyframe >= the end time.
+              removeAndCheckBufferedRanges(test, mediaSource, sourceBuffer, 0, 3, expectations[subType]);
+          }, "Test removing beginning of appended data.");
+
+          removeAppendedDataTests(function(test, mediaSource, sourceBuffer, duration, subType)
+          {
+              var expectations = {
+                webm: ("{ [0.000, 1.012) [3.187, " + duration + ") }"),
+                mp4: ("{ [0.000, 1.022) [3.154, " + duration + ") }"),
+              };
+
+              // Note: The first resulting range ends slightly after start because the removal algorithm only removes
+              // frames with a timestamp >= the start time. If a frame starts before and ends after the remove() start
+              // timestamp, then it stays in the buffer.
+              removeAndCheckBufferedRanges(test, mediaSource, sourceBuffer, 1, 3, expectations[subType]);
+          }, "Test removing the middle of appended data.");
+
+          removeAppendedDataTests(function(test, mediaSource, sourceBuffer, duration, subType)
+          {
+              var expectations = {
+                webm: "{ [0.000, 1.012) }",
+                mp4: "{ [0.000, 1.029) }",
+              };
+
+              removeAndCheckBufferedRanges(test, mediaSource, sourceBuffer, 1, Number.POSITIVE_INFINITY, expectations[subType]);
+          }, "Test removing the end of appended data.");
+        </script>
+    </body>
+</html>
diff --git a/src/third_party/web_platform_tests/media-source/mediasource-removesourcebuffer.html b/src/third_party/web_platform_tests/media-source/mediasource-removesourcebuffer.html
new file mode 100644
index 0000000..cbf3a1b
--- /dev/null
+++ b/src/third_party/web_platform_tests/media-source/mediasource-removesourcebuffer.html
@@ -0,0 +1,92 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <title>MediaSource.removeSourceBuffer() test cases.</title>
+        <script src="/resources/testharness.js"></script>
+        <script src="/resources/testharnessreport.js"></script>
+        <script src="mediasource-util.js"></script>
+    </head>
+    <body>
+        <div id="log"></div>
+        <script>
+          mediasource_test(function(test, mediaElement, mediaSource)
+          {
+              var sourceBuffer = mediaSource.addSourceBuffer(MediaSourceUtil.AUDIO_VIDEO_TYPE);
+              assert_true(sourceBuffer != null, "New SourceBuffer returned");
+
+              mediaSource.removeSourceBuffer(sourceBuffer);
+
+              var sourceBuffer2 = mediaSource.addSourceBuffer(MediaSourceUtil.AUDIO_VIDEO_TYPE);
+              assert_true(sourceBuffer2 != null, "New SourceBuffer returned");
+              assert_true(sourceBuffer != sourceBuffer2, "SourceBuffers are different instances.");
+              assert_equals(mediaSource.sourceBuffers.length, 1, "sourceBuffers.length == 1");
+
+              test.done();
+          }, "Test addSourceBuffer(), removeSourceBuffer(), addSourceBuffer() sequence.");
+
+          mediasource_test(function(test, mediaElement, mediaSource)
+          {
+              assert_throws(new TypeError(),
+                          function() { mediaSource.removeSourceBuffer(null); },
+                          "removeSourceBuffer() threw an exception when passed null.");
+              test.done();
+          }, "Test removeSourceBuffer() with null");
+
+          mediasource_test(function(test, mediaElement, mediaSource)
+          {
+              var sourceBuffer = mediaSource.addSourceBuffer(MediaSourceUtil.AUDIO_VIDEO_TYPE);
+              assert_true(sourceBuffer != null, "New SourceBuffer returned");
+
+              mediaSource.removeSourceBuffer(sourceBuffer);
+
+              assert_throws("NotFoundError",
+                  function() { mediaSource.removeSourceBuffer(sourceBuffer); },
+                  "removeSourceBuffer() threw an exception when a SourceBuffer that was already removed.");
+
+              test.done();
+          }, "Test calling removeSourceBuffer() twice with the same object.");
+
+          mediasource_test(function(test, mediaElement, mediaSource)
+          {
+              var sourceBuffer = mediaSource.addSourceBuffer(MediaSourceUtil.AUDIO_VIDEO_TYPE);
+              assert_true(sourceBuffer != null, "New SourceBuffer returned");
+
+              mediaSource.endOfStream();
+              assert_true(mediaSource.readyState == "ended", "MediaSource in ended state");
+              mediaSource.removeSourceBuffer(sourceBuffer);
+
+              assert_true(mediaSource.sourceBuffers.length == 0, "MediaSource.sourceBuffers is empty");
+              assert_true(mediaSource.activeSourceBuffers.length == 0, "MediaSource.activesourceBuffers is empty");
+
+              test.done();
+          }, "Test calling removeSourceBuffer() in ended state.");
+
+          mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
+          {
+              var initSegment = MediaSourceUtil.extractSegmentData(mediaData, segmentInfo.init);
+
+              test.expectEvent(sourceBuffer, "updateend", "initSegment append ended.");
+              test.expectEvent(mediaElement, "loadedmetadata", "loadedmetadata done.");
+              sourceBuffer.appendBuffer(initSegment);
+
+              test.waitForExpectedEvents(function()
+              {
+                  assert_true(mediaSource.sourceBuffers.length == 1, "MediaSource.sourceBuffers is not empty");
+                  assert_true(mediaSource.activeSourceBuffers.length == 1, "MediaSource.activesourceBuffers is not empty");
+                  assert_equals(mediaElement.readyState, mediaElement.HAVE_METADATA);
+                  assert_equals(mediaSource.duration, segmentInfo.duration);
+                  test.expectEvent(mediaSource.activeSourceBuffers, "removesourcebuffer", "SourceBuffer removed from activeSourceBuffers.");
+                  test.expectEvent(mediaSource.sourceBuffers, "removesourcebuffer", "SourceBuffer removed.");
+                  mediaSource.removeSourceBuffer(sourceBuffer);
+              });
+
+              test.waitForExpectedEvents(function()
+              {
+                  assert_true(mediaSource.sourceBuffers.length == 0, "MediaSource.sourceBuffers is empty");
+                  assert_true(mediaSource.activeSourceBuffers.length == 0, "MediaSource.activesourceBuffers is empty");
+                  test.done();
+              });
+          }, "Test removesourcebuffer event on activeSourceBuffers.");
+        </script>
+    </body>
+</html>
diff --git a/src/third_party/web_platform_tests/media-source/mediasource-seek-beyond-duration.html b/src/third_party/web_platform_tests/media-source/mediasource-seek-beyond-duration.html
new file mode 100644
index 0000000..3caf5f8
--- /dev/null
+++ b/src/third_party/web_platform_tests/media-source/mediasource-seek-beyond-duration.html
@@ -0,0 +1,95 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <title>Test MediaSource behavior when seeking beyond the duration of the clip.</title>
+        <script src="/resources/testharness.js"></script>
+        <script src="/resources/testharnessreport.js"></script>
+        <script src="mediasource-util.js"></script>
+    </head>
+    <body>
+        <div id="log"></div>
+        <script>
+
+            function seekToSpecifiedTimeSetEOSAndVerifyDone(test, mediaElement, mediaSource, seekToTime)
+            {
+                assert_less_than(mediaElement.currentTime, mediaElement.duration, 'Not at the end yet.');
+                test.expectEvent(mediaElement, 'seeking', 'mediaElement seeking');
+                // Seek to specified time.
+                mediaElement.currentTime = seekToTime;
+                if (seekToTime >= mediaSource.duration) {
+                    assert_equals(mediaElement.currentTime, mediaSource.duration, 'Current time equals duration.');
+                } else {
+                    assert_equals(mediaElement.currentTime, seekToTime, 'Current time equals specified seek time.');
+                }
+
+                test.waitForExpectedEvents(function()
+                {
+                    test.expectEvent(mediaElement, 'timeupdate', 'mediaElement time updated.');
+                    test.expectEvent(mediaElement, 'seeked', 'mediaElement seeked');
+                    test.expectEvent(mediaElement, 'ended', 'mediaElement ended.');
+                    test.expectEvent(mediaSource, 'sourceended', 'mediaSource ended.');
+                    mediaSource.endOfStream();
+                    assert_true(mediaElement.seeking, 'mediaElement seeking.');
+                });
+
+                test.waitForExpectedEvents(function()
+                {
+                    assert_equals(mediaElement.currentTime, mediaSource.duration, 'Current time equals duration.');
+                    test.done();
+                });
+            };
+
+            mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
+            {
+                mediaElement.play();
+                var initSegment = MediaSourceUtil.extractSegmentData(mediaData, segmentInfo.init);
+
+                // Append the initialization segment to trigger a transition to HAVE_METADATA.
+                test.expectEvent(sourceBuffer, 'updateend', 'sourceBuffer end update.');
+                test.expectEvent(mediaElement, 'loadedmetadata', 'Reached HAVE_METADATA');
+                sourceBuffer.appendBuffer(initSegment);
+
+                test.waitForExpectedEvents(function()
+                {
+                    // Add sufficient segments to have at least 2s of play-time.
+                    var playbackData = MediaSourceUtil.getMediaDataForPlaybackTime(mediaData, segmentInfo, 2.0);
+                    test.expectEvent(sourceBuffer, 'updateend', 'sourceBuffer');
+                    test.expectEvent(mediaElement, 'playing', 'Playing media.');
+                    sourceBuffer.appendBuffer(playbackData);
+                });
+
+                test.waitForExpectedEvents(function()
+                {
+                    assert_equals(mediaElement.duration, segmentInfo.duration);
+                    assert_greater_than_equal(mediaElement.duration, 2.0, 'Duration is >2.0s.');
+                    test.waitForCurrentTimeChange(mediaElement, function()
+                    {
+                        // Update duration.
+                        mediaSource.duration = 1.5;
+                        seekToSpecifiedTimeSetEOSAndVerifyDone(test, mediaElement, mediaSource, 1.8);
+                    });
+                });
+            }, 'Test seeking beyond updated media duration.');
+
+            mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
+            {
+                mediaElement.play();
+
+                // Append all media data for complete playback.
+                test.expectEvent(sourceBuffer, 'updateend', 'sourceBuffer end update.');
+                test.expectEvent(mediaElement, 'loadedmetadata', 'Reached HAVE_METADATA');
+                test.expectEvent(mediaElement, 'playing', 'Playing media.');
+                sourceBuffer.appendBuffer(mediaData);
+
+                test.waitForExpectedEvents(function()
+                {
+                    test.waitForCurrentTimeChange(mediaElement, function()
+                    {
+                        seekToSpecifiedTimeSetEOSAndVerifyDone(test, mediaElement, mediaSource, mediaSource.duration, mediaSource.duration + 0.1);
+                    });
+                });
+
+            }, 'Test seeking beyond media duration.');
+        </script>
+    </body>
+</html>
diff --git a/src/third_party/web_platform_tests/media-source/mediasource-seek-during-pending-seek.html b/src/third_party/web_platform_tests/media-source/mediasource-seek-during-pending-seek.html
new file mode 100644
index 0000000..4b415a6
--- /dev/null
+++ b/src/third_party/web_platform_tests/media-source/mediasource-seek-during-pending-seek.html
@@ -0,0 +1,142 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <title>Test MediaSource behavior when a seek is requested while another seek is pending.</title>
+        <script src="/resources/testharness.js"></script>
+        <script src="/resources/testharnessreport.js"></script>
+        <script src="mediasource-util.js"></script>
+    </head>
+    <body>
+        <div id="log"></div>
+        <script>
+          mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
+          {
+              mediaElement.play();
+
+              var initSegment = MediaSourceUtil.extractSegmentData(mediaData, segmentInfo.init);
+              var firstSegment = MediaSourceUtil.extractSegmentData(mediaData, segmentInfo.media[0]);
+              var segmentIndex = 2;
+              var secondSegmentInfo = segmentInfo.media[segmentIndex];
+
+              // Append the initialization segment to trigger a transition to HAVE_METADATA.
+              test.expectEvent(sourceBuffer, 'updateend', 'sourceBuffer');
+              test.expectEvent(mediaElement, 'loadedmetadata', 'Reached HAVE_METADATA');
+              sourceBuffer.appendBuffer(initSegment);
+
+              test.waitForExpectedEvents(function()
+              {
+                  assert_false(mediaElement.seeking, 'mediaElement is not seeking');
+                  assert_equals(mediaElement.readyState, mediaElement.HAVE_METADATA, 'Still in HAVE_METADATA');
+
+                  // Seek to a new position before letting the initial seek to 0 completes.
+                  test.expectEvent(mediaElement, 'seeking', 'mediaElement');
+                  mediaElement.currentTime = secondSegmentInfo.timecode;
+                  assert_true(mediaElement.seeking, 'mediaElement is seeking');
+
+                  // Append media data for time 0.
+                  test.expectEvent(sourceBuffer, 'updateend', 'sourceBuffer');
+                  sourceBuffer.appendBuffer(firstSegment);
+              });
+
+              test.waitForExpectedEvents(function()
+              {
+                  // Verify that the media data didn't trigger a 'seeking' event or a transition beyond HAVE_METADATA.
+                  assert_true(mediaElement.seeking, 'mediaElement is still seeking');
+                  assert_equals(mediaElement.readyState, mediaElement.HAVE_METADATA, 'Still in HAVE_METADATA');
+
+                  // Append media data for the current position until the element starts playing.
+                  test.expectEvent(mediaElement, 'seeked', 'mediaElement finished seek');
+                  test.expectEvent(mediaElement, 'playing', 'mediaElement playing');
+
+                  MediaSourceUtil.appendUntilEventFires(test, mediaElement, 'playing', sourceBuffer, mediaData, segmentInfo, segmentIndex);
+              });
+
+              test.waitForExpectedEvents(function()
+              {
+                  test.expectEvent(mediaSource, 'sourceended', 'mediaSource ended');
+                  mediaSource.endOfStream();
+              });
+
+              test.waitForExpectedEvents(function()
+              {
+                  assert_greater_than(mediaElement.readyState, mediaElement.HAVE_CURRENT_DATA, 'Greater than HAVE_CURRENT_DATA');
+                  test.done();
+              });
+
+          }, 'Test seeking to a new location before transitioning beyond HAVE_METADATA.');
+
+          mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
+          {
+              mediaElement.play();
+
+              var initSegment = MediaSourceUtil.extractSegmentData(mediaData, segmentInfo.init);
+              var firstSegment = MediaSourceUtil.extractSegmentData(mediaData, segmentInfo.media[0]);
+              var secondSegmentInfo = segmentInfo.media[2];
+              var secondSegment = MediaSourceUtil.extractSegmentData(mediaData, secondSegmentInfo);
+              var segmentIndex = 4;
+              var thirdSegmentInfo = segmentInfo.media[segmentIndex];
+
+              // Append the initialization segment to trigger a transition to HAVE_METADATA.
+              test.expectEvent(sourceBuffer, 'updateend', 'sourceBuffer');
+              test.expectEvent(mediaElement, 'loadedmetadata', 'Reached HAVE_METADATA');
+              sourceBuffer.appendBuffer(initSegment);
+
+              test.waitForExpectedEvents(function()
+              {
+                  test.expectEvent(sourceBuffer, 'updateend', 'sourceBuffer');
+                  test.expectEvent(mediaElement, 'playing', 'mediaElement playing');
+                  sourceBuffer.appendBuffer(firstSegment);
+              });
+
+              test.waitForExpectedEvents(function()
+              {
+                  assert_greater_than(mediaElement.readyState, mediaElement.HAVE_CURRENT_DATA, 'Greater than HAVE_CURRENT_DATA');
+
+                  // Seek to a new position.
+                  test.expectEvent(mediaElement, 'seeking', 'mediaElement');
+                  mediaElement.currentTime = secondSegmentInfo.timecode;
+                  assert_true(mediaElement.seeking, 'mediaElement is seeking');
+
+              });
+
+              test.waitForExpectedEvents(function()
+              {
+                  assert_true(mediaElement.seeking, 'mediaElement is still seeking');
+
+                  // Seek to a second position while the first seek is still pending.
+                  test.expectEvent(mediaElement, 'seeking', 'mediaElement');
+                  mediaElement.currentTime = thirdSegmentInfo.timecode;
+                  assert_true(mediaElement.seeking, 'mediaElement is seeking');
+
+                  // Append media data for the first seek position.
+                  test.expectEvent(sourceBuffer, 'updateend', 'sourceBuffer');
+                  sourceBuffer.appendBuffer(secondSegment);
+              });
+
+              test.waitForExpectedEvents(function()
+              {
+                  assert_true(mediaElement.seeking, 'mediaElement is still seeking');
+
+                  // Append media data for the second seek position.
+                  test.expectEvent(sourceBuffer, 'updateend', 'sourceBuffer');
+                  test.expectEvent(mediaElement, 'seeked', 'mediaElement finished seek');
+                  MediaSourceUtil.appendUntilEventFires(test, mediaElement, 'seeked', sourceBuffer, mediaData, segmentInfo, segmentIndex);
+              });
+
+              test.waitForExpectedEvents(function()
+              {
+                  assert_false(mediaElement.seeking, 'mediaElement is no longer seeking');
+
+                  test.expectEvent(mediaSource, 'sourceended', 'mediaSource ended');
+                  mediaSource.endOfStream();
+              });
+
+              test.waitForExpectedEvents(function()
+              {
+                  assert_greater_than(mediaElement.readyState, mediaElement.HAVE_CURRENT_DATA, 'Greater than HAVE_CURRENT_DATA');
+                  test.done();
+              });
+          }, 'Test seeking to a new location during a pending seek.');
+        </script>
+    </body>
+</html>
diff --git a/src/third_party/web_platform_tests/media-source/mediasource-sequencemode-append-buffer.html b/src/third_party/web_platform_tests/media-source/mediasource-sequencemode-append-buffer.html
new file mode 100644
index 0000000..d2cfe35
--- /dev/null
+++ b/src/third_party/web_platform_tests/media-source/mediasource-sequencemode-append-buffer.html
@@ -0,0 +1,129 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <title>SourceBuffer.mode == "sequence" test cases.</title>
+        <script src="/resources/testharness.js"></script>
+        <script src="/resources/testharnessreport.js"></script>
+        <script src="mediasource-util.js"></script>
+    </head>
+    <body>
+        <div id="log"></div>
+        <script>
+          function mediasource_sequencemode_test(testFunction, description, options)
+          {
+              return mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
+              {
+                  assert_greater_than(segmentInfo.media.length, 3, "at least 3 media segments for supported type");
+                  mediaElement.addEventListener("error", test.unreached_func("Unexpected event 'error'"));
+                  sourceBuffer.mode = "sequence";
+                  assert_equals(sourceBuffer.mode, "sequence", "mode after setting it to \"sequence\"");
+
+                  var initSegment = MediaSourceUtil.extractSegmentData(mediaData, segmentInfo.init);
+                  test.expectEvent(sourceBuffer, "updatestart", "initSegment append started.");
+                  test.expectEvent(sourceBuffer, "update", "initSegment append success.");
+                  test.expectEvent(sourceBuffer, "updateend", "initSegment append ended.");
+                  sourceBuffer.appendBuffer(initSegment);
+                  test.waitForExpectedEvents(function()
+                  {
+                      assert_equals(sourceBuffer.timestampOffset, 0, "timestampOffset initially 0");
+                      testFunction(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData);
+                  });
+              }, description, options);
+          }
+
+          function append_segment(test, sourceBuffer, mediaData, info, callback)
+          {
+              var mediaSegment = MediaSourceUtil.extractSegmentData(mediaData, info);
+              test.expectEvent(sourceBuffer, "updatestart", "media segment append started.");
+              test.expectEvent(sourceBuffer, "update", "media segment append success.");
+              test.expectEvent(sourceBuffer, "updateend", "media segment append ended.");
+              sourceBuffer.appendBuffer(mediaSegment);
+              test.waitForExpectedEvents(callback);
+          }
+
+          function threeDecimalPlaces(number)
+          {
+              return Number(number.toFixed(3));
+          }
+
+          // Verifies expected times to 3 decimal places before and after mediaSource.endOfStream(),
+          // and calls |callback| on success.
+          function verify_offset_and_buffered(test, mediaSource, sourceBuffer,
+                                              expectedTimestampOffset, expectedBufferedRangeStartTime,
+                                              expectedBufferedRangeMaxEndTimeBeforeEOS,
+                                              expectedBufferedRangeEndTimeAfterEOS,
+                                              callback) {
+              assert_equals(threeDecimalPlaces(sourceBuffer.timestampOffset),
+                            threeDecimalPlaces(expectedTimestampOffset),
+                            "expectedTimestampOffset");
+
+              // Prior to EOS, the buffered range end time may not have fully reached the next media
+              // segment's timecode (adjusted by any timestampOffset). It should not exceed it though.
+              // Therefore, an exact assertBufferedEquals() will not work here.
+              assert_equals(sourceBuffer.buffered.length, 1, "sourceBuffer.buffered has 1 range before EOS");
+              assert_equals(threeDecimalPlaces(sourceBuffer.buffered.start(0)),
+                            threeDecimalPlaces(expectedBufferedRangeStartTime),
+                            "sourceBuffer.buffered range begins where expected before EOS");
+              assert_less_than_equal(threeDecimalPlaces(sourceBuffer.buffered.end(0)),
+                                     threeDecimalPlaces(expectedBufferedRangeMaxEndTimeBeforeEOS),
+                                     "sourceBuffer.buffered range ends at or before expected upper bound before EOS");
+
+              test.expectEvent(mediaSource, "sourceended", "mediaSource endOfStream");
+              mediaSource.endOfStream();
+              test.waitForExpectedEvents(function()
+              {
+                  assertBufferedEquals(sourceBuffer,
+                                       "{ [" + expectedBufferedRangeStartTime.toFixed(3) + ", " + expectedBufferedRangeEndTimeAfterEOS.toFixed(3) + ") }",
+                                       "sourceBuffer.buffered after EOS");
+                  callback();
+              });
+          }
+
+          mediasource_sequencemode_test(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
+          {
+              assert_equals(segmentInfo.media[0].timecode, 0, "segment starts at time 0");
+              append_segment(test, sourceBuffer, mediaData, segmentInfo.media[0], function()
+              {
+                  verify_offset_and_buffered(test, mediaSource, sourceBuffer,
+                                             0, 0,
+                                             segmentInfo.media[1].timecode + sourceBuffer.timestampOffset,
+                                             segmentInfo.media[0].highest_end_time + sourceBuffer.timestampOffset,
+                                             test.done);
+              });
+          }, "Test sequence AppendMode appendBuffer(first media segment)");
+
+          mediasource_sequencemode_test(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
+          {
+              assert_greater_than(segmentInfo.media[1].timecode, 0, "segment starts after time 0");
+              append_segment(test, sourceBuffer, mediaData, segmentInfo.media[1], function()
+              {
+                  verify_offset_and_buffered(test, mediaSource, sourceBuffer,
+                                             -segmentInfo.media[1].timecode, 0,
+                                             segmentInfo.media[2].timecode + sourceBuffer.timestampOffset,
+                                             segmentInfo.media[1].highest_end_time + sourceBuffer.timestampOffset,
+                                             test.done);
+              });
+          }, "Test sequence AppendMode appendBuffer(second media segment)");
+
+          mediasource_sequencemode_test(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
+          {
+              assert_greater_than(segmentInfo.media[1].timecode, 0, "segment starts after time 0");
+              append_segment(test, sourceBuffer, mediaData, segmentInfo.media[1], function()
+              {
+                  assert_equals(segmentInfo.media[0].timecode, 0, "segment starts at time 0");
+                  append_segment(test, sourceBuffer, mediaData, segmentInfo.media[0], function()
+                  {
+                      // Current timestampOffset should reflect offset required to put media[0]
+                      // immediately after media[1]'s highest frame end timestamp (as was adjusted
+                      // by an earlier timestampOffset).
+                      verify_offset_and_buffered(test, mediaSource, sourceBuffer,
+                                                 segmentInfo.media[1].highest_end_time - segmentInfo.media[1].timecode, 0,
+                                                 segmentInfo.media[1].timecode + sourceBuffer.timestampOffset,
+                                                 segmentInfo.media[0].highest_end_time + sourceBuffer.timestampOffset,
+                                                 test.done);
+                  })
+              });
+          }, "Test sequence AppendMode appendBuffer(second media segment, then first media segment)");
+        </script>
+    </body>
+</html>
diff --git a/src/third_party/web_platform_tests/media-source/mediasource-sourcebuffer-mode.html b/src/third_party/web_platform_tests/media-source/mediasource-sourcebuffer-mode.html
new file mode 100644
index 0000000..94843e2
--- /dev/null
+++ b/src/third_party/web_platform_tests/media-source/mediasource-sourcebuffer-mode.html
@@ -0,0 +1,140 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <title>SourceBuffer.mode test cases.</title>
+        <script src="/resources/testharness.js"></script>
+        <script src="/resources/testharnessreport.js"></script>
+        <script src="mediasource-util.js"></script>
+    </head>
+    <body>
+        <div id="log"></div>
+        <script>
+          mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
+          {
+              assert_equals(sourceBuffer.mode, 'segments', 'default append mode should be \'segments\'');
+              test.done();
+          }, 'Test initial value of SourceBuffer.mode is "segments"');
+
+          mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
+          {
+              sourceBuffer.mode = 'sequence';
+              assert_equals(sourceBuffer.mode, 'sequence', 'mode after setting it to \'sequence\'');
+
+              // Setting a mode that is not in AppendMode IDL enum should be ignored and not cause exception.
+              sourceBuffer.mode = 'invalidmode';
+              sourceBuffer.mode = null;
+              sourceBuffer.mode = '';
+              sourceBuffer.mode = 'Segments';
+              assert_equals(sourceBuffer.mode, 'sequence', 'mode unchanged by attempts to set invalid modes');
+
+              sourceBuffer.mode = 'segments';
+              assert_equals(sourceBuffer.mode, 'segments', 'mode after setting it to \'segments\'');
+              test.done();
+          }, 'Test setting SourceBuffer.mode');
+
+          mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
+          {
+              mediaSource.removeSourceBuffer(sourceBuffer);
+              assert_throws('InvalidStateError',
+                  function() { sourceBuffer.mode = 'segments'; },
+                  'Setting valid sourceBuffer.mode on removed SourceBuffer should throw InvalidStateError.');
+              test.done();
+          }, 'Test setting a removed SourceBuffer\'s mode');
+
+          mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
+          {
+              sourceBuffer.appendBuffer(mediaData);
+              assert_true(sourceBuffer.updating, 'updating attribute is true');
+              assert_throws('InvalidStateError',
+                  function() { sourceBuffer.mode = 'segments'; },
+                  'Setting valid sourceBuffer.mode on updating SourceBuffer threw InvalidStateError.');
+              test.done();
+          }, 'Test setting SourceBuffer.mode while still updating');
+
+          mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
+          {
+              test.expectEvent(sourceBuffer, 'updateend', 'Append ended.');
+              sourceBuffer.appendBuffer(mediaData);
+
+              test.waitForExpectedEvents(function()
+              {
+                  assert_false(sourceBuffer.updating, 'updating attribute is false');
+
+                  test.expectEvent(mediaSource, 'sourceended', 'MediaSource sourceended event');
+                  mediaSource.endOfStream();
+                  assert_equals(mediaSource.readyState, 'ended', 'MediaSource readyState is \'ended\'');
+              });
+
+              test.waitForExpectedEvents(function()
+              {
+                  assert_equals(mediaSource.readyState, 'ended', 'MediaSource readyState is \'ended\'');
+
+                  test.expectEvent(mediaSource, 'sourceopen', 'MediaSource sourceopen event');
+                  sourceBuffer.mode = 'segments';
+
+                  assert_equals(mediaSource.readyState, 'open', 'MediaSource readyState is \'open\'');
+              });
+
+              test.waitForExpectedEvents(function()
+              {
+                  assert_equals(mediaSource.readyState, 'open', 'MediaSource readyState is \'open\'');
+                  test.done();
+              });
+          }, 'Test setting SourceBuffer.mode triggers parent MediaSource \'ended\' to \'open\' transition.');
+
+          mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
+          {
+              var initSegment = MediaSourceUtil.extractSegmentData(mediaData, segmentInfo.init);
+              var fullMediaSegment = MediaSourceUtil.extractSegmentData(mediaData, segmentInfo.media[0]);
+              var truncateAt = Math.floor(segmentInfo.media[0].size * 0.5);  // Pick first 50% of segment bytes.
+              var partialMediaSegment = fullMediaSegment.subarray(0, truncateAt);
+              var mediaSegmentRemainder = fullMediaSegment.subarray(truncateAt);
+
+              // Append init segment.
+              test.expectEvent(sourceBuffer, 'updateend', 'Init segment append ended.');
+              sourceBuffer.appendBuffer(initSegment);
+
+              test.waitForExpectedEvents(function()
+              {
+                  assert_false(sourceBuffer.updating, 'updating attribute is false');
+                  assert_equals(sourceBuffer.mode, 'segments');
+                  sourceBuffer.mode = 'segments';  // No exception should occur.
+                  assert_equals(sourceBuffer.timestampOffset, 0.0);
+                  sourceBuffer.timestampOffset = 10.123456789;  // No exception should occur.
+                  assert_equals(sourceBuffer.timestampOffset, 10.123456789);  // Super-precise offsets should round-trip.
+
+                  // Append first part of media segment.
+                  test.expectEvent(sourceBuffer, 'updateend', 'Partial media segment append ended.');
+                  sourceBuffer.appendBuffer(partialMediaSegment);
+              });
+
+              test.waitForExpectedEvents(function()
+              {
+                  assert_false(sourceBuffer.updating, 'updating attribute is false');
+                  assert_equals(sourceBuffer.mode, 'segments');
+                  assert_throws('InvalidStateError',
+                      function() { sourceBuffer.mode = 'segments'; },
+                      'Setting valid sourceBuffer.mode while still parsing media segment threw InvalidStateError.');
+                  assert_equals(sourceBuffer.timestampOffset, 10.123456789);
+                  assert_throws('InvalidStateError',
+                      function() { sourceBuffer.timestampOffset = 20.0; },
+                      'Setting valid sourceBuffer.timestampOffset while still parsing media segment threw InvalidStateError.');
+
+                  // Append remainder of media segment.
+                  test.expectEvent(sourceBuffer, 'updateend', 'Append ended of remainder of media segment.');
+                  sourceBuffer.appendBuffer(mediaSegmentRemainder);
+              });
+
+              test.waitForExpectedEvents(function()
+              {
+                  assert_false(sourceBuffer.updating, 'updating attribute is false');
+                  assert_equals(sourceBuffer.mode, 'segments');
+                  sourceBuffer.mode = 'segments';  // No exception should occur.
+                  assert_equals(sourceBuffer.timestampOffset, 10.123456789);
+                  sourceBuffer.timestampOffset = 20.0;  // No exception should occur.
+                  test.done();
+              });
+          }, 'Test setting SourceBuffer.mode and SourceBuffer.timestampOffset while parsing media segment.');
+        </script>
+    </body>
+</html>
diff --git a/src/third_party/web_platform_tests/media-source/mediasource-sourcebufferlist.html b/src/third_party/web_platform_tests/media-source/mediasource-sourcebufferlist.html
new file mode 100644
index 0000000..31757ac
--- /dev/null
+++ b/src/third_party/web_platform_tests/media-source/mediasource-sourcebufferlist.html
@@ -0,0 +1,83 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <title>SourceBufferList test cases.</title>
+        <script src="/resources/testharness.js"></script>
+        <script src="/resources/testharnessreport.js"></script>
+        <script src="mediasource-util.js"></script>
+    </head>
+    <body>
+        <div id="log"></div>
+        <script>
+          function verifySourceBufferLists(mediaSource, expected)
+          {
+              assert_equals(mediaSource.sourceBuffers.length, expected.length, "sourceBuffers length");
+              assert_equals(mediaSource.activeSourceBuffers.length, 0, "activeSourceBuffers length");
+              for (var i = 0; i < expected.length; ++i)
+                assert_equals(mediaSource.sourceBuffers[i], expected[i], "Verifying mediaSource.sourceBuffers[" + i + "]");
+          }
+
+          mediasource_test(function(test, mediaElement, mediaSource)
+          {
+              test.expectEvent(mediaSource.sourceBuffers, "addsourcebuffer", "sourceBuffers");
+              var sourceBufferA = mediaSource.addSourceBuffer(MediaSourceUtil.VIDEO_ONLY_TYPE);
+              var sourceBufferB = null;
+
+              test.waitForExpectedEvents(function()
+              {
+                  test.expectEvent(mediaSource.sourceBuffers, "addsourcebuffer", "sourceBuffers");
+                  sourceBufferB = mediaSource.addSourceBuffer(MediaSourceUtil.AUDIO_ONLY_TYPE);
+
+                  verifySourceBufferLists(mediaSource, [sourceBufferA, sourceBufferB]);
+              });
+
+              test.waitForExpectedEvents(function()
+              {
+                  test.expectEvent(mediaSource.sourceBuffers, "removesourcebuffer", "sourceBuffers");
+                  mediaSource.removeSourceBuffer(sourceBufferA);
+
+                  verifySourceBufferLists(mediaSource, [sourceBufferB]);
+
+                  test.expectEvent(mediaSource.sourceBuffers, "addsourcebuffer", "sourceBuffers");
+                  sourceBufferA = mediaSource.addSourceBuffer(MediaSourceUtil.VIDEO_ONLY_TYPE);
+
+                  verifySourceBufferLists(mediaSource, [sourceBufferB, sourceBufferA]);
+              });
+
+              test.waitForExpectedEvents(function()
+              {
+                  test.done();
+              });
+          }, "Test SourceBufferList event dispatching.");
+
+          mediasource_test(function(test, mediaElement, mediaSource)
+          {
+              test.expectEvent(mediaSource.sourceBuffers, "addsourcebuffer", "sourceBuffers");
+              test.expectEvent(mediaSource.sourceBuffers, "addsourcebuffer", "sourceBuffers");
+              var sourceBufferA = mediaSource.addSourceBuffer(MediaSourceUtil.VIDEO_ONLY_TYPE);
+              var sourceBufferB = mediaSource.addSourceBuffer(MediaSourceUtil.AUDIO_ONLY_TYPE);
+
+              verifySourceBufferLists(mediaSource, [sourceBufferA, sourceBufferB]);
+
+              test.waitForExpectedEvents(function()
+              {
+                  verifySourceBufferLists(mediaSource, [sourceBufferA, sourceBufferB]);
+
+                  // Force the media element to close the MediaSource object.
+                  test.expectEvent(mediaSource.sourceBuffers, "removesourcebuffer", "sourceBuffers");
+                  test.expectEvent(mediaSource, "sourceclose", "mediaSource closing");
+                  mediaElement.src = "";
+              });
+
+              test.waitForExpectedEvents(function()
+              {
+                  assert_equals(mediaSource.readyState, "closed", "mediaSource is closed.");
+
+                  verifySourceBufferLists(mediaSource, []);
+                  test.done();
+              });
+          }, "Test that only 1 removesourcebuffer event fires on each SourceBufferList when the MediaSource closes.");
+
+        </script>
+    </body>
+</html>
diff --git a/src/third_party/web_platform_tests/media-source/mediasource-timestamp-offset.html b/src/third_party/web_platform_tests/media-source/mediasource-timestamp-offset.html
new file mode 100644
index 0000000..728dc2c
--- /dev/null
+++ b/src/third_party/web_platform_tests/media-source/mediasource-timestamp-offset.html
@@ -0,0 +1,121 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <title>SourceBuffer.timestampOffset test cases.</title>
+        <script src="/resources/testharness.js"></script>
+        <script src="/resources/testharnessreport.js"></script>
+        <script src="mediasource-util.js"></script>
+    </head>
+    <body>
+        <div id="log"></div>
+        <script>
+          function simpleTimestampOffsetTest(value, expected, description)
+          {
+              mediasource_test(function(test, mediaElement, mediaSource)
+              {
+                  var segmentInfo = MediaSourceUtil.SEGMENT_INFO;
+                  var sourceBuffer = mediaSource.addSourceBuffer(segmentInfo.type);
+
+                  if (expected == "TypeError")  {
+                      assert_throws({name: "TypeError"},
+                          function() { sourceBuffer.timestampOffset = value; },
+                          "setting timestampOffset to " + description + " throws an exception.");
+                  } else {
+                      sourceBuffer.timestampOffset = value;
+                      assert_equals(sourceBuffer.timestampOffset, expected);
+                  }
+
+                  test.done();
+              }, "Test setting SourceBuffer.timestampOffset to " + description + ".");
+          }
+
+          simpleTimestampOffsetTest(10.5, 10.5, "a positive number");
+          simpleTimestampOffsetTest(-10.4, -10.4, "a negative number");
+          simpleTimestampOffsetTest(0, 0, "zero");
+          simpleTimestampOffsetTest(Number.POSITIVE_INFINITY, "TypeError", "positive infinity");
+          simpleTimestampOffsetTest(Number.NEGATIVE_INFINITY, "TypeError", "negative infinity");
+          simpleTimestampOffsetTest(Number.NaN, "TypeError", "NaN");
+          simpleTimestampOffsetTest(undefined, "TypeError", "undefined");
+          simpleTimestampOffsetTest(null, 0, "null");
+          simpleTimestampOffsetTest(false, 0, "false");
+          simpleTimestampOffsetTest(true, 1, "true");
+          simpleTimestampOffsetTest("10.5", 10.5, "a number string");
+          simpleTimestampOffsetTest("", 0, "an empty string");
+
+          mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
+          {
+              var initSegment = MediaSourceUtil.extractSegmentData(mediaData, segmentInfo.init);
+              var mediaSegment = MediaSourceUtil.extractSegmentData(mediaData, segmentInfo.media[0]);
+
+              test.expectEvent(sourceBuffer, "updateend", "initSegment append ended.");
+              sourceBuffer.appendBuffer(initSegment);
+
+              test.waitForExpectedEvents(function()
+              {
+                  test.expectEvent(sourceBuffer, "updateend", "mediaSegment append ended.");
+                  sourceBuffer.appendBuffer(mediaSegment);
+              });
+
+              test.waitForExpectedEvents(function()
+              {
+                  mediaSource.endOfStream();
+
+                  assert_equals(mediaSource.readyState, "ended");
+
+                  mediaSource.sourceBuffers[0].timestampOffset = 2;
+
+                  assert_equals(mediaSource.readyState, "open");
+
+                  test.expectEvent(mediaSource, "sourceopen", "mediaSource fired 'sourceopen' event.");
+              });
+
+              test.waitForExpectedEvents(function()
+              {
+                  test.done();
+              });
+          }, "Test setting timestampOffset in 'ended' state causes a transition to 'open'.");
+
+          mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
+          {
+              var initSegment = MediaSourceUtil.extractSegmentData(mediaData, segmentInfo.init);
+              var mediaSegment = MediaSourceUtil.extractSegmentData(mediaData, segmentInfo.media[0]);
+
+              test.expectEvent(sourceBuffer, "updateend", "initSegment append ended.");
+              sourceBuffer.appendBuffer(initSegment);
+              assert_equals(mediaSource.sourceBuffers[0].timestampOffset, 0, "read initial value");
+
+              test.waitForExpectedEvents(function()
+              {
+                  test.expectEvent(sourceBuffer, "updateend", "mediaSegment append ended.");
+                  sourceBuffer.appendBuffer(mediaSegment);
+                  assert_equals(mediaSource.sourceBuffers[0].timestampOffset, 0,
+                      "No change to timestampoffset after segments mode init segment append");
+              });
+
+              test.waitForExpectedEvents(function()
+              {
+                  assert_equals(mediaSource.sourceBuffers[0].timestampOffset, 0,
+                      "No change to timestampoffset after segments mode media segment append");
+                  test.done();
+              });
+          }, "Test getting the initial value of timestampOffset.");
+
+          mediasource_test(function(test, mediaElement, mediaSource)
+          {
+              var sourceBuffer = mediaSource.addSourceBuffer(MediaSourceUtil.AUDIO_VIDEO_TYPE);
+              assert_true(sourceBuffer != null, "New SourceBuffer returned");
+
+              mediaSource.removeSourceBuffer(sourceBuffer);
+              assert_true(mediaSource.sourceBuffers.length == 0, "MediaSource.sourceBuffers is empty");
+              assert_true(mediaSource.activeSourceBuffers.length == 0, "MediaSource.activesourceBuffers is empty");
+
+              assert_throws("InvalidStateError", function()
+              {
+                  sourceBuffer.timestampOffset = 10;
+              });
+
+              test.done();
+          }, "Test setting timestampoffset after removing the sourcebuffer.");
+        </script>
+    </body>
+</html>
diff --git a/src/third_party/web_platform_tests/media-source/mediasource-util.js b/src/third_party/web_platform_tests/media-source/mediasource-util.js
new file mode 100644
index 0000000..036df89
--- /dev/null
+++ b/src/third_party/web_platform_tests/media-source/mediasource-util.js
@@ -0,0 +1,416 @@
+(function(window) {
+    var SEGMENT_INFO_LIST = [
+        {
+            url: 'mp4/test.mp4',
+            type: 'video/mp4; codecs="mp4a.40.2,avc1.4d400d"',
+            duration: 6.0756,
+            init: { offset: 0, size: 1197 },
+            media: [
+                { offset: 1241, size: 17845, timecode: 0.000000 },
+                { offset: 19130, size: 5551, timecode: 0.464800 },
+                { offset: 24725, size: 10944, timecode: 0.763600 },
+                { offset: 35713, size: 7131, timecode: 0.863200 },
+                { offset: 42888, size: 2513, timecode: 1.128800 },
+                { offset: 45457, size: 3022, timecode: 1.261600 },
+                { offset: 48479, size: 815, timecode: 1.427600 },
+                { offset: 49338, size: 2818, timecode: 1.460800 },
+                { offset: 52200, size: 11581, timecode: 1.593600 },
+                { offset: 63825, size: 3003, timecode: 1.726400 },
+                { offset: 66872, size: 6390, timecode: 1.892400 },
+                { offset: 73306, size: 3740, timecode: 2.124800 },
+                { offset: 77102, size: 11779, timecode: 2.324000 },
+                { offset: 88881, size: 851, timecode: 2.490000 },
+                { offset: 89776, size: 4236, timecode: 2.523200 },
+                { offset: 94056, size: 9538, timecode: 2.755600 },
+                { offset: 103638, size: 13295, timecode: 3.154000 },
+                { offset: 116977, size: 309, timecode: 3.386400 },
+                { offset: 117330, size: 5806, timecode: 3.419600 },
+                { offset: 123180, size: 4392, timecode: 3.751600 },
+                { offset: 127616, size: 15408, timecode: 3.984000 },
+                { offset: 143068, size: 9899, timecode: 4.216400 },
+                { offset: 153011, size: 11562, timecode: 4.780800 },
+                { offset: 164617, size: 7398, timecode: 4.946800 },
+                { offset: 172059, size: 5698, timecode: 5.212400 },
+                { offset: 177801, size: 11682, timecode: 5.511200 },
+                { offset: 189527, size: 3023, timecode: 5.677200 },
+                { offset: 192594, size: 5726, timecode: 5.843200 },
+            ]
+        },
+        {
+            url: 'webm/test.webm',
+            type: 'video/webm; codecs="vp8, vorbis"',
+            duration: 6.042,
+            init: { offset: 0, size: 4357 },
+            media: [
+                {  offset: 4357, size: 11830, timecode: 0 },
+                {  offset: 16187, size: 12588, timecode: 0.385 },
+                {  offset: 28775, size: 14588, timecode: 0.779 },
+                {  offset: 43363, size: 13023, timecode: 1.174 },
+                {  offset: 56386, size: 13127, timecode: 1.592 },
+                {  offset: 69513, size: 14456, timecode: 1.987 },
+                {  offset: 83969, size: 13458, timecode: 2.381 },
+                {  offset: 97427, size: 14566, timecode: 2.776 },
+                {  offset: 111993, size: 13201, timecode: 3.171 },
+                {  offset: 125194, size: 14061, timecode: 3.566 },
+                {  offset: 139255, size: 15353, timecode: 3.96 },
+                {  offset: 154608, size: 13618, timecode: 4.378 },
+                {  offset: 168226, size: 15094, timecode: 4.773 },
+                {  offset: 183320, size: 13069, timecode: 5.168 },
+                {  offset: 196389, size: 13788, timecode: 5.563 },
+                {  offset: 210177, size: 9009, timecode: 5.957 },
+            ],
+        }
+    ];
+    EventExpectationsManager = function(test)
+    {
+        this.test_ = test;
+        this.eventTargetList_ = [];
+        this.waitCallbacks_ = [];
+    };
+
+    EventExpectationsManager.prototype.expectEvent = function(object, eventName, description)
+    {
+        var eventInfo = { 'target': object, 'type': eventName, 'description': description};
+        var expectations = this.getExpectations_(object);
+        expectations.push(eventInfo);
+
+        var t = this;
+        var waitHandler = this.test_.step_func(this.handleWaitCallback_.bind(this));
+        var eventHandler = this.test_.step_func(function(event)
+        {
+            object.removeEventListener(eventName, eventHandler);
+            var expected = expectations[0];
+            assert_equals(event.target, expected.target, "Event target match.");
+            assert_equals(event.type, expected.type, "Event types match.");
+            assert_equals(eventInfo.description, expected.description, "Descriptions match for '" +  event.type + "'.");
+
+            expectations.shift(1);
+            if (t.waitCallbacks_.length > 0)
+                setTimeout(waitHandler, 0);
+        });
+        object.addEventListener(eventName, eventHandler);
+    };
+
+    EventExpectationsManager.prototype.waitForExpectedEvents = function(callback)
+    {
+        this.waitCallbacks_.push(callback);
+        setTimeout(this.test_.step_func(this.handleWaitCallback_.bind(this)), 0);
+    };
+
+    EventExpectationsManager.prototype.expectingEvents = function()
+    {
+        for (var i = 0; i < this.eventTargetList_.length; ++i) {
+            if (this.eventTargetList_[i].expectations.length > 0) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    EventExpectationsManager.prototype.handleWaitCallback_ = function()
+    {
+        if (this.waitCallbacks_.length == 0 || this.expectingEvents())
+            return;
+        var callback = this.waitCallbacks_.shift(1);
+        callback();
+    };
+
+    EventExpectationsManager.prototype.getExpectations_ = function(target)
+    {
+        for (var i = 0; i < this.eventTargetList_.length; ++i) {
+            var info = this.eventTargetList_[i];
+            if (info.target == target) {
+                return info.expectations;
+            }
+        }
+        var expectations = [];
+        this.eventTargetList_.push({ 'target': target, 'expectations': expectations });
+        return expectations;
+    };
+
+    function loadData_(test, url, callback, isBinary)
+    {
+        var request = new XMLHttpRequest();
+        request.open("GET", url, true);
+        if (isBinary) {
+            request.responseType = 'arraybuffer';
+        }
+        request.onload = test.step_func(function(event)
+        {
+            if (request.status != 200) {
+                assert_unreached("Unexpected status code : " + request.status);
+                return;
+            }
+            var response = request.response;
+            if (isBinary) {
+                response = new Uint8Array(response);
+            }
+            callback(response);
+        });
+        request.onerror = test.step_func(function(event)
+        {
+            assert_unreached("Unexpected error");
+        });
+        request.send();
+    }
+
+    function openMediaSource_(test, mediaTag, callback)
+    {
+        var mediaSource = new MediaSource();
+        var mediaSourceURL = URL.createObjectURL(mediaSource);
+
+        var eventHandler = test.step_func(onSourceOpen);
+        function onSourceOpen(event)
+        {
+            mediaSource.removeEventListener('sourceopen', eventHandler);
+            URL.revokeObjectURL(mediaSourceURL);
+            callback(mediaSource);
+        }
+
+        mediaSource.addEventListener('sourceopen', eventHandler);
+        mediaTag.src = mediaSourceURL;
+    }
+
+    var MediaSourceUtil = {};
+
+    MediaSourceUtil.loadTextData = function(test, url, callback)
+    {
+        loadData_(test, url, callback, false);
+    };
+
+    MediaSourceUtil.loadBinaryData = function(test, url, callback)
+    {
+        loadData_(test, url, callback, true);
+    };
+
+    MediaSourceUtil.fetchManifestAndData = function(test, manifestFilename, callback)
+    {
+        var baseURL = '';
+        var manifestURL = baseURL + manifestFilename;
+        MediaSourceUtil.loadTextData(test, manifestURL, function(manifestText)
+        {
+            var manifest = JSON.parse(manifestText);
+
+            assert_true(MediaSource.isTypeSupported(manifest.type), manifest.type + " is supported.");
+
+            var mediaURL = baseURL + manifest.url;
+            MediaSourceUtil.loadBinaryData(test, mediaURL, function(mediaData)
+            {
+                callback(manifest.type, mediaData);
+            });
+        });
+    };
+
+    MediaSourceUtil.extractSegmentData = function(mediaData, info)
+    {
+        var start = info.offset;
+        var end = start + info.size;
+        return mediaData.subarray(start, end);
+    }
+
+    MediaSourceUtil.getMediaDataForPlaybackTime = function(mediaData, segmentInfo, playbackTimeToAdd)
+    {
+        assert_less_than_equal(playbackTimeToAdd, segmentInfo.duration);
+        var mediaInfo = segmentInfo.media;
+        var start = mediaInfo[0].offset;
+        var numBytes = 0;
+        var segmentIndex = 0;
+        while (segmentIndex < mediaInfo.length && mediaInfo[segmentIndex].timecode <= playbackTimeToAdd)
+        {
+          numBytes += mediaInfo[segmentIndex].size;
+          ++segmentIndex;
+        }
+        return mediaData.subarray(start, numBytes + start);
+    }
+
+    function getFirstSupportedType(typeList)
+    {
+        for (var i = 0; i < typeList.length; ++i) {
+            if (window.MediaSource && MediaSource.isTypeSupported(typeList[i]))
+                return typeList[i];
+        }
+        return "";
+    }
+
+    function getSegmentInfo()
+    {
+        for (var i = 0; i < SEGMENT_INFO_LIST.length; ++i) {
+            var segmentInfo = SEGMENT_INFO_LIST[i];
+            if (window.MediaSource && MediaSource.isTypeSupported(segmentInfo.type)) {
+                return segmentInfo;
+            }
+        }
+        return null;
+    }
+
+    var audioOnlyTypes = ['audio/mp4;codecs="mp4a.40.2"', 'audio/webm;codecs="vorbis"'];
+    var videoOnlyTypes = ['video/mp4;codecs="avc1.4D4001"', 'video/webm;codecs="vp8"'];
+    var audioVideoTypes = ['video/mp4;codecs="avc1.4D4001,mp4a.40.2"', 'video/webm;codecs="vp8,vorbis"'];
+    MediaSourceUtil.AUDIO_ONLY_TYPE = getFirstSupportedType(audioOnlyTypes);
+    MediaSourceUtil.VIDEO_ONLY_TYPE = getFirstSupportedType(videoOnlyTypes);
+    MediaSourceUtil.AUDIO_VIDEO_TYPE = getFirstSupportedType(audioVideoTypes);
+    MediaSourceUtil.SEGMENT_INFO = getSegmentInfo();
+
+    MediaSourceUtil.getSubType = function(mimetype) {
+        var slashIndex = mimetype.indexOf("/");
+        var semicolonIndex = mimetype.indexOf(";");
+        if (slashIndex <= 0) {
+            assert_unreached("Invalid mimetype '" + mimetype + "'");
+            return;
+        }
+
+        var start = slashIndex + 1;
+        if (semicolonIndex >= 0) {
+            if (semicolonIndex <= start) {
+                assert_unreached("Invalid mimetype '" + mimetype + "'");
+                return;
+            }
+
+            return mimetype.substr(start, semicolonIndex - start)
+        }
+
+        return mimetype.substr(start);
+    };
+
+    MediaSourceUtil.append = function(test, sourceBuffer, data, callback)
+    {
+        function onUpdate() {
+            sourceBuffer.removeEventListener("update", onUpdate);
+            callback();
+        }
+        sourceBuffer.addEventListener("update", onUpdate);
+
+        sourceBuffer.addEventListener('error', test.unreached_func("Unexpected event 'error'"));
+
+        sourceBuffer.appendBuffer(data);
+    };
+
+    MediaSourceUtil.appendUntilEventFires = function(test, mediaElement, eventName, sourceBuffer, mediaData, segmentInfo, startingIndex)
+    {
+        var eventFired = false;
+        function onEvent() {
+            mediaElement.removeEventListener(eventName, onEvent);
+            eventFired = true;
+        }
+        mediaElement.addEventListener(eventName, onEvent);
+
+        var i = startingIndex;
+        var onAppendDone = function() {
+            if (eventFired)
+                return;
+
+            i++;
+            MediaSourceUtil.append(test, sourceBuffer, MediaSourceUtil.extractSegmentData(mediaData, segmentInfo.media[i]), onAppendDone);
+        };
+        MediaSourceUtil.append(test, sourceBuffer, MediaSourceUtil.extractSegmentData(mediaData, segmentInfo.media[i]), onAppendDone);
+
+    };
+
+    function addExtraTestMethods(test)
+    {
+        test.eventExpectations_ = new EventExpectationsManager(test);
+        test.expectEvent = function(object, eventName, description)
+        {
+            test.eventExpectations_.expectEvent(object, eventName, description);
+        };
+
+        test.waitForExpectedEvents = function(callback)
+        {
+            test.eventExpectations_.waitForExpectedEvents(callback);
+        };
+
+        test.waitForCurrentTimeChange = function(mediaElement, callback)
+        {
+            var initialTime = mediaElement.currentTime;
+
+            var onTimeUpdate = test.step_func(function()
+            {
+                if (mediaElement.currentTime != initialTime) {
+                    mediaElement.removeEventListener('timeupdate', onTimeUpdate);
+                    callback();
+                }
+            });
+
+            mediaElement.addEventListener('timeupdate', onTimeUpdate);
+        }
+
+        var oldTestDone = test.done.bind(test);
+        test.done = function()
+        {
+            if (test.status == test.PASS) {
+                assert_false(test.eventExpectations_.expectingEvents(), "No pending event expectations.");
+            }
+            oldTestDone();
+        };
+    };
+
+    window['MediaSourceUtil'] = MediaSourceUtil;
+    window['media_test'] = function(testFunction, description, options)
+    {
+        options = options || {};
+        return async_test(function(test)
+        {
+            addExtraTestMethods(test);
+            testFunction(test);
+        }, description, options);
+    };
+    window['mediasource_test'] = function(testFunction, description, options)
+    {
+        return media_test(function(test)
+        {
+            var mediaTag = document.createElement("video");
+            document.body.appendChild(mediaTag);
+
+            test.removeMediaElement_ = true;
+            test.add_cleanup(function()
+            {
+                if (test.removeMediaElement_) {
+                    document.body.removeChild(mediaTag);
+                    test.removeMediaElement_ = false;
+                }
+            });
+
+            openMediaSource_(test, mediaTag, function(mediaSource)
+            {
+                testFunction(test, mediaTag, mediaSource);
+            });
+        }, description, options);
+    };
+
+    window['mediasource_testafterdataloaded'] = function(testFunction, description, options)
+    {
+        mediasource_test(function(test, mediaElement, mediaSource)
+        {
+            var segmentInfo = MediaSourceUtil.SEGMENT_INFO;
+
+            if (!segmentInfo) {
+                assert_unreached("No segment info compatible with this MediaSource implementation.");
+                return;
+            }
+
+            mediaElement.addEventListener('error', test.unreached_func("Unexpected event 'error'"));
+
+            var sourceBuffer = mediaSource.addSourceBuffer(segmentInfo.type);
+            MediaSourceUtil.loadBinaryData(test, segmentInfo.url, function(mediaData)
+            {
+                testFunction(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData);
+            });
+        }, description, options);
+    }
+
+    function timeRangesToString(ranges)
+    {
+        var s = "{";
+        for (var i = 0; i < ranges.length; ++i) {
+            s += " [" + ranges.start(i).toFixed(3) + ", " + ranges.end(i).toFixed(3) + ")";
+        }
+        return s + " }";
+    }
+
+    window['assertBufferedEquals'] = function(obj, expected, description)
+    {
+        var actual = timeRangesToString(obj.buffered);
+        assert_equals(actual, expected, description);
+    };
+
+})(window);
diff --git a/src/third_party/web_platform_tests/media-source/mp4/test-a-128k-44100Hz-1ch-manifest.json b/src/third_party/web_platform_tests/media-source/mp4/test-a-128k-44100Hz-1ch-manifest.json
new file mode 100644
index 0000000..f3caa46
--- /dev/null
+++ b/src/third_party/web_platform_tests/media-source/mp4/test-a-128k-44100Hz-1ch-manifest.json
@@ -0,0 +1,4 @@
+{
+    "url": "mp4/test-a-128k-44100Hz-1ch.mp4",
+    "type": "audio/mp4;codecs=\"mp4a.40.2\""
+}
\ No newline at end of file
diff --git a/src/third_party/web_platform_tests/media-source/mp4/test-a-128k-44100Hz-1ch.mp4 b/src/third_party/web_platform_tests/media-source/mp4/test-a-128k-44100Hz-1ch.mp4
new file mode 100644
index 0000000..fc7832a
--- /dev/null
+++ b/src/third_party/web_platform_tests/media-source/mp4/test-a-128k-44100Hz-1ch.mp4
Binary files differ
diff --git a/src/third_party/web_platform_tests/media-source/mp4/test-a-192k-44100Hz-1ch-manifest.json b/src/third_party/web_platform_tests/media-source/mp4/test-a-192k-44100Hz-1ch-manifest.json
new file mode 100644
index 0000000..41a6f33
--- /dev/null
+++ b/src/third_party/web_platform_tests/media-source/mp4/test-a-192k-44100Hz-1ch-manifest.json
@@ -0,0 +1,4 @@
+{
+    "url": "mp4/test-a-192k-44100Hz-1ch.mp4",
+    "type": "audio/mp4;codecs=\"mp4a.40.2\""
+}
\ No newline at end of file
diff --git a/src/third_party/web_platform_tests/media-source/mp4/test-a-192k-44100Hz-1ch.mp4 b/src/third_party/web_platform_tests/media-source/mp4/test-a-192k-44100Hz-1ch.mp4
new file mode 100644
index 0000000..864a87d
--- /dev/null
+++ b/src/third_party/web_platform_tests/media-source/mp4/test-a-192k-44100Hz-1ch.mp4
Binary files differ
diff --git a/src/third_party/web_platform_tests/media-source/mp4/test-av-384k-44100Hz-1ch-320x240-30fps-10kfr-manifest.json b/src/third_party/web_platform_tests/media-source/mp4/test-av-384k-44100Hz-1ch-320x240-30fps-10kfr-manifest.json
new file mode 100644
index 0000000..7731e31
--- /dev/null
+++ b/src/third_party/web_platform_tests/media-source/mp4/test-av-384k-44100Hz-1ch-320x240-30fps-10kfr-manifest.json
@@ -0,0 +1,4 @@
+{
+    "url": "mp4/test-av-384k-44100Hz-1ch-320x240-30fps-10kfr.mp4",
+    "type": "video/mp4;codecs=\"avc1.4D4001,mp4a.40.2\""
+}
\ No newline at end of file
diff --git a/src/third_party/web_platform_tests/media-source/mp4/test-av-384k-44100Hz-1ch-320x240-30fps-10kfr.mp4 b/src/third_party/web_platform_tests/media-source/mp4/test-av-384k-44100Hz-1ch-320x240-30fps-10kfr.mp4
new file mode 100644
index 0000000..e623e8e
--- /dev/null
+++ b/src/third_party/web_platform_tests/media-source/mp4/test-av-384k-44100Hz-1ch-320x240-30fps-10kfr.mp4
Binary files differ
diff --git a/src/third_party/web_platform_tests/media-source/mp4/test-av-384k-44100Hz-1ch-640x480-30fps-10kfr-manifest.json b/src/third_party/web_platform_tests/media-source/mp4/test-av-384k-44100Hz-1ch-640x480-30fps-10kfr-manifest.json
new file mode 100644
index 0000000..78ded61
--- /dev/null
+++ b/src/third_party/web_platform_tests/media-source/mp4/test-av-384k-44100Hz-1ch-640x480-30fps-10kfr-manifest.json
@@ -0,0 +1,4 @@
+{
+    "url": "mp4/test-av-384k-44100Hz-1ch-640x480-30fps-10kfr.mp4",
+    "type": "video/mp4;codecs=\"avc1.4D4001,mp4a.40.2\""
+}
\ No newline at end of file
diff --git a/src/third_party/web_platform_tests/media-source/mp4/test-av-384k-44100Hz-1ch-640x480-30fps-10kfr.mp4 b/src/third_party/web_platform_tests/media-source/mp4/test-av-384k-44100Hz-1ch-640x480-30fps-10kfr.mp4
new file mode 100644
index 0000000..946167b
--- /dev/null
+++ b/src/third_party/web_platform_tests/media-source/mp4/test-av-384k-44100Hz-1ch-640x480-30fps-10kfr.mp4
Binary files differ
diff --git a/src/third_party/web_platform_tests/media-source/mp4/test-av-448k-44100Hz-1ch-640x480-30fps-10kfr-manifest.json b/src/third_party/web_platform_tests/media-source/mp4/test-av-448k-44100Hz-1ch-640x480-30fps-10kfr-manifest.json
new file mode 100644
index 0000000..ba46349
--- /dev/null
+++ b/src/third_party/web_platform_tests/media-source/mp4/test-av-448k-44100Hz-1ch-640x480-30fps-10kfr-manifest.json
@@ -0,0 +1,4 @@
+{
+    "url": "mp4/test-av-448k-44100Hz-1ch-640x480-30fps-10kfr.mp4",
+    "type": "video/mp4;codecs=\"avc1.4D4001,mp4a.40.2\""
+}
\ No newline at end of file
diff --git a/src/third_party/web_platform_tests/media-source/mp4/test-av-448k-44100Hz-1ch-640x480-30fps-10kfr.mp4 b/src/third_party/web_platform_tests/media-source/mp4/test-av-448k-44100Hz-1ch-640x480-30fps-10kfr.mp4
new file mode 100644
index 0000000..ace4bee
--- /dev/null
+++ b/src/third_party/web_platform_tests/media-source/mp4/test-av-448k-44100Hz-1ch-640x480-30fps-10kfr.mp4
Binary files differ
diff --git a/src/third_party/web_platform_tests/media-source/mp4/test-av-640k-44100Hz-1ch-640x480-30fps-10kfr-manifest.json b/src/third_party/web_platform_tests/media-source/mp4/test-av-640k-44100Hz-1ch-640x480-30fps-10kfr-manifest.json
new file mode 100644
index 0000000..24da9b4
--- /dev/null
+++ b/src/third_party/web_platform_tests/media-source/mp4/test-av-640k-44100Hz-1ch-640x480-30fps-10kfr-manifest.json
@@ -0,0 +1,4 @@
+{
+    "url": "mp4/test-av-640k-44100Hz-1ch-640x480-30fps-10kfr.mp4",
+    "type": "video/mp4;codecs=\"avc1.4D4001,mp4a.40.2\""
+}
\ No newline at end of file
diff --git a/src/third_party/web_platform_tests/media-source/mp4/test-av-640k-44100Hz-1ch-640x480-30fps-10kfr.mp4 b/src/third_party/web_platform_tests/media-source/mp4/test-av-640k-44100Hz-1ch-640x480-30fps-10kfr.mp4
new file mode 100644
index 0000000..f224a54
--- /dev/null
+++ b/src/third_party/web_platform_tests/media-source/mp4/test-av-640k-44100Hz-1ch-640x480-30fps-10kfr.mp4
Binary files differ
diff --git a/src/third_party/web_platform_tests/media-source/mp4/test-v-128k-320x240-24fps-8kfr-manifest.json b/src/third_party/web_platform_tests/media-source/mp4/test-v-128k-320x240-24fps-8kfr-manifest.json
new file mode 100644
index 0000000..a31b6d0
--- /dev/null
+++ b/src/third_party/web_platform_tests/media-source/mp4/test-v-128k-320x240-24fps-8kfr-manifest.json
@@ -0,0 +1,4 @@
+{
+    "url": "mp4/test-v-128k-320x240-24fps-8kfr.mp4",
+    "type": "video/mp4;codecs=\"avc1.4D4001\""
+}
\ No newline at end of file
diff --git a/src/third_party/web_platform_tests/media-source/mp4/test-v-128k-320x240-24fps-8kfr.mp4 b/src/third_party/web_platform_tests/media-source/mp4/test-v-128k-320x240-24fps-8kfr.mp4
new file mode 100644
index 0000000..cc55f40
--- /dev/null
+++ b/src/third_party/web_platform_tests/media-source/mp4/test-v-128k-320x240-24fps-8kfr.mp4
Binary files differ
diff --git a/src/third_party/web_platform_tests/media-source/mp4/test-v-128k-320x240-30fps-10kfr-manifest.json b/src/third_party/web_platform_tests/media-source/mp4/test-v-128k-320x240-30fps-10kfr-manifest.json
new file mode 100644
index 0000000..3e02844
--- /dev/null
+++ b/src/third_party/web_platform_tests/media-source/mp4/test-v-128k-320x240-30fps-10kfr-manifest.json
@@ -0,0 +1,4 @@
+{
+    "url": "mp4/test-v-128k-320x240-30fps-10kfr.mp4",
+    "type": "video/mp4;codecs=\"avc1.4D4001\""
+}
\ No newline at end of file
diff --git a/src/third_party/web_platform_tests/media-source/mp4/test-v-128k-320x240-30fps-10kfr.mp4 b/src/third_party/web_platform_tests/media-source/mp4/test-v-128k-320x240-30fps-10kfr.mp4
new file mode 100644
index 0000000..68d02cd
--- /dev/null
+++ b/src/third_party/web_platform_tests/media-source/mp4/test-v-128k-320x240-30fps-10kfr.mp4
Binary files differ
diff --git a/src/third_party/web_platform_tests/media-source/mp4/test-v-128k-640x480-30fps-10kfr-manifest.json b/src/third_party/web_platform_tests/media-source/mp4/test-v-128k-640x480-30fps-10kfr-manifest.json
new file mode 100644
index 0000000..10c4f4b
--- /dev/null
+++ b/src/third_party/web_platform_tests/media-source/mp4/test-v-128k-640x480-30fps-10kfr-manifest.json
@@ -0,0 +1,4 @@
+{
+    "url": "mp4/test-v-128k-640x480-30fps-10kfr.mp4",
+    "type": "video/mp4;codecs=\"avc1.4D4001\""
+}
\ No newline at end of file
diff --git a/src/third_party/web_platform_tests/media-source/mp4/test-v-128k-640x480-30fps-10kfr.mp4 b/src/third_party/web_platform_tests/media-source/mp4/test-v-128k-640x480-30fps-10kfr.mp4
new file mode 100644
index 0000000..c4f47f0
--- /dev/null
+++ b/src/third_party/web_platform_tests/media-source/mp4/test-v-128k-640x480-30fps-10kfr.mp4
Binary files differ
diff --git a/src/third_party/web_platform_tests/media-source/mp4/test-v-256k-320x240-30fps-10kfr-manifest.json b/src/third_party/web_platform_tests/media-source/mp4/test-v-256k-320x240-30fps-10kfr-manifest.json
new file mode 100644
index 0000000..42d3e1e
--- /dev/null
+++ b/src/third_party/web_platform_tests/media-source/mp4/test-v-256k-320x240-30fps-10kfr-manifest.json
@@ -0,0 +1,4 @@
+{
+    "url": "mp4/test-v-256k-320x240-30fps-10kfr.mp4",
+    "type": "video/mp4;codecs=\"avc1.4D4001\""
+}
\ No newline at end of file
diff --git a/src/third_party/web_platform_tests/media-source/mp4/test-v-256k-320x240-30fps-10kfr.mp4 b/src/third_party/web_platform_tests/media-source/mp4/test-v-256k-320x240-30fps-10kfr.mp4
new file mode 100644
index 0000000..6dc4972
--- /dev/null
+++ b/src/third_party/web_platform_tests/media-source/mp4/test-v-256k-320x240-30fps-10kfr.mp4
Binary files differ
diff --git a/src/third_party/web_platform_tests/media-source/mp4/test.mp4 b/src/third_party/web_platform_tests/media-source/mp4/test.mp4
new file mode 100644
index 0000000..eca97aa
--- /dev/null
+++ b/src/third_party/web_platform_tests/media-source/mp4/test.mp4
Binary files differ
diff --git a/src/third_party/web_platform_tests/media-source/webm/test-a-128k-44100Hz-1ch-manifest.json b/src/third_party/web_platform_tests/media-source/webm/test-a-128k-44100Hz-1ch-manifest.json
new file mode 100644
index 0000000..524da81
--- /dev/null
+++ b/src/third_party/web_platform_tests/media-source/webm/test-a-128k-44100Hz-1ch-manifest.json
@@ -0,0 +1,4 @@
+{
+    "url": "webm/test-a-128k-44100Hz-1ch.webm",
+    "type": "audio/webm;codecs=\"vorbis\""
+}
\ No newline at end of file
diff --git a/src/third_party/web_platform_tests/media-source/webm/test-a-128k-44100Hz-1ch.webm b/src/third_party/web_platform_tests/media-source/webm/test-a-128k-44100Hz-1ch.webm
new file mode 100644
index 0000000..c5b064d
--- /dev/null
+++ b/src/third_party/web_platform_tests/media-source/webm/test-a-128k-44100Hz-1ch.webm
Binary files differ
diff --git a/src/third_party/web_platform_tests/media-source/webm/test-a-192k-44100Hz-1ch-manifest.json b/src/third_party/web_platform_tests/media-source/webm/test-a-192k-44100Hz-1ch-manifest.json
new file mode 100644
index 0000000..7f2fa1e
--- /dev/null
+++ b/src/third_party/web_platform_tests/media-source/webm/test-a-192k-44100Hz-1ch-manifest.json
@@ -0,0 +1,4 @@
+{
+    "url": "webm/test-a-192k-44100Hz-1ch.webm",
+    "type": "audio/webm;codecs=\"vorbis\""
+}
\ No newline at end of file
diff --git a/src/third_party/web_platform_tests/media-source/webm/test-a-192k-44100Hz-1ch.webm b/src/third_party/web_platform_tests/media-source/webm/test-a-192k-44100Hz-1ch.webm
new file mode 100644
index 0000000..53814d3
--- /dev/null
+++ b/src/third_party/web_platform_tests/media-source/webm/test-a-192k-44100Hz-1ch.webm
Binary files differ
diff --git a/src/third_party/web_platform_tests/media-source/webm/test-av-384k-44100Hz-1ch-320x240-30fps-10kfr-manifest.json b/src/third_party/web_platform_tests/media-source/webm/test-av-384k-44100Hz-1ch-320x240-30fps-10kfr-manifest.json
new file mode 100644
index 0000000..af9f07a
--- /dev/null
+++ b/src/third_party/web_platform_tests/media-source/webm/test-av-384k-44100Hz-1ch-320x240-30fps-10kfr-manifest.json
@@ -0,0 +1,4 @@
+{
+    "url": "webm/test-av-384k-44100Hz-1ch-320x240-30fps-10kfr.webm",
+    "type": "video/webm;codecs=\"vp8,vorbis\""
+}
\ No newline at end of file
diff --git a/src/third_party/web_platform_tests/media-source/webm/test-av-384k-44100Hz-1ch-320x240-30fps-10kfr.webm b/src/third_party/web_platform_tests/media-source/webm/test-av-384k-44100Hz-1ch-320x240-30fps-10kfr.webm
new file mode 100644
index 0000000..8b705db
--- /dev/null
+++ b/src/third_party/web_platform_tests/media-source/webm/test-av-384k-44100Hz-1ch-320x240-30fps-10kfr.webm
Binary files differ
diff --git a/src/third_party/web_platform_tests/media-source/webm/test-av-384k-44100Hz-1ch-640x480-30fps-10kfr-manifest.json b/src/third_party/web_platform_tests/media-source/webm/test-av-384k-44100Hz-1ch-640x480-30fps-10kfr-manifest.json
new file mode 100644
index 0000000..f7ec86b
--- /dev/null
+++ b/src/third_party/web_platform_tests/media-source/webm/test-av-384k-44100Hz-1ch-640x480-30fps-10kfr-manifest.json
@@ -0,0 +1,4 @@
+{
+    "url": "webm/test-av-384k-44100Hz-1ch-640x480-30fps-10kfr.webm",
+    "type": "video/webm;codecs=\"vp8,vorbis\""
+}
\ No newline at end of file
diff --git a/src/third_party/web_platform_tests/media-source/webm/test-av-384k-44100Hz-1ch-640x480-30fps-10kfr.webm b/src/third_party/web_platform_tests/media-source/webm/test-av-384k-44100Hz-1ch-640x480-30fps-10kfr.webm
new file mode 100644
index 0000000..c5e010e
--- /dev/null
+++ b/src/third_party/web_platform_tests/media-source/webm/test-av-384k-44100Hz-1ch-640x480-30fps-10kfr.webm
Binary files differ
diff --git a/src/third_party/web_platform_tests/media-source/webm/test-av-448k-44100Hz-1ch-640x480-30fps-10kfr-manifest.json b/src/third_party/web_platform_tests/media-source/webm/test-av-448k-44100Hz-1ch-640x480-30fps-10kfr-manifest.json
new file mode 100644
index 0000000..96a59db
--- /dev/null
+++ b/src/third_party/web_platform_tests/media-source/webm/test-av-448k-44100Hz-1ch-640x480-30fps-10kfr-manifest.json
@@ -0,0 +1,4 @@
+{
+    "url": "webm/test-av-448k-44100Hz-1ch-640x480-30fps-10kfr.webm",
+    "type": "video/webm;codecs=\"vp8,vorbis\""
+}
\ No newline at end of file
diff --git a/src/third_party/web_platform_tests/media-source/webm/test-av-448k-44100Hz-1ch-640x480-30fps-10kfr.webm b/src/third_party/web_platform_tests/media-source/webm/test-av-448k-44100Hz-1ch-640x480-30fps-10kfr.webm
new file mode 100644
index 0000000..62c4328
--- /dev/null
+++ b/src/third_party/web_platform_tests/media-source/webm/test-av-448k-44100Hz-1ch-640x480-30fps-10kfr.webm
Binary files differ
diff --git a/src/third_party/web_platform_tests/media-source/webm/test-av-640k-44100Hz-1ch-640x480-30fps-10kfr-manifest.json b/src/third_party/web_platform_tests/media-source/webm/test-av-640k-44100Hz-1ch-640x480-30fps-10kfr-manifest.json
new file mode 100644
index 0000000..86723b3
--- /dev/null
+++ b/src/third_party/web_platform_tests/media-source/webm/test-av-640k-44100Hz-1ch-640x480-30fps-10kfr-manifest.json
@@ -0,0 +1,4 @@
+{
+    "url": "webm/test-av-640k-44100Hz-1ch-640x480-30fps-10kfr.webm",
+    "type": "video/webm;codecs=\"vp8,vorbis\""
+}
\ No newline at end of file
diff --git a/src/third_party/web_platform_tests/media-source/webm/test-av-640k-44100Hz-1ch-640x480-30fps-10kfr.webm b/src/third_party/web_platform_tests/media-source/webm/test-av-640k-44100Hz-1ch-640x480-30fps-10kfr.webm
new file mode 100644
index 0000000..93c31b6
--- /dev/null
+++ b/src/third_party/web_platform_tests/media-source/webm/test-av-640k-44100Hz-1ch-640x480-30fps-10kfr.webm
Binary files differ
diff --git a/src/third_party/web_platform_tests/media-source/webm/test-v-128k-320x240-24fps-8kfr-manifest.json b/src/third_party/web_platform_tests/media-source/webm/test-v-128k-320x240-24fps-8kfr-manifest.json
new file mode 100644
index 0000000..00e103a
--- /dev/null
+++ b/src/third_party/web_platform_tests/media-source/webm/test-v-128k-320x240-24fps-8kfr-manifest.json
@@ -0,0 +1,4 @@
+{
+    "url": "webm/test-v-128k-320x240-24fps-8kfr.webm",
+    "type": "video/webm;codecs=\"vp8\""
+}
\ No newline at end of file
diff --git a/src/third_party/web_platform_tests/media-source/webm/test-v-128k-320x240-24fps-8kfr.webm b/src/third_party/web_platform_tests/media-source/webm/test-v-128k-320x240-24fps-8kfr.webm
new file mode 100644
index 0000000..189c472
--- /dev/null
+++ b/src/third_party/web_platform_tests/media-source/webm/test-v-128k-320x240-24fps-8kfr.webm
Binary files differ
diff --git a/src/third_party/web_platform_tests/media-source/webm/test-v-128k-320x240-30fps-10kfr-manifest.json b/src/third_party/web_platform_tests/media-source/webm/test-v-128k-320x240-30fps-10kfr-manifest.json
new file mode 100644
index 0000000..fdeeb40
--- /dev/null
+++ b/src/third_party/web_platform_tests/media-source/webm/test-v-128k-320x240-30fps-10kfr-manifest.json
@@ -0,0 +1,4 @@
+{
+    "url": "webm/test-v-128k-320x240-30fps-10kfr.webm",
+    "type": "video/webm;codecs=\"vp8\""
+}
\ No newline at end of file
diff --git a/src/third_party/web_platform_tests/media-source/webm/test-v-128k-320x240-30fps-10kfr.webm b/src/third_party/web_platform_tests/media-source/webm/test-v-128k-320x240-30fps-10kfr.webm
new file mode 100644
index 0000000..18b2baf
--- /dev/null
+++ b/src/third_party/web_platform_tests/media-source/webm/test-v-128k-320x240-30fps-10kfr.webm
Binary files differ
diff --git a/src/third_party/web_platform_tests/media-source/webm/test-v-128k-640x480-30fps-10kfr-manifest.json b/src/third_party/web_platform_tests/media-source/webm/test-v-128k-640x480-30fps-10kfr-manifest.json
new file mode 100644
index 0000000..4e30460
--- /dev/null
+++ b/src/third_party/web_platform_tests/media-source/webm/test-v-128k-640x480-30fps-10kfr-manifest.json
@@ -0,0 +1,4 @@
+{
+    "url": "webm/test-v-128k-640x480-30fps-10kfr.webm",
+    "type": "video/webm;codecs=\"vp8\""
+}
\ No newline at end of file
diff --git a/src/third_party/web_platform_tests/media-source/webm/test-v-128k-640x480-30fps-10kfr.webm b/src/third_party/web_platform_tests/media-source/webm/test-v-128k-640x480-30fps-10kfr.webm
new file mode 100644
index 0000000..75e38b0
--- /dev/null
+++ b/src/third_party/web_platform_tests/media-source/webm/test-v-128k-640x480-30fps-10kfr.webm
Binary files differ
diff --git a/src/third_party/web_platform_tests/media-source/webm/test-v-256k-320x240-30fps-10kfr-manifest.json b/src/third_party/web_platform_tests/media-source/webm/test-v-256k-320x240-30fps-10kfr-manifest.json
new file mode 100644
index 0000000..3470674
--- /dev/null
+++ b/src/third_party/web_platform_tests/media-source/webm/test-v-256k-320x240-30fps-10kfr-manifest.json
@@ -0,0 +1,4 @@
+{
+    "url": "webm/test-v-256k-320x240-30fps-10kfr.webm",
+    "type": "video/webm;codecs=\"vp8\""
+}
\ No newline at end of file
diff --git a/src/third_party/web_platform_tests/media-source/webm/test-v-256k-320x240-30fps-10kfr.webm b/src/third_party/web_platform_tests/media-source/webm/test-v-256k-320x240-30fps-10kfr.webm
new file mode 100644
index 0000000..0250d26
--- /dev/null
+++ b/src/third_party/web_platform_tests/media-source/webm/test-v-256k-320x240-30fps-10kfr.webm
Binary files differ
diff --git a/src/third_party/web_platform_tests/media-source/webm/test-vp8-vorbis-webvtt.webm b/src/third_party/web_platform_tests/media-source/webm/test-vp8-vorbis-webvtt.webm
new file mode 100644
index 0000000..c626f86
--- /dev/null
+++ b/src/third_party/web_platform_tests/media-source/webm/test-vp8-vorbis-webvtt.webm
Binary files differ
diff --git a/src/third_party/web_platform_tests/media-source/webm/test.webm b/src/third_party/web_platform_tests/media-source/webm/test.webm
new file mode 100644
index 0000000..6c2138d
--- /dev/null
+++ b/src/third_party/web_platform_tests/media-source/webm/test.webm
Binary files differ