|
<video id="video" autoplay controls></video> |
|
|
|
<script src="./decoder_wasm/libffmpeg.js"></script> |
|
|
|
<script> |
|
(async () => { |
|
await new Promise((resolve) => setTimeout(resolve, 1000)); // なんか初期化に時間がかかるので待つ |
|
|
|
const fetcher = new Worker('worker-extractor.js'); |
|
const decoder = new Worker('worker-decoder.js'); |
|
|
|
const video = document.getElementById('video'); |
|
|
|
const videoTrackGenerator = new MediaStreamTrackGenerator({ kind: 'video' }); |
|
const audioTrackGenerator = new MediaStreamTrackGenerator({ kind: 'audio' }); |
|
|
|
const videoTrackGeneratorWriter = videoTrackGenerator.writable.getWriter(); |
|
const audioTrackGeneratorWriter = audioTrackGenerator.writable.getWriter(); |
|
|
|
const mediaStream = new MediaStream(); |
|
mediaStream.addTrack(videoTrackGenerator); |
|
mediaStream.addTrack(audioTrackGenerator); |
|
|
|
const videoCallback = Module.addFunction((addr_y, addr_u, addr_v, stride_y, stride_u, stride_v, width, height, pts) => { |
|
const out_y = HEAP8.subarray(addr_y, addr_y + stride_y * height); |
|
const out_u = HEAP8.subarray(addr_u, addr_u + (stride_u * height) / 2); |
|
const out_v = HEAP8.subarray(addr_v, addr_v + (stride_v * height) / 2); |
|
const buf_y = new Uint8Array(out_y); |
|
const buf_u = new Uint8Array(out_u); |
|
const buf_v = new Uint8Array(out_v); |
|
const data = new Uint8Array(buf_y.byteLength + buf_u.byteLength + buf_v.byteLength); |
|
data.set(buf_y, 0); |
|
data.set(buf_u, buf_y.byteLength); |
|
data.set(buf_v, buf_y.byteLength + buf_u.byteLength); |
|
|
|
const videoFrame = new VideoFrame(data, { |
|
format: 'I420', |
|
codedWidth: width, |
|
codedHeight: height, |
|
timestamp: pts / 90 * 1000, |
|
}) |
|
videoTrackGeneratorWriter.write(videoFrame); |
|
videoFrame.close(); |
|
}, 'viiiiiiiii'); |
|
|
|
const decoder_result = Module._openDecoder(2, videoCallback, 3); |
|
|
|
fetcher.onmessage = (e) => { |
|
if (e.data.type === 'video') { |
|
const { data, pts } = e.data.data; |
|
|
|
const cacheBuffer = Module._malloc(data.byteLength); |
|
Module.HEAP8.set(data, cacheBuffer); |
|
Module._decodeData(cacheBuffer, data.byteLength, pts); |
|
Module._free(cacheBuffer); |
|
} else if (e.data.type === 'audio') { |
|
const encodedAudioChunk = e.data.encodedAudioChunk; |
|
decoder.postMessage({ type: 'audio', encodedAudioChunk }); |
|
} |
|
}; |
|
|
|
decoder.onmessage = (e) => { |
|
if (e.data.type === 'video') { |
|
// pass |
|
} else if(e.data.type === 'audio') { |
|
const audioFrame = e.data.audioFrame; |
|
audioTrackGeneratorWriter.write(audioFrame); |
|
audioFrame.close(); |
|
} |
|
} |
|
|
|
video.srcObject = mediaStream; |
|
})(); |
|
</script> |