Files
mediabunny/dev/demux.html
T

468 lines
12 KiB
HTML

<!DOCTYPE html>
<script src="../dist/metamuxer.js"></script>
<script type="module">
const fileInput = document.createElement('input');
fileInput.type = 'file';
document.body.append(fileInput);
/*
const encoder = new AudioEncoder({
output: console.log,
error: console.error
});
encoder.configure({
codec: 'vorbis',
numberOfChannels: 2,
sampleRate: 48000,
bitrate: 128000
});
let audioData = new AudioData({
format: 'f32',
numberOfChannels: 2,
sampleRate: 48000,
timestamp: 0,
data: new Float32Array(2 * 48000),
numberOfFrames: 48000
});
encoder.encode(audioData);
*/
fileInput.addEventListener('change', async () => {
const file = fileInput.files[0];
const source = new Metamuxer.BlobSource(file);
const start = performance.now();
const input = new Metamuxer.Input({
formats: Metamuxer.ALL_FORMATS,
source
});
//const videoTrack = await input.getPrimaryVideoTrack();
//console.log(await videoTrack.computeSampleStats());
//return;
const target = new Metamuxer.ArrayBufferTarget();
const output = new Metamuxer.Output({
format: new Metamuxer.MovOutputFormat({ fastStart: undefined }),
target
});
const audioTrack = await input.getPrimaryAudioTrack();
const videoTrack = await input.getPrimaryVideoTrack();
const drain = new Metamuxer.EncodedAudioSampleDrain(audioTrack);
const decoderConfig = await audioTrack.getDecoderConfig();
const sampleSource = new Metamuxer.EncodedAudioSampleSource(await audioTrack.getCodec());
const audioDataSource = new Metamuxer.AudioDataSource({ codec: 'ulaw' });
const videoSampleSource = new Metamuxer.EncodedVideoSampleSource(await videoTrack.getCodec());
output.addAudioTrack(audioDataSource ?? sampleSource);
output.addVideoTrack(videoSampleSource);
output.start();
const videoDecoderConfig = await videoTrack.getDecoderConfig();
/*
for await (const sample of drain.samples()) {
//sample.timestamp *= 2;
//console.log(sample);
//console.log(sample)
await sampleSource.digest(sample, { decoderConfig });
}*/
for await (const { data } of new Metamuxer.AudioDataDrain(audioTrack).data()) {
//console.log(sample)
await audioDataSource.digest(data);
}
for await (const sample of new Metamuxer.EncodedVideoSampleDrain(videoTrack).samples()) {
//console.log(sample)
await videoSampleSource.digest(sample, { decoderConfig: videoDecoderConfig });
}
await output.finalize();
console.log(target)
function download(blob, filename) {
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = filename;
a.click();
URL.revokeObjectURL(url);
}
download(new Blob([target.buffer]), 'converted.mov');
document.body.textContent = performance.now() - start;
/*
const input2 = new Metamuxer.Input({
formats: Metamuxer.ALL_FORMATS,
source: new Metamuxer.BufferSource(target.buffer)
});
const videoTrack2 = await input2.getPrimaryVideoTrack();
const drain2 = new Metamuxer.EncodedVideoSampleDrain(videoTrack2);
let i = 0;
for await (const sample of drain2.samples(undefined, undefined)) {
console.log(sample);
if (i++ > 10) {
break;
}
}
*/
/*
const videoTrack = await input.getPrimaryVideoTrack();
const drain = new Metamuxer.VideoFrameDrain(videoTrack);
async function* timestamps() {
const fromTime = 0;
const toTime = await videoTrack.computeDuration();
const extractDuration = toTime - fromTime;
const drain = new Metamuxer.EncodedVideoSampleDrain(videoTrack);
const thumbnailsNeeded = 16;
for (let i = 0; i < thumbnailsNeeded; i++) {
const startTime = (extractDuration * i) / thumbnailsNeeded + fromTime;
const endTime = Math.min(
(extractDuration * (i + 1)) / thumbnailsNeeded + fromTime,
toTime + 1,
);
const sample = await drain.getSample(startTime, { onlyMetadata: true });
let bestTimestamp = sample.timestamp;
if (sample.type !== 'key') {
const nextKeySample = await drain.getNextKeySample(sample, { onlyMetadata: true });
if (nextKeySample.timestamp < endTime) {
bestTimestamp = nextKeySample.timestamp;
}
}
yield bestTimestamp;
}
}
for await (const { frame, timestamp } of drain.framesAtTimestamps(timestamps())) {
console.log(frame.timestamp, timestamp)
frame.close();
}
console.log("done")
*/
/*
const audioTrack = await input.getPrimaryVideoTrack();
const drain = new Metamuxer.EncodedVideoChunkDrain(audioTrack);
for await (const chunk of drain.chunks()) {
//console.log(chunk);
}
document.body.textContent = performance.now() - start;
*/
/*
const drain = new Metamuxer.AudioBufferDrain(audioTrack);
const chunks = drain.buffers()
const a = chunks.next();
*/
//chunks.return();
//console.log("Done")
/*
const videoTrack = await input.getPrimaryVideoTrack();
const drain = new Metamuxer.VideoFrameDrain(videoTrack);
const target = new Metamuxer.ArrayBufferTarget();
const format = new Metamuxer.Mp4OutputFormat();
const output = new Metamuxer.Output({ target, format });
const mediaSource = new Metamuxer.VideoFrameSource({
codec: 'av1',
bitrate: 1e6
});
output.addVideoTrack(mediaSource);
output.start();
for await (const frame of drain.frames(0, 10)) {
await mediaSource.digest(frame);
frame.close();
}
await output.finalize();
function download(blob, filename) {
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = filename;
a.click();
URL.revokeObjectURL(url);
}
download(new Blob([target.buffer]), 'converted.mp4');
*/
/*
const videoTrack = await input.getPrimaryVideoTrack();
const drain = new Metamuxer.VideoFrameDrain(videoTrack);
async function* timestamps() {
const fromTime = 0;
const toTime = await videoTrack.computeDuration();
const extractDuration = toTime - fromTime;
const drain = new Metamuxer.EncodedVideoChunkDrain(videoTrack);
const thumbnailsNeeded = 16;
for (let i = 0; i < thumbnailsNeeded; i++) {
const startTime = (extractDuration * i) / thumbnailsNeeded + fromTime;
const endTime = Math.min(
(extractDuration * (i + 1)) / thumbnailsNeeded + fromTime,
toTime + 1,
);
const chunk = await drain.getChunk(startTime, { onlyMetadata: true });
let bestTimestamp = chunk.timestamp / 1e6;
if (chunk.type !== 'key') {
const nextKeyChunk = await drain.getNextKeyChunk(chunk, { onlyMetadata: true });
if (nextKeyChunk.timestamp / 1e6 < endTime) {
bestTimestamp = nextKeyChunk.timestamp / 1e6;
}
}
yield bestTimestamp;
}
}
for await (const frame of drain.framesAtTimestamps(timestamps())) {
const clone = structuredClone(frame);
frame.close();
console.log(clone)
}
console.log("done")
*/
/*
const videoTrack = await input.getPrimaryVideoTrack();
const drain = new Metamuxer.VideoFrameDrain(videoTrack);
const width = await videoTrack.getWidth();
const height = await videoTrack.getHeight();
const canvas = document.createElement('canvas');
canvas.width = width;
canvas.height = height;
document.body.append(canvas);
const context = canvas.getContext('2d');
// Top-level for await loop inside the event listener
for await (const frame of drain.frames()) {
context.drawImage(frame, 0, 0, width, height);
frame.close();
await new Promise(resolve => setTimeout(resolve, 1000 / 24));
}
*/
/*
const videoTrack = await input.getPrimaryVideoTrack();
const audioTrack = await input.getPrimaryAudioTrack();;
console.log(videoTrack.computeDuration());
console.log(await audioTrack.computeDuration());
*/
/*
const audioTrack = await input.getPrimaryAudioTrack();
const drain = new Metamuxer.AudioBufferDrain(audioTrack);
const context = new AudioContext();
const startTime = context.currentTime;
for await (const { buffer, timestamp } of drain.buffers()) {
const node = context.createBufferSource();
node.buffer = buffer;
node.connect(context.destination);
const start = startTime + timestamp
node.start(start);
if (start > context.currentTime + 5) {
await new Promise(resolve => {
const id = setInterval(() => {
if (start < context.currentTime + 5) {
clearInterval(id);
resolve();
}
}, 100);
});
}
}
*/
/*
const drain = new Metamuxer.AudioDataDrain(audioTrack);
console.time()
for await (const data of drain.data()) {
data.close();
}
console.timeEnd()
*/
/*
const drain = new Metamuxer.EncodedAudioChunkDrain(audioTrack);
for await (const chunk of drain.chunks()) {
console.log(chunk);
if (chunk.timestamp > 1e6) {
break;
}
}
*/
/*
const videoTrack = await input.getPrimaryVideoTrack();
const drain = new Metamuxer.VideoFrameDrain(videoTrack);
const width = await videoTrack.getWidth();
const height = await videoTrack.getHeight();
const canvas = document.createElement('canvas');
canvas.width = width;
canvas.height = height;
document.body.append(canvas);
const context = canvas.getContext('2d');
// Top-level for await loop inside the event listener
for await (const frame of drain.frames()) {
context.drawImage(frame, 0, 0, width, height);
frame.close();
}
*/
/*
const drain = new Metamuxer.EncodedVideoChunkDrain(videoTrack);
const startChunk = await drain.getFirstChunk();
for await (const chunk of drain.chunks(startChunk)) {
console.log(chunk.timestamp);
}
*/
/*
for (let i = 0; i < 2; i += 0.1) {
console.log(await drain.getChunk(i));
}
*/
/*
const drain = new Metamuxer.VideoFrameDrain(videoTrack);
for await (const frame of drain.frames()) {
// ...
}
console.log(await videoTrack.getDuration());
*/
/*
const drain = new Metamuxer.VideoFrameDrain(videoTrack);
const width = await videoTrack.getWidth();
const height = await videoTrack.getHeight();
const canvas = document.createElement('canvas');
canvas.width = width;
canvas.height = height;
document.body.append(canvas);
const context = canvas.getContext('2d');
// Top-level for await loop inside the event listener
for await (const frame of drain.frames()) {
context.drawImage(frame, 0, 0, width, height);
frame.close();
}
*/
/*
const videoTrack = await input.getPrimaryVideoTrack();
const drain = new Metamuxer.VideoFrameDrain(videoTrack);
for await (const frame of drain.frames(0.01)) {
console.log(frame)
frame.close()
if (frame.timestamp > 2e6) {
break;
}
}
*/
/*
const drain = new Metamuxer.EncodedVideoChunkDrain(videoTrack);
const decoder = new VideoDecoder({
output: console.log,
error: console.error
});
decoder.configure({
...await videoTrack.getDecoderConfig()
});
const firstChunk = await drain.getFirstChunk();
const secondChunk = await drain.getNextChunk(firstChunk);
const thirdChunk = await drain.getNextChunk(secondChunk);
console.log(firstChunk, secondChunk, thirdChunk);
decoder.decode(firstChunk);
decoder.decode(secondChunk);
decoder.decode(thirdChunk);
decoder.flush();
*/
/*
const drain = new Metamuxer.VideoFrameDrain(videoTrack);
const frame = await drain.getKeyFrame(69);
const canvas = document.createElement('canvas')
canvas.width = await videoTrack.getWidth();
canvas.height = await videoTrack.getHeight();
const context = canvas.getContext('2d');
context.drawImage(frame, 0, 0);
document.body.append(canvas);
*/
/*
const drain = new Metamuxer.EncodedVideoChunkDrain(videoTrack);
for await (const chunk of drain.chunks()) {
console.log(chunk);
if (chunk.timestamp > 1e6) {
break;
}
}
*/
});
</script>