Files
mediabunny/dev/demux.html
T

603 lines
14 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);
fileInput.addEventListener('change', async () => {
const file = fileInput.files[0];
const source = new Metamuxer.BlobSource(file);
const input = new Metamuxer.Input({
formats: Metamuxer.ALL_FORMATS,
source
});
/*
const timestamps = [
4.16,
4.266666666666667,
4.373333333333333,
4.48,
4.586666666666667,
4.693333333333333,
4.8,
4.906666666666666,
5.013333333333334,
5.12,
5.226666666666667,
5.333333333333333,
5.4399999999999995,
5.546666666666667,
5.653333333333333,
5.76,
5.866666666666666,
5.973333333333333,
6.08,
6.186666666666666,
6.293333333333333,
6.4,
6.506666666666666,
6.613333333333333,
6.72,
6.826666666666666,
6.933333333333334,
7.039999999999999,
7.1466666666666665,
7.253333333333333
];
*/
const timestamps = [];
const videoTrack = await input.getPrimaryVideoTrack();
const packetSink = new Metamuxer.EncodedPacketSink(videoTrack);
for await (const packet of packetSink.packets()) {
if (packet.timestamp >= 1) {
break;
}
timestamps.push(packet.timestamp);
}
timestamps.sort((a, b) => a-b)
console.log(timestamps);
//return;
/*
const sink = new Metamuxer.EncodedPacketSink(videoTrack);
for await (const packet of sink.packets()) {
console.log(packet.sequenceNumber);
}
*/
const sink = new Metamuxer.CanvasSink(videoTrack, { width: 320 });
for await (const wrappedCanvas of sink.canvasesAtTimestamps(timestamps)) {
console.log(wrappedCanvas);
}
/*
const output = new Metamuxer.Output({
format: new Metamuxer.Mp3OutputFormat(),
target: new Metamuxer.BufferTarget()
});
const audioTrack = await input.getPrimaryAudioTrack();
const sink = new Metamuxer.AudioDataSink(audioTrack);
const mediaSource = new Metamuxer.AudioDataSource({
codec: 'mp3',
bitrate: 192000
});
output.addAudioTrack(mediaSource);
output.start();
for await (const { data } of sink.data()) {
await mediaSource.add(data);
}
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);
}
console.log(output.target.buffer)
download(new Blob([output.target.buffer]), 'converted.mp3');
*/
/*
const videoTrack = await input.getPrimaryVideoTrack();
const sink = new Metamuxer.EncodedVideoSampleSink(videoTrack);
console.log(await sink.getSample(16));
console.log(await sink.getFirstSample());
*/
/*
const source = new Metamuxer.BufferSource(await file.arrayBuffer()) ?? new Metamuxer.BlobSource(file);
const start = performance.now();
const input = new Metamuxer.Input({
formats: Metamuxer.ALL_FORMATS,
source
});
const output = new Metamuxer.Output({
format: new Metamuxer.WaveOutputFormat(),
target: new Metamuxer.BufferTarget()
});
output.start();
*/
/*
const audioTrack = await input.getPrimaryAudioTrack();
const sink = new Metamuxer.EncodedAudioSampleSink(audioTrack);
let total = 0;
for await (const sample of sink.samples(undefined, undefined, { metadataOnly: true })) {
total++;
if (performance.now() > 10000) {
break;
}
}
console.log("Done", total);
*/
/*
const sink = new Metamuxer.VideoFrameSink(videoTrack);
console.log(await videoTrack.getLanguageCode());
for await (const thing of sink.framesAtTimestamps([0.2, 1, 2, 423])) {
console.log(thing)
}
console.log("Done")
*/
/*
//const videoTrack = await input.getPrimaryVideoTrack();
//console.log(await videoTrack.computeSampleStats());
//return;
const target = new Metamuxer.BufferTarget();
const output = new Metamuxer.Output({
format: new Metamuxer.WaveOutputFormat(),
target
});
console.log(await input.getFormat());
const audioTrack = await input.getPrimaryAudioTrack();
const videoTrack = await input.getPrimaryVideoTrack();
const sink = new Metamuxer.EncodedAudioSampleSink(audioTrack);
const decoderConfig = await audioTrack.getDecoderConfig();
const sampleSource = new Metamuxer.EncodedAudioSampleSource(await audioTrack.getCodec());
const audioDataSource = new Metamuxer.AudioDataSource({ codec: 'pcm-s16', bitrate: 128e3 });
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 sink.samples()) {
// //console.log(sample.timestamp);
// //sample.timestamp *= 2;
// //console.log(sample);
// //console.log(sample)
// await sampleSource.add(sample, { decoderConfig });
//}
for await (const { data, timestamp } of new Metamuxer.AudioDataSink(audioTrack).data()) {
//console.log("wow", data.timestamp);
//console.log(sample)
await audioDataSource.add(data);
}
//for await (const sample of new Metamuxer.EncodedVideoSampleSink(videoTrack).samples()) {
// //console.log(sample)
// await videoSampleSource.add(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.wav');
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.add(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>