/*! @license
* Shaka Player
* Copyright 2016 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
goog.provide('shaka.codec.Vorbis');
/**
* Vorbis utils.
*
* A Vorbis packet has no duration of its own: the audio that a packet adds
* depends on the sizes of its window and of the window before it, and the
* window size depends on the mode that the packet says it uses. This reads
* what is needed to know those sizes.
*
* @see https://xiph.org/vorbis/doc/Vorbis_I_spec.html
*/
shaka.codec.Vorbis = class {
/**
* Reads the window sizes and the modes from the headers of a stream.
*
* @param {!Uint8Array} codecPrivate The three headers (identification,
* comment and setup) with the Xiph lacing that Matroska uses: the number
* of headers minus one, the sizes of all but the last, and the headers.
* @return {?shaka.codec.Vorbis.Info}
*/
static parseHeaders(codecPrivate) {
const Vorbis = shaka.codec.Vorbis;
const headers = Vorbis.splitHeaders_(codecPrivate);
if (!headers) {
return null;
}
const [identification, , setup] = headers;
// The identification header: the packet type (1), 'vorbis', the version,
// the channels, the rate, three bitrates and the block sizes.
if (identification.length <= Vorbis.BLOCK_SIZES_OFFSET_ ||
identification[0] != Vorbis.PACKET_TYPE_IDENTIFICATION_) {
return null;
}
const sizes = identification[Vorbis.BLOCK_SIZES_OFFSET_];
// Two exponents of 2: the small window in the low nibble, the large in the
// high one.
const blockSizes = [1 << (sizes & 0x0f), 1 << (sizes >> 4)];
const modes = Vorbis.parseModes_(setup);
if (!modes) {
return null;
}
// The bits that write the mode of a packet: those that hold the largest
// number of a mode.
const modeBits = modes.length > 1 ?
32 - Math.clz32(modes.length - 1) : 0;
return {blockSizes, modeBlockFlags: modes, modeBits};
}
/**
* Gets the size of the window of an audio packet.
*
* @param {shaka.codec.Vorbis.Info} info
* @param {!Uint8Array} packet
* @return {number} The size in samples, or 0 if the packet is not audio.
*/
static getWindowSize(info, packet) {
// The first bit says whether it is audio (0) or a header (1).
if (!packet.length || (packet[0] & 1)) {
return 0;
}
// Then the number of the mode, least significant bit first.
let mode = 0;
for (let i = 0; i < info.modeBits; i++) {
const bit = 1 + i;
mode |= ((packet[bit >> 3] >> (bit & 7)) & 1) << i;
}
const blockFlag = info.modeBlockFlags[mode];
return blockFlag == null ? 0 : info.blockSizes[blockFlag];
}
/**
* Gets the samples between the start of a packet and the start of the next:
* a quarter of each of their windows, as consecutive windows overlap by half
* of the smaller one.
*
* @param {number} windowSize
* @param {number} nextWindowSize
* @return {number}
*/
static getAdvance(windowSize, nextWindowSize) {
return (windowSize + nextWindowSize) / 4;
}
/**
* @param {!Uint8Array} codecPrivate
* @return {?Array<!Uint8Array>} The headers, or null if it is not what a
* Matroska track writes.
* @private
*/
static splitHeaders_(codecPrivate) {
const Vorbis = shaka.codec.Vorbis;
if (codecPrivate.length < 1 ||
codecPrivate[0] != Vorbis.HEADER_COUNT_MINUS_ONE_) {
return null;
}
let offset = 1;
const sizes = [];
for (let i = 0; i < Vorbis.HEADER_COUNT_MINUS_ONE_; i++) {
let size = 0;
let part;
do {
if (offset >= codecPrivate.length) {
return null;
}
part = codecPrivate[offset++];
size += part;
} while (part == Vorbis.XIPH_RUN_CONTINUES_);
sizes.push(size);
}
const headers = [];
for (const size of sizes) {
if (offset + size > codecPrivate.length) {
return null;
}
headers.push(codecPrivate.subarray(offset, offset + size));
offset += size;
}
headers.push(codecPrivate.subarray(offset));
return headers;
}
/**
* Finds the modes at the end of the setup header. Every mode is 41 bits (a
* block flag, a window type and a transform type that are 0, and a mapping),
* and they are followed only by the framing bit, so they can be found from
* the end, without decoding the codebooks, floors and residues that come
* before them.
*
* @param {!Uint8Array} setup
* @return {?Array<number>} The block flag of each mode.
* @private
*/
static parseModes_(setup) {
const Vorbis = shaka.codec.Vorbis;
// Bits are numbered from the least significant bit of the first byte.
const readBits = (position, count) => {
let value = 0;
for (let i = 0; i < count; i++) {
const bit = position + i;
value += ((setup[bit >> 3] >> (bit & 7)) & 1) * Math.pow(2, i);
}
return value;
};
// The framing bit is the last bit that is set: zeros pad the last byte.
let last = setup.length - 1;
while (last >= 0 && setup[last] == 0) {
last--;
}
if (last < 0) {
return null;
}
const framingBit = last * 8 + (31 - Math.clz32(setup[last]));
// How many modes fit before the framing bit and look like modes.
let candidates = 0;
while (candidates < Vorbis.MAX_MODES_) {
const start = framingBit - Vorbis.MODE_BITS_ * (candidates + 1);
if (start - Vorbis.MODE_COUNT_BITS_ < 0) {
break;
}
// The window type and the transform type are 0 (16 bits each).
if (readBits(start + 1, 32) != 0) {
break;
}
candidates++;
}
// The number of modes, minus one, is written before the first one.
for (let count = candidates; count >= 1; count--) {
const start = framingBit - Vorbis.MODE_BITS_ * count;
if (readBits(start - Vorbis.MODE_COUNT_BITS_, Vorbis.MODE_COUNT_BITS_) +
1 == count) {
const flags = [];
for (let i = 0; i < count; i++) {
flags.push(readBits(start + Vorbis.MODE_BITS_ * i, 1));
}
return flags;
}
}
return null;
}
};
/**
* @typedef {{
* blockSizes: !Array<number>,
* modeBlockFlags: !Array<number>,
* modeBits: number,
* }}
*
* @property {!Array<number>} blockSizes
* The size in samples of the small and of the large window.
* @property {!Array<number>} modeBlockFlags
* For each mode, whether it uses the large window (1) or the small (0).
* @property {number} modeBits
* The number of bits that write the mode in a packet.
*/
shaka.codec.Vorbis.Info;
/**
* The number of headers in the codec configuration of Matroska, minus one: the
* identification, the comment and the setup headers.
* @private @const {number}
*/
shaka.codec.Vorbis.HEADER_COUNT_MINUS_ONE_ = 2;
/**
* In Xiph lacing a byte of 255 means that the size goes on in the next byte.
* @private @const {number}
*/
shaka.codec.Vorbis.XIPH_RUN_CONTINUES_ = 255;
/**
* The type of an identification header packet.
* @private @const {number}
*/
shaka.codec.Vorbis.PACKET_TYPE_IDENTIFICATION_ = 1;
/**
* Offset of the block sizes in the identification header: the packet type, the
* 6 bytes of 'vorbis', the version (4), the channels (1), the sample rate (4)
* and the three bitrates (12).
* @private @const {number}
*/
shaka.codec.Vorbis.BLOCK_SIZES_OFFSET_ = 28;
/**
* The size of a mode: block flag (1 bit), window type (16), transform type
* (16) and mapping (8).
* @private @const {number}
*/
shaka.codec.Vorbis.MODE_BITS_ = 41;
/**
* The size of the field that holds the number of modes, minus one.
* @private @const {number}
*/
shaka.codec.Vorbis.MODE_COUNT_BITS_ = 6;
/**
* The most modes a stream can have, as the count is 6 bits.
* @private @const {number}
*/
shaka.codec.Vorbis.MAX_MODES_ = 64;