mirror of
https://github.com/arcodange-org/mediabunny.git
synced 2026-10-03 13:53:53 +02:00
Fix invalid encoder AAC description on WebKit (fixes #206)
This commit is contained in:
@@ -621,6 +621,54 @@ export const parseAacAudioSpecificConfig = (bytes: Uint8Array | null): AacAudioS
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const buildAacAudioSpecificConfig = (config: {
|
||||||
|
objectType: number;
|
||||||
|
sampleRate: number;
|
||||||
|
numberOfChannels: number;
|
||||||
|
}) => {
|
||||||
|
let frequencyIndex = aacFrequencyTable.indexOf(config.sampleRate);
|
||||||
|
let customSampleRate: number | null = null;
|
||||||
|
|
||||||
|
if (frequencyIndex === -1) {
|
||||||
|
frequencyIndex = 15;
|
||||||
|
customSampleRate = config.sampleRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
const channelConfiguration = aacChannelMap.indexOf(config.numberOfChannels);
|
||||||
|
if (channelConfiguration === -1) {
|
||||||
|
throw new TypeError(`Unsupported number of channels: ${config.numberOfChannels}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
let bitCount = 5 + 4 + 4;
|
||||||
|
if (config.objectType >= 32) {
|
||||||
|
bitCount += 6;
|
||||||
|
}
|
||||||
|
if (frequencyIndex === 15) {
|
||||||
|
bitCount += 24;
|
||||||
|
}
|
||||||
|
|
||||||
|
const byteCount = Math.ceil(bitCount / 8);
|
||||||
|
const bytes = new Uint8Array(byteCount);
|
||||||
|
const bitstream = new Bitstream(bytes);
|
||||||
|
|
||||||
|
if (config.objectType < 32) {
|
||||||
|
bitstream.writeBits(5, config.objectType);
|
||||||
|
} else {
|
||||||
|
bitstream.writeBits(5, 31);
|
||||||
|
bitstream.writeBits(6, config.objectType - 32);
|
||||||
|
}
|
||||||
|
|
||||||
|
bitstream.writeBits(4, frequencyIndex);
|
||||||
|
|
||||||
|
if (frequencyIndex === 15) {
|
||||||
|
bitstream.writeBits(24, customSampleRate!);
|
||||||
|
}
|
||||||
|
|
||||||
|
bitstream.writeBits(4, channelConfiguration);
|
||||||
|
|
||||||
|
return bytes;
|
||||||
|
};
|
||||||
|
|
||||||
export const OPUS_SAMPLE_RATE = 48_000;
|
export const OPUS_SAMPLE_RATE = 48_000;
|
||||||
|
|
||||||
const PCM_CODEC_REGEX = /^pcm-([usf])(\d+)+(be)?$/;
|
const PCM_CODEC_REGEX = /^pcm-([usf])(\d+)+(be)?$/;
|
||||||
|
|||||||
@@ -9,6 +9,8 @@
|
|||||||
import {
|
import {
|
||||||
AUDIO_CODECS,
|
AUDIO_CODECS,
|
||||||
AudioCodec,
|
AudioCodec,
|
||||||
|
buildAacAudioSpecificConfig,
|
||||||
|
parseAacAudioSpecificConfig,
|
||||||
parsePcmCodec,
|
parsePcmCodec,
|
||||||
PCM_AUDIO_CODECS,
|
PCM_AUDIO_CODECS,
|
||||||
PcmAudioCodec,
|
PcmAudioCodec,
|
||||||
@@ -24,9 +26,11 @@ import {
|
|||||||
CallSerializer,
|
CallSerializer,
|
||||||
clamp,
|
clamp,
|
||||||
isFirefox,
|
isFirefox,
|
||||||
|
last,
|
||||||
promiseWithResolvers,
|
promiseWithResolvers,
|
||||||
setInt24,
|
setInt24,
|
||||||
setUint24,
|
setUint24,
|
||||||
|
toUint8Array,
|
||||||
} from './misc';
|
} from './misc';
|
||||||
import { Muxer } from './muxer';
|
import { Muxer } from './muxer';
|
||||||
import { SubtitleParser } from './subtitles';
|
import { SubtitleParser } from './subtitles';
|
||||||
@@ -1515,6 +1519,32 @@ class AudioEncoderWrapper {
|
|||||||
|
|
||||||
this.encoder = new AudioEncoder({
|
this.encoder = new AudioEncoder({
|
||||||
output: (chunk, meta) => {
|
output: (chunk, meta) => {
|
||||||
|
// WebKit emits an invalid description for AAC (https://bugs.webkit.org/show_bug.cgi?id=302253),
|
||||||
|
// which we try to detect here. If detected, we'll provide our own description instead, derived
|
||||||
|
// from the codec string and audio parameters.
|
||||||
|
if (this.encodingConfig.codec === 'aac' && meta?.decoderConfig) {
|
||||||
|
let needsDescriptionOverwrite = false;
|
||||||
|
if (!meta.decoderConfig.description || meta.decoderConfig.description.byteLength < 2) {
|
||||||
|
needsDescriptionOverwrite = true;
|
||||||
|
} else {
|
||||||
|
const audioSpecificConfig = parseAacAudioSpecificConfig(
|
||||||
|
toUint8Array(meta.decoderConfig.description),
|
||||||
|
);
|
||||||
|
|
||||||
|
needsDescriptionOverwrite = audioSpecificConfig.objectType === 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (needsDescriptionOverwrite) {
|
||||||
|
const objectType = Number(last(encoderConfig.codec.split('.')));
|
||||||
|
|
||||||
|
meta.decoderConfig.description = buildAacAudioSpecificConfig({
|
||||||
|
objectType,
|
||||||
|
numberOfChannels: meta.decoderConfig.numberOfChannels,
|
||||||
|
sampleRate: meta.decoderConfig.sampleRate,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const packet = EncodedPacket.fromEncodedChunk(chunk);
|
const packet = EncodedPacket.fromEncodedChunk(chunk);
|
||||||
|
|
||||||
this.encodingConfig.onEncodedPacket?.(packet, meta);
|
this.encodingConfig.onEncodedPacket?.(packet, meta);
|
||||||
|
|||||||
Reference in New Issue
Block a user