mirror of
https://github.com/arcodange-org/mediabunny.git
synced 2026-09-27 19:03:46 +02:00
Migrate all codec data parsing logic into new file
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import { OPUS_INTERNAL_SAMPLE_RATE, parseOpusIdentificationHeader } from '../codec';
|
||||
import { OPUS_INTERNAL_SAMPLE_RATE } from '../codec';
|
||||
import { parseModesFromVorbisSetupPacket, parseOpusIdentificationHeader } from '../codec-data';
|
||||
import { Demuxer } from '../demuxer';
|
||||
import { Input } from '../input';
|
||||
import { InputAudioTrack, InputAudioTrackBacking } from '../input-track';
|
||||
@@ -6,7 +7,7 @@ import { PacketRetrievalOptions } from '../media-sink';
|
||||
import { assert, AsyncMutex, findLast, roundToPrecision, toDataView, UNDETERMINED_LANGUAGE } from '../misc';
|
||||
import { EncodedPacket, PLACEHOLDER_DATA } from '../packet';
|
||||
import { Reader } from '../reader';
|
||||
import { computeOggPageCrc, extractSampleMetadata, OggCodecInfo, parseModesFromVorbisSetupPacket } from './ogg-misc';
|
||||
import { computeOggPageCrc, extractSampleMetadata, OggCodecInfo } from './ogg-misc';
|
||||
import { MAX_PAGE_HEADER_SIZE, MAX_PAGE_SIZE, MIN_PAGE_HEADER_SIZE, OggReader, Page } from './ogg-reader';
|
||||
|
||||
type LogicalBitstream = {
|
||||
|
||||
+2
-90
@@ -1,5 +1,5 @@
|
||||
import { parseOpusTocByte } from '../codec';
|
||||
import { assert, Bitstream, ilog, toDataView } from '../misc';
|
||||
import { parseOpusTocByte } from '../codec-data';
|
||||
import { assert, ilog, toDataView } from '../misc';
|
||||
|
||||
export const OGGS = 0x5367674f; // 'OggS'
|
||||
|
||||
@@ -93,91 +93,3 @@ export const extractSampleMetadata = (
|
||||
vorbisBlockSize: currentBlocksize,
|
||||
};
|
||||
};
|
||||
|
||||
// Based on vorbis_parser.c from FFmpeg.
|
||||
export const parseModesFromVorbisSetupPacket = (setupHeader: Uint8Array) => {
|
||||
// Verify that this is a Setup header.
|
||||
if (setupHeader.length < 7) {
|
||||
throw new Error('Setup header is too short.');
|
||||
}
|
||||
if (setupHeader[0] !== 5) {
|
||||
throw new Error('Wrong packet type in Setup header.');
|
||||
}
|
||||
const signature = String.fromCharCode(...setupHeader.slice(1, 7));
|
||||
if (signature !== 'vorbis') {
|
||||
throw new Error('Invalid packet signature in Setup header.');
|
||||
}
|
||||
|
||||
// Reverse the entire buffer.
|
||||
const bufSize = setupHeader.length;
|
||||
const revBuffer = new Uint8Array(bufSize);
|
||||
for (let i = 0; i < bufSize; i++) {
|
||||
revBuffer[i] = setupHeader[bufSize - 1 - i]!;
|
||||
}
|
||||
|
||||
// Initialize a Bitstream on the reversed buffer.
|
||||
const bitstream = new Bitstream(revBuffer);
|
||||
|
||||
// --- Find the framing bit.
|
||||
// In FFmpeg code, we scan until get_bits1() returns 1.
|
||||
let gotFramingBit = 0;
|
||||
while (bitstream.getBitsLeft() > 97) {
|
||||
if (bitstream.readBits(1) === 1) {
|
||||
gotFramingBit = bitstream.pos;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (gotFramingBit === 0) {
|
||||
throw new Error('Invalid Setup header: framing bit not found.');
|
||||
}
|
||||
|
||||
// --- Search backwards for a valid mode header.
|
||||
// We try to “guess” the number of modes by reading a fixed pattern.
|
||||
let modeCount = 0;
|
||||
let gotModeHeader = false;
|
||||
let lastModeCount = 0;
|
||||
while (bitstream.getBitsLeft() >= 97) {
|
||||
const tempPos = bitstream.pos;
|
||||
const a = bitstream.readBits(8);
|
||||
const b = bitstream.readBits(16);
|
||||
const c = bitstream.readBits(16);
|
||||
// If a > 63 or b or c nonzero, assume we’ve gone too far.
|
||||
if (a > 63 || b !== 0 || c !== 0) {
|
||||
bitstream.pos = tempPos;
|
||||
break;
|
||||
}
|
||||
bitstream.skipBits(1);
|
||||
modeCount++;
|
||||
if (modeCount > 64) {
|
||||
break;
|
||||
}
|
||||
const bsClone = bitstream.clone();
|
||||
const candidate = bsClone.readBits(6) + 1;
|
||||
if (candidate === modeCount) {
|
||||
gotModeHeader = true;
|
||||
lastModeCount = modeCount;
|
||||
}
|
||||
}
|
||||
if (!gotModeHeader) {
|
||||
throw new Error('Invalid Setup header: mode header not found.');
|
||||
}
|
||||
if (lastModeCount > 63) {
|
||||
throw new Error(`Unsupported mode count: ${lastModeCount}.`);
|
||||
}
|
||||
const finalModeCount = lastModeCount;
|
||||
|
||||
// --- Reinitialize the bitstream.
|
||||
bitstream.pos = 0;
|
||||
// Skip the bits up to the found framing bit.
|
||||
bitstream.skipBits(gotFramingBit);
|
||||
|
||||
// --- Now read, for each mode (in reverse order), 40 bits then one bit.
|
||||
// That one bit is the mode blockflag.
|
||||
const modeBlockflags = Array(finalModeCount).fill(0) as number[];
|
||||
for (let i = finalModeCount - 1; i >= 0; i--) {
|
||||
bitstream.skipBits(40);
|
||||
modeBlockflags[i] = bitstream.readBits(1);
|
||||
}
|
||||
|
||||
return { modeBlockflags };
|
||||
};
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { OPUS_INTERNAL_SAMPLE_RATE, parseOpusIdentificationHeader, validateAudioChunkMetadata } from '../codec';
|
||||
import { OPUS_INTERNAL_SAMPLE_RATE, validateAudioChunkMetadata } from '../codec';
|
||||
import { parseModesFromVorbisSetupPacket, parseOpusIdentificationHeader } from '../codec-data';
|
||||
import { assert, setInt64, toDataView, toUint8Array } from '../misc';
|
||||
import { Muxer } from '../muxer';
|
||||
import { Output, OutputAudioTrack } from '../output';
|
||||
@@ -10,7 +11,6 @@ import {
|
||||
extractSampleMetadata,
|
||||
OggCodecInfo,
|
||||
OGGS,
|
||||
parseModesFromVorbisSetupPacket,
|
||||
} from './ogg-misc';
|
||||
import { MAX_PAGE_SIZE } from './ogg-reader';
|
||||
|
||||
|
||||
Reference in New Issue
Block a user