Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement cross-thread MediaSource attachments #4314

Open
wants to merge 5 commits into
base: 25.lts.1+
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions cobalt/black_box_tests/black_box_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@
# 'h5vcc_watchdog_api_test',
'http_cache',
'javascript_profiler',
'mediasource_worker_play',
'navigator_test',
'performance_resource_timing_test',
'persistent_cookie',
Expand Down
71 changes: 71 additions & 0 deletions cobalt/black_box_tests/testdata/mediasource_worker_play.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
<!DOCTYPE html>
<!--
Copyright 2024 The Cobalt Authors.All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

Copyright 2020 The Chromium Authors
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
<html>
<head>
<title>Simple MediaSource-in-Worker playback test case</title>
<script src="black_box_js_test_utils.js"></script>
</head>
<body>
<script>
const timeoutId = window.setTimeout(notReached, 10000);

// Enable MSE-in-Workers H5VCC flags.
h5vcc.settings.set('MediaElement.EnableUsingMediaSourceBufferedRange', 1);
h5vcc.settings.set('MediaElement.EnableUsingMediaSourceAttachmentMethods', 1);
h5vcc.settings.set('MediaSource.EnableInWorkers', 1);

// Fail fast if MSE-in-Workers is not supported.
assertTrue(MediaSource.hasOwnProperty('canConstructInDedicatedWorker'),
"MediaSource hasOwnProperty 'canConstructInDedicatedWorker'");
assertTrue(MediaSource.canConstructInDedicatedWorker,
'MediaSource.canConstructInDedicatedWorker');

const video = document.createElement('video');
document.body.appendChild(video);
video.addEventListener('error', () => notReached('video error'));
video.addEventListener('ended', () => {
window.clearTimeout(timeoutId);
onEndTest();
});

const worker = new Worker('mediasource_worker_play.js');
worker.addEventListener('error', () => notReached('worker error'));
worker.addEventListener('message', (event) => {
const subject = event.data.subject;
assertTrue(subject !== undefined, 'message must have a subject field');
switch(subject) {
case 'error':
notReached(event.data.info);
break;
case 'handle':
const handle = event.data.info;
video.src = handle;
video.play();
break;
default:
notReached();
}
});

setupFinished();
</script>
</body>
</html>
65 changes: 65 additions & 0 deletions cobalt/black_box_tests/testdata/mediasource_worker_play.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// Copyright 2024 The Cobalt Authors.All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

importScripts('mediasource_worker_util.js');

onmessage = function(event) {
postMessage({subject: 'error', info: 'No message expected by Worker'});
};

const util = new MediaSourceWorkerUtil();
const handle = URL.createObjectURL(util.mediaSource);

util.mediaSource.addEventListener('sourceopen', () => {
URL.revokeObjectURL(handle);

const sourceBuffer =
util.mediaSource.addSourceBuffer(util.mediaMetadata.type);
sourceBuffer.addEventListener('error', (err) => {
postMessage({subject: 'error', info: err});
});
function updateEndOnce() {
sourceBuffer.removeEventListener('updateend', updateEndOnce);
sourceBuffer.addEventListener('updateend', () => {
util.mediaSource.duration = 0.5;
util.mediaSource.endOfStream();
// Sanity check the duration.
// Unnecessary for this buffering, except helps with test coverage.
const duration = util.mediaSource.duration;
if (isNaN(duration) || duration <= 0.0 || duration >= 1.0) {
postMessage({
subject: 'error',
info: 'mediaSource.duration ' + duration +
' is not within expected range (0,1)'
});
}
});

// Reset the parser. Unnecessary for this buffering, except helps with test
// coverage.
sourceBuffer.abort();
// Shorten the buffered media and test playback duration to avoid timeouts.
sourceBuffer.remove(0.5, Infinity);
}
sourceBuffer.addEventListener('updateend', updateEndOnce);
util.mediaLoadPromise.then(mediaData => {
sourceBuffer.appendBuffer(mediaData);
}, err => {postMessage({subject: 'error', info: err})});
});

postMessage({subject: 'handle', info: handle});
79 changes: 79 additions & 0 deletions cobalt/black_box_tests/testdata/mediasource_worker_util.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
// Copyright 2024 The Cobalt Authors.All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// This script is intended to be imported into a worker's script, and provides
// common preparation for multiple test cases. Errors encountered are either
// postMessaged with subject of 'error', or in the case of failed
// mediaLoadPromise, result in promise rejection.

if (!this.MediaSource)
postMessage({subject: 'error', info: 'MediaSource API missing from Worker'});

const MEDIA_LIST = [
{
url: 'video/test.mp4',
type: 'video/mp4; codecs="mp4a.40.2,avc1.4d400d"',
},
{
url: 'video/test.webm',
type: 'video/webm; codecs="vp8, vorbis"',
},
];

class MediaSourceWorkerUtil {
constructor() {
this.mediaSource = new MediaSource();

// Find supported test media, if any.
this.foundSupportedMedia = false;
for (let i = 0; i < MEDIA_LIST.length; ++i) {
this.mediaMetadata = MEDIA_LIST[i];
if (MediaSource.isTypeSupported(this.mediaMetadata.type)) {
this.foundSupportedMedia = true;
break;
}
}

// Begin asynchronous fetch of the test media.
if (this.foundSupportedMedia) {
this.mediaLoadPromise =
MediaSourceWorkerUtil.loadBinaryAsync(this.mediaMetadata.url);
} else {
postMessage({subject: 'error', info: 'No supported test media'});
}
}

static loadBinaryAsync(url) {
return new Promise((resolve, reject) => {
const request = new XMLHttpRequest();
request.open('GET', url, true);
request.responseType = 'arraybuffer';
request.onerror = event => {
reject(event);
};
request.onload = () => {
if (request.status != 200) {
reject('Unexpected loadData_ status code : ' + request.status);
}
let response = new Uint8Array(request.response);
resolve(response);
};
request.send();
});
}
}
Binary file added cobalt/black_box_tests/testdata/video/test.mp4
Binary file not shown.
Binary file added cobalt/black_box_tests/testdata/video/test.webm
Binary file not shown.
27 changes: 27 additions & 0 deletions cobalt/black_box_tests/tests/mediasource_worker_play.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Copyright 2024 The Cobalt Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Tests MSE-in-Workers functionality."""

from cobalt.black_box_tests import black_box_tests
from cobalt.black_box_tests.threaded_web_server import ThreadedWebServer


class MediaeourceWorkerPlayTest(black_box_tests.BlackBoxTestCase):

def test_mediasource_worker_play(self):
with ThreadedWebServer(binding_address=self.GetBindingAddress()) as server:
url = server.GetURL(file_name='testdata/mediasource_worker_play.html')
with self.CreateCobaltRunner(url=url) as runner:
runner.WaitForJSTestsSetup()
self.assertTrue(runner.JSTestsSucceeded())
1 change: 1 addition & 0 deletions cobalt/dom/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,7 @@ static_library("dom") {
"media_source.cc",
"media_source.h",
"media_source_attachment.h",
"media_source_attachment_supplement.cc",
"media_source_attachment_supplement.h",
"memory_info.cc",
"memory_info.h",
Expand Down
Loading
Loading