Turn AudioBuffers into AudioData in a chunked fashion

This commit is contained in:
Vanilagy
2025-01-02 19:28:43 +01:00
parent 0f25dcb096
commit 022b157eeb
5 changed files with 53 additions and 25 deletions
-1
View File
@@ -1,4 +1,3 @@
/node_modules
/build
/dist
todo.txt
+3 -1
View File
@@ -40,6 +40,7 @@
format = new Metamuxer.Mp4OutputFormat({ fastStart: false }); // new Metamuxer.MkvOutputFormat();// new Metamuxer.Mp4OutputFormat({ fastStart: false });
let target = new Metamuxer.ArrayBufferTarget();
/*
target = new Metamuxer.StreamTarget(new WritableStream({
async write(chunk) {
console.log(chunk)
@@ -47,6 +48,7 @@
await new Promise(resolve => setTimeout(resolve, 250));
}
}), { chunked: true });
*/
let output = new Metamuxer.Output({ format, target });
@@ -170,5 +172,5 @@ Testing... <00:17.350>One... <00:18.125>Two...
await output.finalize();
console.log(target);
//download(new Blob([target.buffer]), 'test.mp4');
download(new Blob([target.buffer]), 'test.mp4');
</script>
+1 -1
View File
@@ -1076,7 +1076,7 @@ export class IsobmffDemuxer extends Demuxer {
const startPos = this.isobmffReader.pos;
while (true) {
while (this.isobmffReader.pos < boxEndPos) {
const flagAndType = this.isobmffReader.readU8();
const metadataBlockLength = this.isobmffReader.readU24();
const type = flagAndType & BLOCK_TYPE_MASK;
+38 -21
View File
@@ -517,32 +517,49 @@ export class AudioBufferSource extends AudioSource {
throw new TypeError('audioBuffer must be an AudioBuffer.');
}
const MAX_FLOAT_COUNT = 64 * 1024 * 1024;
const numberOfChannels = audioBuffer.numberOfChannels;
const sampleRate = audioBuffer.sampleRate;
const numberOfFrames = audioBuffer.length;
const totalFrames = audioBuffer.length;
const maxFramesPerChunk = Math.floor(MAX_FLOAT_COUNT / numberOfChannels);
// Create a planar F32 array containing all channels
const data = new Float32Array(numberOfChannels * numberOfFrames);
for (let channel = 0; channel < numberOfChannels; channel++) {
const channelData = audioBuffer.getChannelData(channel);
data.set(channelData, channel * numberOfFrames);
let currentRelativeFrame = 0;
let remainingFrames = totalFrames;
const promises: Promise<void>[] = [];
// Create AudioData in a chunked fashion so we don't create huge Float32Arrays
while (remainingFrames > 0) {
const framesToCopy = Math.min(maxFramesPerChunk, remainingFrames);
const chunkData = new Float32Array(numberOfChannels * framesToCopy);
for (let channel = 0; channel < numberOfChannels; channel++) {
audioBuffer.copyFromChannel(
chunkData.subarray(channel * framesToCopy, channel * framesToCopy + framesToCopy),
channel,
currentRelativeFrame,
);
}
const audioData = new AudioData({
format: 'f32-planar',
sampleRate,
numberOfFrames: framesToCopy,
numberOfChannels,
timestamp: (1e6 * (this._accumulatedFrameCount + currentRelativeFrame)) / sampleRate,
data: chunkData,
});
promises.push(this._encoder.digest(audioData));
audioData.close();
currentRelativeFrame += framesToCopy;
remainingFrames -= framesToCopy;
}
const audioData = new AudioData({
format: 'f32-planar',
sampleRate,
numberOfFrames,
numberOfChannels,
timestamp: Math.round(1e6 * this._accumulatedFrameCount / sampleRate),
data: data,
});
const promise = this._encoder.digest(audioData);
audioData.close();
this._accumulatedFrameCount += numberOfFrames;
return promise;
this._accumulatedFrameCount += totalFrames;
return Promise.all(promises);
}
/** @internal */
+10
View File
@@ -0,0 +1,10 @@
- Manual key frame passing
- Progress reporting
- Test tree shaking
- Throw if edit list detected
- Audio codec string regex validation
- Add the new audio codecs to muxers
- Mov muxer!!! Only mov can hold PCM audio, MP4 cannot
- Metadata methods for computing average fps and bitrate
- close method on Output to cancel it (and dispose the encoders). Perhaps abort is a better title
- lower default key frame interval (3 secs is better I think?) and make it outside-configurable