From 5dda43959dbd27e00407ec1837f90acce4a4307a Mon Sep 17 00:00:00 2001 From: Vanilagy <1696106+Vanilagy@users.noreply.github.com> Date: Thu, 2 Jan 2025 15:42:04 +0100 Subject: [PATCH] Support mp4a.67 --- src/codec.ts | 25 +++++++++++++++++++++---- src/isobmff/isobmff-demuxer.ts | 8 ++++++-- 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/src/codec.ts b/src/codec.ts index 4678ff1..21cb074 100644 --- a/src/codec.ts +++ b/src/codec.ts @@ -2,6 +2,7 @@ import { COLOR_PRIMARIES_MAP, MATRIX_COEFFICIENTS_MAP, TRANSFER_CHARACTERISTICS_MAP, + assert, bytesToHexString, isAllowSharedBufferSource, last, @@ -392,10 +393,26 @@ export const buildAudioCodecString = (codec: AudioCodec, numberOfChannels: numbe throw new TypeError(`Unhandled codec '${codec}'.`); }; -export const extractAudioCodecString = (codec: AudioCodec, description: Uint8Array | null) => { +export type AacCodecInfo = { + isMpeg2: boolean; +}; + +export const extractAudioCodecString = (trackInfo: { + codec: AudioCodec | null; + codecDescription: Uint8Array | null; + aacCodecInfo: AacCodecInfo | null; +}) => { + const { codec, codecDescription, aacCodecInfo } = trackInfo; + if (codec === 'aac') { - const audioSpecificConfig = parseAacAudioSpecificConfig(description); - return `mp4a.40.${audioSpecificConfig.objectType}`; + assert(aacCodecInfo); + + if (aacCodecInfo.isMpeg2) { + return 'mp4a.67'; + } else { + const audioSpecificConfig = parseAacAudioSpecificConfig(codecDescription); + return `mp4a.40.${audioSpecificConfig.objectType}`; + } } else if (codec === 'mp3') { return 'mp3'; } else if (codec === 'opus') { @@ -404,7 +421,7 @@ export const extractAudioCodecString = (codec: AudioCodec, description: Uint8Arr return 'vorbis'; } else if (codec === 'flac') { return 'flac'; - } else if (codec.startsWith('pcm-')) { + } else if (codec?.startsWith('pcm-')) { return codec; } else if (codec === 'ulaw') { return 'ulaw'; diff --git a/src/isobmff/isobmff-demuxer.ts b/src/isobmff/isobmff-demuxer.ts index ec54106..ed03f46 100644 --- a/src/isobmff/isobmff-demuxer.ts +++ b/src/isobmff/isobmff-demuxer.ts @@ -1,4 +1,5 @@ import { + AacCodecInfo, AudioCodec, Av1CodecInfo, extractAudioCodecString, @@ -67,6 +68,7 @@ type InternalTrack = { sampleRate: number; codec: AudioCodec | null; codecDescription: Uint8Array | null; + aacCodecInfo: AacCodecInfo | null; }; }); @@ -647,6 +649,7 @@ export class IsobmffDemuxer extends Demuxer { sampleRate: -1, codec: null, codecDescription: null, + aacCodecInfo: null, }; } }; break; @@ -972,8 +975,9 @@ export class IsobmffDemuxer extends Demuxer { const payloadStart = this.isobmffReader.pos; const objectTypeIndication = this.isobmffReader.readU8(); - if (objectTypeIndication === 0x40) { + if (objectTypeIndication === 0x40 || objectTypeIndication === 0x67) { track.info.codec = 'aac'; + track.info.aacCodecInfo = { isMpeg2: objectTypeIndication === 0x67 }; } else if (objectTypeIndication === 0x69 || objectTypeIndication === 0x6b) { track.info.codec = 'mp3'; } else if (objectTypeIndication === 0xdd) { @@ -2179,7 +2183,7 @@ class IsobmffAudioTrackBacking extends IsobmffTrackBacking im async getDecoderConfig(): Promise { return { - codec: extractAudioCodecString(this.internalTrack.info.codec!, this.internalTrack.info.codecDescription), + codec: extractAudioCodecString(this.internalTrack.info), numberOfChannels: this.internalTrack.info.numberOfChannels, sampleRate: this.internalTrack.info.sampleRate, description: this.internalTrack.info.codecDescription ?? undefined,