Remove a layer of Worker

This commit is contained in:
David Halls
2021-07-11 17:43:24 +01:00
parent 516c7de1ab
commit 48979b8638
4 changed files with 122 additions and 121 deletions

View File

@@ -1,99 +0,0 @@
let ffmpeg_worker;
let ffmpeg_args;
let base_url;
function onerror(e) {
if (ffmpeg_worker) {
console.error(e);
self.postMessage({
type: 'error',
detail: e.message
});
}
}
function ffmpeg_onmessage(e) {
const msg = e.data;
switch (msg.type) {
case 'ready':
this.postMessage({
type: 'run',
arguments: [
'-loglevel', 'debug',
...ffmpeg_args,
'-f', 'hls', // use hls encoder
'-hls_time', '2', // 2 second HLS chunks
'-hls_segment_type', 'mpegts', // MPEG2-TS muxer
'-hls_list_size', '2', // two chunks in the list at a time
'-hls_flags', 'split_by_time',
'/outbound/output.m3u8' // path to media playlist file in virtual FS,
// must be under /outbound
],
MEMFS: [
{ name: 'stream1' },
{ name: 'stream2' }
]
});
break;
case 'stdout':
console.log(msg.data);
break;
case 'stderr':
console.error(msg.data);
break;
case 'error':
case 'abort':
onerror(msg.data);
break;
case 'start-stream':
this.postMessage({
type: 'base-url',
data: base_url
});
self.postMessage(msg);
break;
case 'exit':
ffmpeg_worker = null;
self.postMessage({ type: msg.type, code: msg.data });
break;
}
}
onmessage = function (e) {
const msg = e.data;
switch (msg.type) {
case 'start':
({ ffmpeg_args, base_url } = msg);
ffmpeg_worker = new Worker(msg.ffmpeg_lib_url);
ffmpeg_worker.onerror = onerror;
ffmpeg_worker.onmessage = ffmpeg_onmessage;
break;
case 'end':
if (ffmpeg_worker) {
if (msg.force) {
ffmpeg_worker.terminate();
self.postMessage({
type: 'exit',
code: 'force-end'
});
} else {
ffmpeg_worker.postMessage({
type: 'stream-end'
});
}
ffmpeg_worker = null;
}
break;
case 'muxed-data':
if (ffmpeg_worker) {
ffmpeg_worker.postMessage({
type: 'stream-data',
name: msg.name,
data: msg.data
}, [msg.data]);
}
break;
}
};
self.postMessage({ type: 'ready' });

View File

