mirror of
https://github.com/arcodange-org/mediabunny.git
synced 2026-10-02 21:33:52 +02:00
Implement ADTS demuxer, Fix MP3 demuxer race conditions
This commit is contained in:
@@ -0,0 +1,96 @@
|
||||
/*!
|
||||
* Copyright (c) 2025-present, Vanilagy and contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
import { Bitstream } from '../misc';
|
||||
import { Reader } from '../reader';
|
||||
|
||||
export const MAX_FRAME_HEADER_SIZE = 9;
|
||||
|
||||
export type FrameHeader = {
|
||||
objectType: number;
|
||||
samplingFrequencyIndex: number;
|
||||
channelConfiguration: number;
|
||||
frameLength: number;
|
||||
numberOfAacFrames: number;
|
||||
crcCheck: number | null;
|
||||
startPos: number;
|
||||
};
|
||||
|
||||
export class AdtsReader {
|
||||
pos = 0;
|
||||
constructor(public reader: Reader) {}
|
||||
|
||||
readBytes(length: number) {
|
||||
const { view, offset } = this.reader.getViewAndOffset(this.pos, this.pos + length);
|
||||
this.pos += length;
|
||||
|
||||
return new Uint8Array(view.buffer, offset, length);
|
||||
}
|
||||
|
||||
readFrameHeader(): FrameHeader | null {
|
||||
// https://wiki.multimedia.cx/index.php/ADTS (last visited: 2025/08/17)
|
||||
|
||||
const startPos = this.pos;
|
||||
|
||||
const bytes = this.readBytes(9); // 9 with CRC, 7 without CRC
|
||||
const bitstream = new Bitstream(bytes);
|
||||
|
||||
const syncword = bitstream.readBits(12);
|
||||
if (syncword !== 0b1111_11111111) {
|
||||
return null;
|
||||
}
|
||||
|
||||
bitstream.skipBits(1); // MPEG version
|
||||
const layer = bitstream.readBits(2);
|
||||
if (layer !== 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const protectionAbsence = bitstream.readBits(1);
|
||||
const objectType = bitstream.readBits(2) + 1;
|
||||
const samplingFrequencyIndex = bitstream.readBits(4);
|
||||
if (samplingFrequencyIndex === 15) {
|
||||
return null;
|
||||
}
|
||||
|
||||
bitstream.skipBits(1); // Private bit
|
||||
const channelConfiguration = bitstream.readBits(3);
|
||||
if (channelConfiguration === 0) {
|
||||
throw new Error('ADTS frames with channel configuration 0 are not supported.');
|
||||
}
|
||||
|
||||
bitstream.skipBits(1); // Originality
|
||||
bitstream.skipBits(1); // Home
|
||||
bitstream.skipBits(1); // Copyright ID bit
|
||||
bitstream.skipBits(1); // Copyright ID start
|
||||
const frameLength = bitstream.readBits(13);
|
||||
bitstream.skipBits(11); // Buffer fullness
|
||||
const numberOfAacFrames = bitstream.readBits(2) + 1;
|
||||
if (numberOfAacFrames !== 1) {
|
||||
throw new Error('ADTS frames with more than one AAC frame are not supported.');
|
||||
}
|
||||
|
||||
let crcCheck: number | null = null;
|
||||
|
||||
if (protectionAbsence === 1) { // No CRC
|
||||
this.pos -= 2;
|
||||
} else { // CRC
|
||||
crcCheck = bitstream.readBits(16);
|
||||
}
|
||||
|
||||
return {
|
||||
objectType,
|
||||
samplingFrequencyIndex,
|
||||
channelConfiguration,
|
||||
frameLength,
|
||||
numberOfAacFrames,
|
||||
crcCheck,
|
||||
startPos,
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user