2021-07-16 14:18:18 +08:00
|
|
|
export class MuxReceiver extends EventTarget {
|
2021-07-12 00:43:24 +08:00
|
|
|
constructor() {
|
|
|
|
super();
|
|
|
|
setTimeout(() => {
|
|
|
|
this.dispatchEvent(new CustomEvent('message', { detail: {
|
|
|
|
type: 'ready'
|
|
|
|
}}));
|
|
|
|
}, 0);
|
|
|
|
}
|
|
|
|
|
2021-10-15 01:07:21 +08:00
|
|
|
start({ ffmpeg_lib_url, ffmpeg_args, base_url, protocol }) {
|
2021-07-12 00:43:24 +08:00
|
|
|
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: [
|
2021-07-16 14:18:18 +08:00
|
|
|
'-seekable', '0',
|
2021-07-12 00:43:24 +08:00
|
|
|
...ffmpeg_args,
|
2021-10-16 14:37:09 +08:00
|
|
|
...(protocol === 'dash' ? [
|
|
|
|
'-f', 'dash', // use dash encoder
|
|
|
|
'-seg_duration', '2', // 2 second segments
|
2021-10-17 15:00:32 +08:00
|
|
|
'-window_size', '2', // two chunks in the list at a time
|
|
|
|
'-streaming', '1', // fragment data
|
|
|
|
'-dash_segment_type', 'webm', // container type
|
2021-10-16 14:37:09 +08:00
|
|
|
'/outbound/output.mpd'
|
|
|
|
] : [
|
|
|
|
'-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
|
2021-10-17 15:00:32 +08:00
|
|
|
'-hls_flags', 'split_by_time', // if you don't have < 2s keyframes
|
2021-10-16 14:37:09 +08:00
|
|
|
'/outbound/output.m3u8' // path to media playlist file in virtual FS,
|
|
|
|
// must be under /outbound
|
|
|
|
])
|
2021-07-12 00:43:24 +08:00
|
|
|
],
|
|
|
|
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',
|
2021-10-15 01:07:21 +08:00
|
|
|
data: base_url,
|
2021-10-17 05:00:43 +08:00
|
|
|
protocol,
|
|
|
|
options: protocol === 'dash' ? {
|
2021-10-17 16:04:55 +08:00
|
|
|
//method: 'PUT'
|
2021-10-17 05:00:43 +08:00
|
|
|
} : {}
|
2021-07-12 00:43:24 +08:00
|
|
|
});
|
2021-07-30 14:53:34 +08:00
|
|
|
// falls through
|
|
|
|
case 'sending':
|
2021-07-12 00:43:24 +08:00
|
|
|
this.dispatchEvent(new CustomEvent('message', { detail: msg }));
|
|
|
|
break;
|
2021-07-16 14:18:18 +08:00
|
|
|
case 'ffexit':
|
2021-07-12 14:39:30 +08:00
|
|
|
this.worker.terminate();
|
2021-07-12 00:43:24 +08:00
|
|
|
this.worker = null;
|
|
|
|
this.dispatchEvent(new CustomEvent('message', { detail: {
|
2021-07-16 14:18:18 +08:00
|
|
|
type: 'exit',
|
|
|
|
code: msg.code
|
2021-07-12 00:43:24 +08:00
|
|
|
}}));
|
|
|
|
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();
|
2021-07-12 14:39:30 +08:00
|
|
|
this.worker = null;
|
|
|
|
this.dispatchEvent(new CustomEvent('message', { detail: {
|
|
|
|
type: 'exit',
|
|
|
|
code: 'force-end'
|
|
|
|
}}));
|
2021-07-12 00:43:24 +08:00
|
|
|
} else {
|
|
|
|
this.worker.postMessage({
|
|
|
|
type: 'stream-end'
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
onerror(e) {
|
|
|
|
if (this.worker) {
|
|
|
|
console.error(e);
|
|
|
|
this.dispatchEvent(new CustomEvent('message', { detail: {
|
|
|
|
type: 'error',
|
|
|
|
detail: e.message
|
|
|
|
}}));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|