Fix async race condition bug

This commit is contained in:
Vanilagy
2025-05-08 16:23:07 +02:00
parent 94b797e227
commit 865fdcf110
3 changed files with 49 additions and 12 deletions
+6 -6
View File
@@ -21,7 +21,7 @@
chunked: true, chunked: true,
chunkSize: 2**20 chunkSize: 2**20
}); });
const outputFormat = new Metamuxer.OggOutputFormat(); const outputFormat = new Metamuxer.WavOutputFormat();
const button = document.createElement('button'); const button = document.createElement('button');
button.textContent = 'Cancel'; button.textContent = 'Cancel';
@@ -77,10 +77,10 @@
//width: 200, //width: 200,
//height: 100, //height: 100,
}, },
trim: { //trim: {
start: 0, // start: 0,
end: 30 // end: 30
}, //},
computeProgress: true computeProgress: true
}); });
console.log(conversion); console.log(conversion);
@@ -108,7 +108,7 @@
document.body.append(video); document.body.append(video);
video.play(); video.play();
//download(new Blob([target.buffer]), 'converted' + outputFormat.fileExtension); download(new Blob([target.buffer]), 'converted' + outputFormat.fileExtension);
function download(blob, filename) { function download(blob, filename) {
const url = URL.createObjectURL(blob); const url = URL.createObjectURL(blob);
+25
View File
@@ -43,6 +43,7 @@
format = new Metamuxer.OggOutputFormat(); format = new Metamuxer.OggOutputFormat();
format = new Metamuxer.Mp4OutputFormat({ fastStart: 'fragmented', minimumFragmentDuration: 2 }); format = new Metamuxer.Mp4OutputFormat({ fastStart: 'fragmented', minimumFragmentDuration: 2 });
format = new Metamuxer.MkvOutputFormat({ minimumClusterDuration: 2 }); format = new Metamuxer.MkvOutputFormat({ minimumClusterDuration: 2 });
format = new Metamuxer.WavOutputFormat();
let target = new Metamuxer.BufferTarget(); let target = new Metamuxer.BufferTarget();
/* /*
@@ -57,6 +58,30 @@
let output = new Metamuxer.Output({ format, target }); let output = new Metamuxer.Output({ format, target });
let sourcy = new Metamuxer.AudioBufferSource({
codec: 'pcm-s16',
bitrate: Metamuxer.QUALITY_HIGH
});
output.addAudioTrack(sourcy);
await output.start();
for (let i = 0; i < 1000; i++) {
let buf = new AudioBuffer({
length: 1024,
sampleRate: 48000,
numberOfChannels: 2
});
sourcy.add(buf);
}
console.log("Done")
await output.finalize();
await new Promise(() => {});
/* /*
let videoSource = new Metamuxer.EncodedVideoChunkSource('avc'); let videoSource = new Metamuxer.EncodedVideoChunkSource('avc');
output.addTrack(videoSource); output.addTrack(videoSource);
+18 -6
View File
@@ -278,10 +278,16 @@ class VideoEncoderWrapper {
} }
if (!this.encoderInitialized) { if (!this.encoderInitialized) {
if (this.ensureEncoderPromise) { if (!this.ensureEncoderPromise) {
void this.ensureEncoder(videoSample);
}
// No, this "if" statement is not useless. Sometimes, the above call to `ensureEncoder` might have
// synchronously completed and the encoder is already initialized. In this case, we don't need to await the
// promise anymore. This also fixes nasty async race condition bugs when multiple code paths are calling
// this method: It's important that the call that initialized the encoder go through this code first.
if (!this.encoderInitialized) {
await this.ensureEncoderPromise; await this.ensureEncoderPromise;
} else {
await this.ensureEncoder(videoSample);
} }
} }
assert(this.encoderInitialized); assert(this.encoderInitialized);
@@ -763,10 +769,16 @@ class AudioEncoderWrapper {
} }
if (!this.encoderInitialized) { if (!this.encoderInitialized) {
if (this.ensureEncoderPromise) { if (!this.ensureEncoderPromise) {
void this.ensureEncoder(audioSample);
}
// No, this "if" statement is not useless. Sometimes, the above call to `ensureEncoder` might have
// synchronously completed and the encoder is already initialized. In this case, we don't need to await the
// promise anymore. This also fixes nasty async race condition bugs when multiple code paths are calling
// this method: It's important that the call that initialized the encoder go through this code first.
if (!this.encoderInitialized) {
await this.ensureEncoderPromise; await this.ensureEncoderPromise;
} else {
await this.ensureEncoder(audioSample);
} }
} }
assert(this.encoderInitialized); assert(this.encoderInitialized);