Fix webcodecs, add menu option to select encoder

This commit is contained in:
David Halls
2022-09-15 20:58:18 +01:00
parent 2786feb595
commit bbbdfe48ac
5 changed files with 76 additions and 45 deletions

View File

@@ -108,6 +108,19 @@
</div>
</div>
</div>
<div class="pt-4">
<label class="form-label">Encoder Preference</label>
<div>
<div class="form-check form-check-inline">
<input id="prefer-mediarecorder" name="preferred-encoder" class="form-check-input" type="radio" value="mediarecorder">
<label for="prefer-mediarecorder" class="form-check-label">MediaRecorder</label>
</div>
<div class="form-check form-check-inline">
<input id="prefer-webcodecs" name="preferred-encoder" class="form-check-input" type="radio" value="webcodecs">
<label for="prefer-webcodecs" class="form-check-label">WebCodecs</label>
</div>
</div>
</div>
<div class="pt-4">
<label for="ffmpeg-lib-url" class="form-label">FFmpeg library URL</label>
<input id="ffmpeg-lib-url" class="form-control" type="text">

View File

@@ -105,43 +105,57 @@ const camera_swap_el = document.getElementById('camera-swap');
const ingestion_url_el = document.getElementById('ingestion-url');
const protocol_hls_el = document.getElementById('protocol-hls');
const protocol_dash_el = document.getElementById('protocol-dash');
const request_post = document.getElementById('request-post');
const request_put = document.getElementById('request-put');
const request_cors = document.getElementById('request-cors');
const request_no_cors = document.getElementById('request-no-cors');
const request_same_origin = document.getElementById('request-same-origin');
const request_post_el = document.getElementById('request-post');
const request_put_el = document.getElementById('request-put');
const request_cors_el = document.getElementById('request-cors');
const request_no_cors_el = document.getElementById('request-no-cors');
const request_same_origin_el = document.getElementById('request-same-origin');
const resolution_el = document.getElementById('resolution');
const prefer_mediarecorder_el = document.getElementById('prefer-mediarecorder');
const prefer_webcodecs_el = document.getElementById('prefer-webcodecs');
if (localStorage.getItem('streamana-request-method') === 'PUT') {
request_put.checked = true;
request_no_cors.disabled = true;
request_put_el.checked = true;
request_no_cors_el.disabled = true;
} else {
request_post.checked = true;
request_post_el.checked = true;
}
switch (localStorage.getItem('streamana-request-mode')) {
case 'cors':
request_cors.checked = true;
request_cors_el.checked = true;
break;
case 'same-origin':
request_same_origin.checked = true;
request_same_origin_el.checked = true;
break;
default:
request_no_cors.checked = true;
request_put.disabled = true;
request_no_cors_el.checked = true;
request_put_el.disabled = true;
break;
}
function request_save() {
localStorage.setItem(`streamana-${this.name}`, this.value);
request_put.disabled = request_no_cors.checked;
request_no_cors.disabled = request_put.checked;
request_put_el.disabled = request_no_cors_el.checked;
request_no_cors_el.disabled = request_put_el.checked;
}
request_put_el.addEventListener('change', request_save);
request_post_el.addEventListener('change', request_save);
request_cors_el.addEventListener('change', request_save);
request_no_cors_el.addEventListener('change', request_save);
request_same_origin_el.addEventListener('change', request_save);
function encoder_preference_save() {
localStorage.setItem('streamana-encoder-preference', this.value);
}
prefer_mediarecorder_el.addEventListener('change', encoder_preference_save);
prefer_webcodecs_el.addEventListener('change', encoder_preference_save);
if (localStorage.getItem('streamana-encoder-preference') === 'webcodecs') {
prefer_webcodecs_el.checked = true;
} else {
prefer_mediarecorder_el.checked = true;
}
request_put.addEventListener('change', request_save);
request_post.addEventListener('change', request_save);
request_cors.addEventListener('change', request_save);
request_no_cors.addEventListener('change', request_save);
request_same_origin.addEventListener('change', request_save);
let streamer_config;
let video_config;
@@ -243,8 +257,6 @@ async function set_ingestion() {
resolution_el.appendChild(option);
video_configs.set(option.innerText, config);
}
return streamer_config;
} finally {
busy_el.classList.add('d-none');
}
@@ -283,10 +295,10 @@ async function start() {
const ffmpeg_lib_url = ffmpeg_lib_url_el.value.trim() ||
ffmpeg_lib_url_el.placeholder.trim();
const method = request_put.checked ? request_put.value : request_post.value;
const mode = request_cors.checked ? request_cors.value :
request_same_origin.checked ? request_same_origin.value :
request_no_cors.value;
const method = request_put_el.checked ? request_put_el.value : request_post_el.value;
const mode = request_cors_el.checked ? request_cors_el.value :
request_same_origin_el.checked ? request_same_origin_el.value :
request_no_cors_el.value;
go_live_el.disabled = true;
ingestion_url_el.disabled = true;
@@ -297,11 +309,13 @@ async function start() {
resolution_el.disabled = true;
protocol_hls_el.disabled = true;
protocol_dash_el.disabled = true;
request_post.disabled = true;
request_put.disabled = true;
request_cors.disabled = true;
request_no_cors.disabled = true;
request_same_origin.disabled = true;
request_post_el.disabled = true;
request_put_el.disabled = true;
request_cors_el.disabled = true;
request_no_cors_el.disabled = true;
request_same_origin_el.disabled = true;
prefer_mediarecorder_el.disabled = true;
prefer_webcodecs_el.disabled = true;
waiting_el.classList.remove('d-none');
mic_el.removeEventListener('click', mic_save);
camera_el.removeEventListener('click', camera_save);
@@ -413,11 +427,13 @@ async function start() {
resolution_el.disabled = false;
protocol_hls_el.disabled = ffmpeg_lib_url_el.value.trim();
protocol_dash_el.disabled = ffmpeg_lib_url_el.value.trim();;
request_post.disabled = false;
request_put.disabled = request_no_cors.checked;
request_cors.disabled = false;
request_no_cors.disabled = request_put.checked;
request_same_origin.disabled = false;
request_post_el.disabled = false;
request_put_el.disabled = request_no_cors_el.checked;
request_cors_el.disabled = false;
request_no_cors_el.disabled = request_put_el.checked;
request_same_origin_el.disabled = false;
prefer_mediarecorder_el.disabled = false;
prefer_webcodecs_el.disabled = false;
waiting_el.classList.add('d-none');
canvas_el.classList.add('d-none');
}
@@ -726,7 +742,7 @@ async function start() {
// Note: WebAudio destination stream output is bugged on Safari:
// https://bugs.webkit.org/show_bug.cgi?id=173863
// https://bugs.webkit.org/show_bug.cgi?id=198284
//const silence = audio_dest.context.createBufferSource();
//silence = audio_dest.context.createBufferSource();
silence = audio_dest.context.createConstantSource();
silence.start();
audio_source = silence;
@@ -738,7 +754,8 @@ async function start() {
ingestion_url,
streamer_config,
lock_portrait,
{ method, mode });
{ method, mode },
prefer_webcodecs_el.checked);
streamer.addEventListener('run', () => console.log('Streamer running'));
streamer.addEventListener('exit', ev => {
const msg = `Streamer exited with status ${ev.detail.code}`;

View File

@@ -60,7 +60,7 @@ export function get_default_config_from_url(ffmpeg_lib_url) {
}
export class Streamer extends EventTarget {
constructor(stream, audio_context, base_url, config, rotate, request_options) {
constructor(stream, audio_context, base_url, config, rotate, request_options, prefer_webcodecs) {
super();
this.stream = stream;
this.audio_context = audio_context;
@@ -75,6 +75,7 @@ export class Streamer extends EventTarget {
this.update_event = new CustomEvent('update');
this.sending = false;
this.started = false;
this.prefer_webcodecs = prefer_webcodecs;
}
async start() {
@@ -111,7 +112,7 @@ export class Streamer extends EventTarget {
}
};
if (mrcfg.webm) {
if (mrcfg.webm && !this.prefer_webcodecs) {
try {
// try MediaRecorder WebM - this should work on Chrome Linux and Windows
const codecs = `${mrcfg.video.codec},${mrcfg.audio.codec}`;
@@ -251,7 +252,7 @@ export class Streamer extends EventTarget {
break;
default:
if (audio_codes.startsWith('mp4a')) {
if (this.config.media_recorder.audio.codec.toLowerCase().startsWith('mp4a')) {
audio_codec = 'aac';
} else {
audio_codec = null;
@@ -400,7 +401,7 @@ export class Streamer extends EventTarget {
};
let video_codec;
switch (this.config.webcodecs.video.codec) {
switch (this.config.webcodecs.webm_muxer.video.codec) {
case 'V_AV1':
video_codec = 'libaom-av1';
break;
@@ -423,7 +424,7 @@ export class Streamer extends EventTarget {
}
let audio_codec;
switch (this.config.webcodecs.audio.codec) {
switch (this.config.webcodecs.webm_muxer.audio.codec) {
case 'A_FLAC':
audio_codec = 'flac';
break;
@@ -445,7 +446,7 @@ export class Streamer extends EventTarget {
break;
default:
if (audio_codes.startsWith('A_AAC')) {
if (this.config.webcodecs.webm_muxer.audio.codec.startsWith('A_AAC')) {
audio_codec = 'aac';
} else {
audio_codec = null;