diff --git a/src/codec.ts b/src/codec.ts index b987e1b..89516e4 100644 --- a/src/codec.ts +++ b/src/codec.ts @@ -967,6 +967,30 @@ export const parseAacAudioSpecificConfig = (bytes: Uint8Array | null) => { }; }; +export const parseOpusIdentificationHeader = (bytes: Uint8Array) => { + const view = toDataView(bytes); + + const outputChannelCount = view.getUint8(9); + const preSkip = view.getUint16(10, true); + const inputSampleRate = view.getUint32(12, true); + const outputGain = view.getInt16(16, true); + const channelMappingFamily = view.getUint8(18); + + let channelMappingTable: Uint8Array | null = null; + if (channelMappingFamily) { + channelMappingTable = bytes.subarray(19, 19 + 2 + outputChannelCount); + } + + return { + outputChannelCount, + preSkip, + inputSampleRate, + outputGain, + channelMappingFamily, + channelMappingTable, + }; +}; + // From https://datatracker.ietf.org/doc/html/rfc6716, in 48 kHz samples const OPUS_FRAME_DURATION_TABLE = [ 480, 960, 1920, 2880, diff --git a/src/isobmff/isobmff-boxes.ts b/src/isobmff/isobmff-boxes.ts index 1baa707..d77218a 100644 --- a/src/isobmff/isobmff-boxes.ts +++ b/src/isobmff/isobmff-boxes.ts @@ -16,6 +16,7 @@ import { import { AudioCodec, generateAv1CodecConfigurationFromCodecString, + parseOpusIdentificationHeader, parsePcmCodec, PCM_AUDIO_CODECS, PcmAudioCodec, @@ -824,19 +825,17 @@ export const dOps = (trackData: IsobmffAudioTrackData) => { if (description) { assert(description.byteLength >= 18); - const view = ArrayBuffer.isView(description) - ? new DataView(description.buffer, description.byteOffset, description.byteLength) - : new DataView(description); + const bytes = toUint8Array(description); + const header = parseOpusIdentificationHeader(bytes); - outputChannelCount = view.getUint8(9); - preSkip = view.getUint16(10, true); - inputSampleRate = view.getUint32(12, true); - outputGain = view.getInt16(16, true); - channelMappingFamily = view.getUint8(18); + outputChannelCount = header.outputChannelCount; + preSkip = header.preSkip; + inputSampleRate = header.inputSampleRate; + outputGain = header.outputGain; + channelMappingFamily = header.channelMappingFamily; - if (channelMappingFamily) { - const bytes = toUint8Array(description); - channelMappingTable = bytes.subarray(19, 19 + 2 + outputChannelCount); + if (header.channelMappingTable) { + channelMappingTable = header.channelMappingTable; } } diff --git a/src/matroska/matroska-muxer.ts b/src/matroska/matroska-muxer.ts index 7bd0318..75c457c 100644 --- a/src/matroska/matroska-muxer.ts +++ b/src/matroska/matroska-muxer.ts @@ -34,6 +34,7 @@ import { PCM_AUDIO_CODECS, PcmAudioCodec, generateAv1CodecConfigurationFromCodecString, + parseOpusIdentificationHeader, parsePcmCodec, validateAudioChunkMetadata, validateSubtitleMetadata, @@ -228,12 +229,11 @@ export class MatroskaMuxer extends Muxer { const description = trackData.info.decoderConfig.description; if (description) { - const view = ArrayBuffer.isView(description) - ? new DataView(description.buffer, description.byteOffset, description.byteLength) - : new DataView(description); + const bytes = toUint8Array(description); + const header = parseOpusIdentificationHeader(bytes); - // Read the value from the Opus Identification Header - seekPreRollNs = Math.round(1e9 * (view.getUint16(10, true) / 48000)); + // Use the preSkip value from the header + seekPreRollNs = Math.round(1e9 * (header.preSkip / 48000)); } } diff --git a/src/ogg/ogg-demuxer.ts b/src/ogg/ogg-demuxer.ts index 13686e9..14aa736 100644 --- a/src/ogg/ogg-demuxer.ts +++ b/src/ogg/ogg-demuxer.ts @@ -1,4 +1,4 @@ -import { AudioCodec, parseOpusTocByte } from '../codec'; +import { AudioCodec, parseOpusIdentificationHeader, parseOpusTocByte } from '../codec'; import { Demuxer } from '../demuxer'; import { Input } from '../input'; import { InputAudioTrack, InputAudioTrackBacking } from '../input-track'; @@ -236,12 +236,12 @@ export class OggDemuxer extends Demuxer { bitstream.description = firstPacket.data; bitstream.lastMetadataPacket = secondPacket; - const view = toDataView(firstPacket.data); - bitstream.numberOfChannels = view.getUint8(9); - bitstream.sampleRate = view.getUint32(12, true); + const header = parseOpusIdentificationHeader(firstPacket.data); + bitstream.numberOfChannels = header.outputChannelCount; + bitstream.sampleRate = header.inputSampleRate; bitstream.opusInfo = { - preSkip: view.getUint16(10, true), + preSkip: header.preSkip, }; }