mirror of
https://github.com/arcodange-org/mediabunny.git
synced 2026-09-27 02:43:48 +02:00
Add reusable Opus identification header parsing function
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user