forked from web-platform-tests/wpt
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[MSE][webcodecs] Plumb AddSourceBufferUsingConfig to ChunkDemuxer AddId
This change: 1) Exposes as static synchronous helpers the WebCodecs MakeMediaConfig methods' internals so that MediaSource can use them to obtain media::{Audio,Video}DecoderConfigs from WebCodecs {Audio,Video}DecoderConfigs. 2) Implements MediaSource::AddSourceBufferUsingConfig for encoded configs (not decodedMediaType), plumbing the media decoder config through the usual steps in MSE addSourceBuffer, and through new methods in WebMediaSource and WebMediaSourceImpl to let ChunkDemuxer::AddId know it will be expected to handle WebCodecs encoded chunk appends for the associated SourceBuffer. 3) Adds a tentative folder for MSE-for-WebCodecs web_tests and adds a test for the current behavior of addSourceBuffer(webcodecs decoder config) that this CL adds. Later changes will continue plumbing of the configs in ChunkDemuxer and SourceBufferState, and also add implementations and ChunkDemuxer/etc support for appendEncoded{Audio,Video}Chunks. The h264 parser and avcc conditionally created in #1, above, could then be used by SourceBuffer processing of appended EncodedVideoChunks, too. BUG=1144908 Change-Id: I90c1d90c3a28d5cc1e33b1e50e32f4cfea639784 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2548844 Commit-Queue: Matthew Wolenetz <wolenetz@chromium.org> Reviewed-by: Daniel Cheng <dcheng@chromium.org> Reviewed-by: Chrome Cunningham <chcunningham@chromium.org> Reviewed-by: Dan Sanders <sandersd@chromium.org> Cr-Commit-Position: refs/heads/master@{#835058}
- Loading branch information
1 parent
e0707f9
commit 009fb03
Showing
1 changed file
with
207 additions
and
0 deletions.
There are no files selected for viewing
207 changes: 207 additions & 0 deletions
207
media-source/mse-for-webcodecs/tentative/mediasource-webcodecs-addsourcebuffer.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,207 @@ | ||
<!DOCTYPE html> | ||
<html> | ||
<title>Test MediaSource addSourceBuffer overloads for WebCodecs Audio/VideoDecoderConfigs</title> | ||
<script src="/resources/testharness.js"></script> | ||
<script src="/resources/testharnessreport.js"></script> | ||
<script> | ||
|
||
setup(() => { | ||
assert_implements( | ||
SourceBuffer.prototype.hasOwnProperty('appendEncodedChunks'), | ||
'SourceBuffer prototype hasOwnProperty "appendEncodedChunks", used ' + | ||
'here to feature detect MSE-for-WebCodecs implementation.'); | ||
}); | ||
|
||
testInvalidArguments(); | ||
testValidArguments(); | ||
|
||
function getValidAudioConfig() { | ||
// TODO(crbug.com/1144908): Consider confirming with WebCodecs' | ||
// isConfigSupported() once that API is available. | ||
return { | ||
codec: 'opus', | ||
sampleRate: 48000, | ||
numberOfChannels: 2 | ||
}; | ||
} | ||
|
||
function getValidVideoConfig() { | ||
// TODO(crbug.com/1144908): Consider confirming with WebCodecs' | ||
// isConfigSupported() once that API is available. | ||
return { codec: 'vp09.00.10.08' }; | ||
} | ||
|
||
function testInvalidArguments() { | ||
const INVALID_CASES = [ | ||
{ arg: null, | ||
name: 'null' }, | ||
{ arg: undefined, | ||
name: 'undefined' }, | ||
{ arg: { }, | ||
name: '{ empty dictionary }' }, | ||
{ | ||
arg: { | ||
audioConfig: getValidAudioConfig(), | ||
videoConfig: getValidVideoConfig() | ||
}, | ||
name: '{ valid audioConfig and videoConfig }', | ||
}, | ||
{ | ||
arg: { | ||
audioConfig: { | ||
codec: 'bogus', | ||
sampleRate: 48000, | ||
numberOfChannels: 2 | ||
} | ||
}, | ||
name: 'bad audio config codec', | ||
}, | ||
{ arg: { videoConfig: { codec: 'bogus' } }, | ||
name: 'bad video config codec' }, | ||
{ arg: { audioConfig: { sampleRate: 48000, numberOfChannels: 2 } }, | ||
name: 'audio config missing required member "codec"' }, | ||
{ arg: { videoConfig: { } }, | ||
name: 'video config missing required member "codec"' }, | ||
]; | ||
|
||
[ 'closed', 'open', 'ended' ].forEach(readyStateScenario => { | ||
INVALID_CASES.forEach(invalidCase => { | ||
runAddSourceBufferTest(invalidCase['arg'] /* argument */, | ||
false /* isValidArgument */, | ||
invalidCase['name'] /* argumentDescription */, | ||
readyStateScenario); | ||
}); | ||
}); | ||
} | ||
|
||
function testValidArguments() { | ||
const VALID_CASES = [ | ||
{ | ||
arg: { | ||
audioConfig: getValidAudioConfig() | ||
}, | ||
name: 'valid audioConfig' | ||
}, | ||
{ | ||
arg: { | ||
videoConfig: getValidVideoConfig() | ||
}, | ||
name: 'valid videoConfig' | ||
}, | ||
]; | ||
|
||
[ 'closed', 'open', 'ended' ].forEach(readyStateScenario => { | ||
VALID_CASES.forEach(validCase => { | ||
runAddSourceBufferTest( | ||
validCase['arg'] /* argument */, | ||
true /* isValidArgument */, | ||
validCase['name'] /* argumentDescription */, | ||
readyStateScenario); | ||
}); | ||
}); | ||
} | ||
|
||
async function getClosedMediaSource(test) { | ||
let mediaSource = new MediaSource(); | ||
assert_equals(mediaSource.readyState, 'closed'); | ||
return mediaSource; | ||
} | ||
|
||
async function getOpenMediaSource(test) { | ||
return new Promise(async resolve => { | ||
const v = document.createElement('video'); | ||
const mediaSource = new MediaSource(); | ||
const url = URL.createObjectURL(mediaSource); | ||
mediaSource.addEventListener('sourceopen', test.step_func(() => { | ||
URL.revokeObjectURL(url); | ||
assert_equals(mediaSource.readyState, 'open', 'MediaSource is open'); | ||
resolve(mediaSource); | ||
}), { once: true }); | ||
v.src = url; | ||
}); | ||
} | ||
|
||
async function getEndedMediaSource(test) { | ||
let mediaSource = await getOpenMediaSource(test); | ||
assert_equals(mediaSource.readyState, 'open', 'MediaSource is open'); | ||
mediaSource.endOfStream(); | ||
assert_equals(mediaSource.readyState, 'ended', 'MediaSource is ended'); | ||
return mediaSource; | ||
} | ||
|
||
function runAddSourceBufferTest(argument, isValidArgument, argumentDescription, readyStateScenario) { | ||
const testDescription = 'addSourceBuffer call with ' + | ||
(isValidArgument ? 'valid' : 'invalid') + | ||
' argument ' + argumentDescription + ' while MediaSource readyState is ' + | ||
readyStateScenario; | ||
|
||
switch(readyStateScenario) { | ||
case 'closed': | ||
promise_test(async t => { | ||
let mediaSource = await getClosedMediaSource(t); | ||
assert_equals(mediaSource.readyState, 'closed'); | ||
let sourceBuffer; | ||
if (isValidArgument) { | ||
assert_throws_dom('InvalidStateError', | ||
() => { sourceBuffer = mediaSource.addSourceBuffer(argument); }, | ||
'addSourceBuffer(valid config) throws InvalidStateError if MediaSource is "closed"'); | ||
assert_equals(sourceBuffer, undefined, | ||
'addSourceBuffer result for valid config while "closed" should be exception'); | ||
} else { | ||
assert_throws_js(TypeError, | ||
() => { sourceBuffer = mediaSource.addSourceBuffer(argument); }, | ||
'addSourceBuffer(invalid config) throws TypeError if MediaSource is "closed"'); | ||
assert_equals(sourceBuffer, undefined, | ||
'addSourceBuffer result for invalid config while "closed" should be exception'); | ||
} | ||
}, testDescription); | ||
break; | ||
case 'open': | ||
promise_test(async t => { | ||
let mediaSource = await getOpenMediaSource(t); | ||
assert_equals(mediaSource.readyState, 'open', 'MediaSource is open'); | ||
let sourceBuffer; | ||
if (isValidArgument) { | ||
// TODO(crbug.com/1144908): Update to expect success once the impl is | ||
// more complete. | ||
assert_throws_dom('QuotaExceededError', | ||
() => { sourceBuffer = mediaSource.addSourceBuffer(argument); }, | ||
'addSourceBuffer(valid config) throws QuotaExceededError'); | ||
assert_equals(sourceBuffer, undefined, | ||
'addSourceBuffer result for valid config while "open" should be exception'); | ||
} else { | ||
assert_throws_js(TypeError, | ||
() => { sourceBuffer = mediaSource.addSourceBuffer(argument); }, | ||
'addSourceBuffer(invalid config) throws TypeError if MediaSource is "open"'); | ||
assert_equals(sourceBuffer, undefined, | ||
'addSourceBufferResult for invalid config while "open" should be exception'); | ||
} | ||
}, testDescription); | ||
break; | ||
case 'ended': | ||
promise_test(async t => { | ||
let mediaSource = await getEndedMediaSource(t); | ||
let sourceBuffer; | ||
if (isValidArgument) { | ||
assert_throws_dom('InvalidStateError', | ||
() => { sourceBuffer = mediaSource.addSourceBuffer(argument); }, | ||
'addSourceBuffer(valid config) throws InvalidStateError if MediaSource is "ended"'); | ||
assert_equals(sourceBuffer, undefined, | ||
'addSourceBuffer result for valid config while "ended" should be exception'); | ||
} else { | ||
assert_throws_js(TypeError, | ||
() => { sourceBuffer = mediaSource.addSourceBuffer(argument); }, | ||
'addSourceBuffer(invalid config) throws TypeError if MediaSource is "ended"'); | ||
assert_equals(sourceBuffer, undefined, | ||
'addSourceBuffer result for invalid config while "ended" should be exception'); | ||
} | ||
}, testDescription); | ||
break; | ||
default: | ||
assert_unreached('Invalid readyStateScenario ' + readyStateScenario); | ||
break; | ||
} | ||
} | ||
|
||
</script> | ||
</html> |