src/demux/base-audio-demuxer.ts
- import * as ID3 from '../demux/id3';
- import type {
- DemuxerResult,
- Demuxer,
- DemuxedAudioTrack,
- AppendedAudioFrame,
- DemuxedMetadataTrack,
- DemuxedAvcTrack,
- DemuxedUserdataTrack,
- KeyData,
- } from '../types/demuxer';
- import { dummyTrack } from './dummy-demuxed-track';
- import { appendUint8Array } from '../utils/mp4-tools';
- import { sliceUint8 } from '../utils/typed-array';
-
- class BaseAudioDemuxer implements Demuxer {
- protected _audioTrack!: DemuxedAudioTrack;
- protected _id3Track!: DemuxedMetadataTrack;
- protected frameIndex: number = 0;
- protected cachedData: Uint8Array | null = null;
- protected initPTS: number | null = null;
-
- resetInitSegment(audioCodec: string, videoCodec: string, duration: number) {
- this._id3Track = {
- type: 'id3',
- id: 0,
- pid: -1,
- inputTimeScale: 90000,
- sequenceNumber: 0,
- samples: [],
- dropped: 0,
- };
- }
-
- resetTimeStamp() {}
-
- resetContiguity(): void {}
-
- canParse(data: Uint8Array, offset: number): boolean {
- return false;
- }
-
- appendFrame(
- track: DemuxedAudioTrack,
- data: Uint8Array,
- offset: number
- ): AppendedAudioFrame | void {}
-
- // feed incoming data to the front of the parsing pipeline
- demux(data: Uint8Array, timeOffset: number): DemuxerResult {
- if (this.cachedData) {
- data = appendUint8Array(this.cachedData, data);
- this.cachedData = null;
- }
-
- let id3Data: Uint8Array | undefined = ID3.getID3Data(data, 0);
- let offset = id3Data ? id3Data.length : 0;
- let lastDataIndex;
- let pts;
- const track = this._audioTrack;
- const id3Track = this._id3Track;
- const timestamp = id3Data ? ID3.getTimeStamp(id3Data) : undefined;
- const length = data.length;
-
- if (this.frameIndex === 0 || this.initPTS === null) {
- this.initPTS = initPTSFn(timestamp, timeOffset);
- }
-
- // more expressive than alternative: id3Data?.length
- if (id3Data && id3Data.length > 0) {
- id3Track.samples.push({
- pts: this.initPTS,
- dts: this.initPTS,
- data: id3Data,
- });
- }
-
- pts = this.initPTS;
-
- while (offset < length) {
- if (this.canParse(data, offset)) {
- const frame = this.appendFrame(track, data, offset);
- if (frame) {
- this.frameIndex++;
- pts = frame.sample.pts;
- offset += frame.length;
- lastDataIndex = offset;
- } else {
- offset = length;
- }
- } else if (ID3.canParse(data, offset)) {
- // after a ID3.canParse, a call to ID3.getID3Data *should* always returns some data
- id3Data = ID3.getID3Data(data, offset)!;
- id3Track.samples.push({ pts: pts, dts: pts, data: id3Data });
- offset += id3Data.length;
- lastDataIndex = offset;
- } else {
- offset++;
- }
- if (offset === length && lastDataIndex !== length) {
- const partialData = sliceUint8(data, lastDataIndex);
- if (this.cachedData) {
- this.cachedData = appendUint8Array(this.cachedData, partialData);
- } else {
- this.cachedData = partialData;
- }
- }
- }
-
- return {
- audioTrack: track,
- avcTrack: dummyTrack() as DemuxedAvcTrack,
- id3Track,
- textTrack: dummyTrack() as DemuxedUserdataTrack,
- };
- }
-
- demuxSampleAes(
- data: Uint8Array,
- keyData: KeyData,
- timeOffset: number
- ): Promise<DemuxerResult> {
- return Promise.reject(
- new Error(`[${this}] This demuxer does not support Sample-AES decryption`)
- );
- }
-
- flush(timeOffset: number): DemuxerResult {
- // Parse cache in case of remaining frames.
- const cachedData = this.cachedData;
- if (cachedData) {
- this.cachedData = null;
- this.demux(cachedData, 0);
- }
-
- this.frameIndex = 0;
-
- return {
- audioTrack: this._audioTrack,
- avcTrack: dummyTrack() as DemuxedAvcTrack,
- id3Track: this._id3Track,
- textTrack: dummyTrack() as DemuxedUserdataTrack,
- };
- }
-
- destroy() {}
- }
-
- /**
- * Initialize PTS
- * <p>
- * use timestamp unless it is undefined, NaN or Infinity
- * </p>
- */
- export const initPTSFn = (
- timestamp: number | undefined,
- timeOffset: number
- ): number => {
- return Number.isFinite(timestamp as number)
- ? timestamp! * 90
- : timeOffset * 90000;
- };
- export default BaseAudioDemuxer;