@@ -1,4 +1,5 @@
import { UpdateLimiter } from './update-limiter.js';
import { WebMDestination } from './webm-destination.js';
const audioBitsPerSecond = 128 * 1000;
const videoBitsPerSecond = 2500 * 1000;
@@ -74,13 +75,9 @@ export class HLS extends EventTarget {
// push encoded data into the ffmpeg worker
recorder.ondataavailable = async event => {
if (this.worker) {
const data = await event.data.arrayBuffer();
this.worker.postMessage({
type: 'muxed-data',
name: 'stream1',
data
}, [data]);
if (this.destination) {
this.destination.muxed_data(await event.data.arrayBuffer(),
{ name: 'stream1' });
}
};
@@ -96,16 +93,13 @@ export class HLS extends EventTarget {
dummy_processor.connect(context.destination);
// start the ffmpeg worker
this.worker = new Worker('./hls-worker.js');
this.worker.onerror = onerror;
this.worker.onmessage = e => {
const msg = e.data;
this.destination = new WebMDestination();
this.destination.addEventListener('message', e => {
const msg = e.detail;
switch (msg.type) {
case 'ready':
this.worker.postMessage({
type: 'start',
this.destination.start({
ffmpeg_lib_url: this.ffmpeg_lib_url,
base_url: this.base_url,
ffmpeg_args: [
'-i', '/work/stream1',
'-map', '0:v',
@@ -115,7 +109,8 @@ export class HLS extends EventTarget {
['-c:a', 'copy'] : // assume already AAC
['-c:a', 'aac', // re-encode audio as AAC-LC
'-b:a', audioBitsPerSecond.toString()]) // set audio bitrate
]
],
base_url: this.base_url
});
break;
@@ -130,8 +125,7 @@ export class HLS extends EventTarget {
break;
case 'exit':
this.worker.terminate();
this.worker = null;
this.destination = null;
if (recorder.state !== 'inactive') {
recorder.stop();
}
@@ -140,7 +134,7 @@ export class HLS extends EventTarget {
this.dispatchEvent(new CustomEvent(msg.type, { detail: { code: msg.code } }));
break;
}
};
});
}
webcodecs(video_codec, audio_codec, video_config, audio_config) {
@@ -248,7 +242,7 @@ export class HLS extends EventTarget {
codec_id: 'A_OPUS'
}
},
webm_destination: './hls-worker.js',
webm_destination: './webm-destination.js',
muxed_metadata: { name: 'stream1' },
ffmpeg_lib_url: this.ffmpeg_lib_url,
base_url: this.base_url,
@@ -264,7 +258,9 @@ export class HLS extends EventTarget {
}
end(force) {
if (this.worker) {
if (this.destination) {
this.destination.end({ force });
} else if (this.worker) {
this.worker.postMessage({
type: 'end',
force
@@ -273,7 +269,7 @@ export class HLS extends EventTarget {
}
onerror(e) {
if (this.worker) {
if (this.destination || this.worker) {
this.dispatchEvent(new CustomEvent('error', { detail: e }));
}
};

104
site/webm-destination.js Normal file
View File

@@ -0,0 +1,104 @@
export class WebMDestination extends EventTarget {
constructor() {
super();
setTimeout(() => {
this.dispatchEvent(new CustomEvent('message', { detail: {
type: 'ready'
}}));
}, 0);
}
start({ ffmpeg_lib_url, ffmpeg_args, base_url }) {
this.worker = new Worker(ffmpeg_lib_url);
this.worker.onerror = this.onerror.bind(this);
this.worker.onmessage = e => {
const msg = e.data;
switch (msg.type) {
case 'ready':
this.worker.postMessage({
type: 'run',
arguments: [
'-loglevel', 'debug',
...ffmpeg_args,
'-f', 'hls', // use hls encoder
'-hls_time', '2', // 2 second HLS chunks
'-hls_segment_type', 'mpegts', // MPEG2-TS muxer
'-hls_list_size', '2', // two chunks in the list at a time
'-hls_flags', 'split_by_time',
'/outbound/output.m3u8' // path to media playlist file in virtual FS,
// must be under /outbound
],
MEMFS: [
{ name: 'stream1' },
{ name: 'stream2' }
]
});
break;
case 'stdout':
console.log(msg.data);
break;
case 'stderr':
console.error(msg.data);
break;
case 'error':
case 'abort':
this.onerror(msg.data);
break;
case 'start-stream':
this.worker.postMessage({
type: 'base-url',
data: base_url
});
this.dispatchEvent(new CustomEvent('message', { detail: msg }));
break;
case 'exit':
this.worker = null;
this.dispatchEvent(new CustomEvent('message', { detail: {
type: msg.type,
code: msg.data
}}));
this.worker.terminate();
break;
}
};
}
muxed_data(data, { name }) {
if (this.worker) {
this.worker.postMessage({
type: 'stream-data',
name,
data
}, [data]);
}
}
end({ force }) {
if (this.worker) {
if (force) {
this.worker.terminate();
self.postMessage({
this.dispatchEvent(new CustomEvent('message', { detail: {
type: 'exit',
code: 'force-end'
}}));
});
} else {
this.worker.postMessage({
type: 'stream-end'
});
}
this.worker = null;
}
}
onerror(e) {
if (this.worker) {
console.error(e);
this.dispatchEvent(new CustomEvent('message', { detail: {
type: 'error',
detail: e.message
}}));
}
}
}