Initial working version

This commit is contained in:
Samuel Kent
2022-12-22 20:22:22 +11:00
parent ce9675a1cc
commit ced7fa5092
902 changed files with 150252 additions and 0 deletions
+48
View File
@@ -0,0 +1,48 @@
import { IGetToken } from 'strtok3/lib/core';
/**
* Opus ID Header interface
* Ref: https://wiki.xiph.org/OggOpus#ID_Header
*/
export interface IIdHeader {
/**
* Magic signature: "OpusHead" (64 bits)
*/
magicSignature: string;
/**
* Version number (8 bits unsigned): 0x01 for this spec
*/
version: number;
/**
* Channel count 'c' (8 bits unsigned): MUST be > 0
*/
channelCount: number;
/**
* Pre-skip (16 bits unsigned, little endian)
*/
preSkip: number;
/**
* Input sample rate (32 bits unsigned, little endian): informational only
*/
inputSampleRate: number;
/**
* Output gain (16 bits, little endian, signed Q7.8 in dB) to apply when decoding
*/
outputGain: number;
/**
* Channel mapping family (8 bits unsigned)
* - 0 = one stream: mono or L,R stereo
* - 1 = channels in vorbis spec order: mono or L,R stereo or ... or FL,C,FR,RL,RR,LFE, ...
* - 2..254 = reserved (treat as 255)
* - 255 = no defined channel meaning
*/
channelMapping: number;
}
/**
* Opus ID Header parser
* Ref: https://wiki.xiph.org/OggOpus#ID_Header
*/
export declare class IdHeader implements IGetToken<IIdHeader> {
len: number;
constructor(len: number);
get(buf: any, off: any): IIdHeader;
}
+28
View File
@@ -0,0 +1,28 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.IdHeader = void 0;
const Token = require("token-types");
/**
* Opus ID Header parser
* Ref: https://wiki.xiph.org/OggOpus#ID_Header
*/
class IdHeader {
constructor(len) {
this.len = len;
if (len < 19) {
throw new Error("ID-header-page 0 should be at least 19 bytes long");
}
}
get(buf, off) {
return {
magicSignature: new Token.StringType(8, 'ascii').get(buf, off + 0),
version: buf.readUInt8(off + 8),
channelCount: buf.readUInt8(off + 9),
preSkip: buf.readInt16LE(off + 10),
inputSampleRate: buf.readInt32LE(off + 12),
outputGain: buf.readInt16LE(off + 16),
channelMapping: buf.readUInt8(off + 18)
};
}
}
exports.IdHeader = IdHeader;
+25
View File
@@ -0,0 +1,25 @@
/// <reference types="node" />
import { ITokenizer } from 'strtok3/lib/core';
import { IPageHeader } from '../Ogg';
import { VorbisParser } from '../vorbis/VorbisParser';
import { IOptions } from '../../type';
import { INativeMetadataCollector } from '../../common/MetadataCollector';
/**
* Opus parser
* Internet Engineering Task Force (IETF) - RFC 6716
* Used by OggParser
*/
export declare class OpusParser extends VorbisParser {
private tokenizer;
private idHeader;
private lastPos;
constructor(metadata: INativeMetadataCollector, options: IOptions, tokenizer: ITokenizer);
/**
* Parse first Opus Ogg page
* @param {IPageHeader} header
* @param {Buffer} pageData
*/
protected parseFirstPage(header: IPageHeader, pageData: Buffer): void;
protected parseFullPage(pageData: Buffer): void;
calculateDuration(header: IPageHeader): void;
}
+56
View File
@@ -0,0 +1,56 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.OpusParser = void 0;
const Token = require("token-types");
const Opus = require("./Opus");
const VorbisParser_1 = require("../vorbis/VorbisParser");
/**
* Opus parser
* Internet Engineering Task Force (IETF) - RFC 6716
* Used by OggParser
*/
class OpusParser extends VorbisParser_1.VorbisParser {
constructor(metadata, options, tokenizer) {
super(metadata, options);
this.tokenizer = tokenizer;
this.lastPos = -1;
}
/**
* Parse first Opus Ogg page
* @param {IPageHeader} header
* @param {Buffer} pageData
*/
parseFirstPage(header, pageData) {
this.metadata.setFormat('codec', 'Opus');
// Parse Opus ID Header
this.idHeader = new Opus.IdHeader(pageData.length).get(pageData, 0);
if (this.idHeader.magicSignature !== "OpusHead")
throw new Error("Illegal ogg/Opus magic-signature");
this.metadata.setFormat('sampleRate', this.idHeader.inputSampleRate);
this.metadata.setFormat('numberOfChannels', this.idHeader.channelCount);
}
parseFullPage(pageData) {
const magicSignature = new Token.StringType(8, 'ascii').get(pageData, 0);
switch (magicSignature) {
case 'OpusTags':
this.parseUserCommentList(pageData, 8);
this.lastPos = this.tokenizer.position - pageData.length;
break;
default:
break;
}
}
calculateDuration(header) {
if (this.metadata.format.sampleRate && header.absoluteGranulePosition >= 0) {
// Calculate duration
const pos_48bit = header.absoluteGranulePosition - this.idHeader.preSkip;
this.metadata.setFormat('numberOfSamples', pos_48bit);
this.metadata.setFormat('duration', pos_48bit / 48000);
if (this.lastPos !== -1 && this.tokenizer.fileInfo.size && this.metadata.format.duration) {
const dataSize = this.tokenizer.fileInfo.size - this.lastPos;
this.metadata.setFormat('bitrate', 8 * dataSize / this.metadata.format.duration);
}
}
}
}
exports.OpusParser = OpusParser;