From 0e5a9d59acc6a3ff501fc537f2726488c5e80f45 Mon Sep 17 00:00:00 2001 From: Casey Occhialini <1508707+littlespex@users.noreply.github.com> Date: Tue, 21 Jan 2025 19:15:58 -0800 Subject: [PATCH] chore: update API docs --- CHANGELOG.md | 3 + lib/config/common-media-library.api.md | 106 ++++++++++++++++++++++--- lib/src/isobmff/IsoView.ts | 9 ++- lib/src/isobmff/parsers/mdhd.ts | 12 ++- lib/src/isobmff/parsers/stss.ts | 50 ++++++++++++ lib/src/isobmff/parsers/tfra.ts | 19 ++++- lib/src/isobmff/parsers/trun.ts | 19 ++++- 7 files changed, 202 insertions(+), 16 deletions(-) create mode 100644 lib/src/isobmff/parsers/stss.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 5c8143f1..c7a24438 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Added +- ISO BMFF parser and utilities [#118](https://github.com/streaming-video-technology-alliance/common-media-library/issues/118) + ## [0.7.4] - 2024-11-05 diff --git a/lib/config/common-media-library.api.md b/lib/config/common-media-library.api.md index e63cba03..ca9c8fdd 100644 --- a/lib/config/common-media-library.api.md +++ b/lib/config/common-media-library.api.md @@ -554,10 +554,16 @@ export function decodeSfItem(input: string, options?: SfDecodeOptions): SfItem; // @beta export function decodeSfList(input: string, options?: SfDecodeOptions): SfMember[]; +// @beta +export type DecodingTimeSample = { + sampleCount: number; + sampleDelta: number; +}; + // @beta export type DecodingTimeToSampleBox = FullBox & { entryCount: number; - entries: Sample[]; + entries: DecodingTimeSample[]; }; // @beta @@ -648,13 +654,13 @@ export type FileTypeBox = TypeBox; export function filterBoxes(raw: IsoData, config: IsoViewConfig, fn: BoxFilter): Box[]; // @beta -export function filterBoxesByType(type: string, raw: IsoData, config: IsoViewConfig): Box[]; +export function filterBoxesByType(type: string, raw: IsoData, config?: IsoViewConfig): Box[]; // @beta export function findBox(raw: IsoData, config: IsoViewConfig, fn: BoxFilter): Box | null; // @beta -export function findBoxByType(type: string, raw: IsoData, config: IsoViewConfig): Box | null; +export function findBoxByType(type: string, raw: IsoData, config?: IsoViewConfig): Box | null; // @beta export function findCta608Nalus(raw: DataView, startPos: number, size: number): Array>; @@ -805,8 +811,6 @@ export class IsoView { get done(): boolean; // (undocumented) readArray: (type: T, size: number, length: number) => ISOFieldTypeMap[T][]; - // Warning: (ae-forgotten-export) The symbol "RawBox" needs to be exported by the entry point index.d.ts - // // (undocumented) readBox: () => RawBox; // (undocumented) @@ -844,7 +848,7 @@ export function kind(view: IsoView): TrackKindBox; export type LabelBox = FullBox & { isGroupLabel: boolean; labelId: number; - langauge: string; + language: string; label: string; }; @@ -866,6 +870,9 @@ export type ManifestFormat = 'hls' | 'dash'; // @beta export function mdat(view: IsoView): MediaDataBox; +// @beta +export function mdhd(view: IsoView): MediaHeaderBox; + // @beta export type MediaDataBox = { data: Uint8Array; @@ -889,6 +896,16 @@ export type MediaGroups = { }; }; +// @beta +export type MediaHeaderBox = FullBox & { + creationTime: number; + modificationTime: number; + timescale: number; + duration: number; + language: string; + preDefined: number; +}; + // @beta export function mehd(view: IsoView): MovieExtendsHeaderBox; @@ -1065,6 +1082,15 @@ type Range_2 = { }; export { Range_2 as Range } +// @beta +export type RawBox = { + type: string; + size: number; + largesize?: number; + usertype?: number[]; + data: IsoView; +}; + // @beta export type Reference = { reference: number; @@ -1155,12 +1181,6 @@ export class Row { setPenStyles(styles: Partial): void; } -// @beta -export type Sample = { - sampleCount: number; - sampleDelta: number; -}; - // @beta export type SampleDependencyTypeBox = FullBox & { sampleDependencyTable: number[]; @@ -1373,12 +1393,18 @@ export type SoundMediaHeaderBox = FullBox & { // @beta export function ssix(view: IsoView): SubsegmentIndexBox; +// @beta +export function sthd(view: IsoView): SubtitleMediaHeaderBox; + // @beta export const STRING = "string"; // @beta export function stsd(view: IsoView): SampleDescriptionBox; +// @beta +export function stss(view: IsoView): SyncSampleBox; + // @beta export function sttg(view: IsoView): WebVTTSettingsBox; @@ -1444,6 +1470,9 @@ export type SubsegmentIndexBox = FullBox & { subsegments: Subsegment[]; }; +// @beta +export type SubtitleMediaHeaderBox = FullBox; + // @beta export type SupportedField = 1 | 3; @@ -1452,6 +1481,17 @@ export type SwitchingSet = Ham & { tracks: Track[]; }; +// @beta +export type SyncSample = { + sampleNumber: number; +}; + +// @beta +export type SyncSampleBox = FullBox & { + entryCount: number; + entries: SyncSample[]; +}; + // @beta export const TEMPLATE = "template"; @@ -1468,6 +1508,9 @@ export function tfdt(view: IsoView): TrackFragmentDecodeTimeBox; // @beta export function tfhd(view: IsoView): TrackFragmentHeaderBox; +// @beta +export function tfra(view: IsoView): TrackFragmentRandomAccessBox; + // @beta export function tkhd(view: IsoView): TrackHeaderBox; @@ -1524,6 +1567,26 @@ export type TrackFragmentHeaderBox = FullBox & { defaultSampleFlags?: number; }; +// @beta +export type TrackFragmentRandomAccessBox = FullBox & { + trackId: number; + reserved: number; + numberOfEntry: number; + lengthSizeOfTrafNum: number; + lengthSizeOfTrunNum: number; + lengthSizeOfSampleNum: number; + entries: TrackFragmentRandomAccessEntry[]; +}; + +// @beta +export type TrackFragmentRandomAccessEntry = { + time: number; + moofOffset: number; + trafNumber: number; + trunNumber: number; + sampleNumber: number; +}; + // @beta export type TrackHeaderBox = FullBox & { creationTime: number; @@ -1547,12 +1610,31 @@ export type TrackKindBox = FullBox & { value: string; }; +// @beta +export type TrackRunBox = FullBox & { + sampleCount: number; + dataOffset?: number; + firstSampleFlags?: number; + samples: TrackRunSample[]; +}; + +// @beta +export type TrackRunSample = { + sampleDuration?: number; + sampleSize?: number; + sampleFlags?: number; + sampleCompositionTimeOffset?: number; +}; + // @alpha export type TrackType = 'audio' | 'video' | 'text'; // @beta export function trex(view: IsoView): TrackExtendsBox; +// @beta +export function trun(view: IsoView): TrackRunBox; + // @beta export type TypeBox = { majorBrand: string; diff --git a/lib/src/isobmff/IsoView.ts b/lib/src/isobmff/IsoView.ts index 95d00a5d..5e0d93b7 100644 --- a/lib/src/isobmff/IsoView.ts +++ b/lib/src/isobmff/IsoView.ts @@ -18,7 +18,14 @@ import { readUint } from './readers/readUint.js'; import { readUTF8String } from './readers/readUTF8String.js'; import { readUTF8TerminatedString } from './readers/readUTF8TerminatedString.js'; -type RawBox = { +/** + * Raw ISO BMFF data box. + * + * @group ISOBMFF + * + * @beta + */ +export type RawBox = { type: string; size: number; largesize?: number; diff --git a/lib/src/isobmff/parsers/mdhd.ts b/lib/src/isobmff/parsers/mdhd.ts index f562e9b1..f3183147 100644 --- a/lib/src/isobmff/parsers/mdhd.ts +++ b/lib/src/isobmff/parsers/mdhd.ts @@ -28,7 +28,17 @@ export type MediaHeaderBox = FullBox & { preDefined: number; } -// ISO/IEC 14496-12:2012 - 8.4.2 Media Header Box +/** + * Parse a MediaHeaderBox from an IsoView + * + * @param view - The IsoView to read data from + * + * @returns A parsed MediaHeaderBox + * + * @group ISOBMFF + * + * @beta + */ export function mdhd(view: IsoView): MediaHeaderBox { const { version, flags } = view.readFullBox(); diff --git a/lib/src/isobmff/parsers/stss.ts b/lib/src/isobmff/parsers/stss.ts new file mode 100644 index 00000000..cf802a9a --- /dev/null +++ b/lib/src/isobmff/parsers/stss.ts @@ -0,0 +1,50 @@ +import type { FullBox } from '../FullBox.js'; +import type { IsoView } from '../IsoView.js'; + +/** + * Sync sample + * + * @group ISOBMFF + * + * @beta + */ +export type SyncSample = { + sampleNumber: number; +} + +/** + * ISO/IEC 14496-12:2015 - 8.6.2 Sync Sample Box + * + * @group ISOBMFF + * + * @beta + */ +export type SyncSampleBox = FullBox & { + entryCount: number; + entries: SyncSample[]; +}; + +/** + * Parse a SyncSampleBox from an IsoView + * + * @param view - The IsoView to read data from + * + * @returns A parsed SyncSampleBox + * + * @group ISOBMFF + * + * @beta + */ +export function stss(view: IsoView): SyncSampleBox { + const { version, flags } = view.readFullBox(); + const entryCount = view.readUint(4); + + return { + version, + flags, + entryCount, + entries: view.readEntries(entryCount, () => ({ + sampleNumber: view.readUint(4), + })), + }; +}; diff --git a/lib/src/isobmff/parsers/tfra.ts b/lib/src/isobmff/parsers/tfra.ts index c522a0fd..965d40f9 100644 --- a/lib/src/isobmff/parsers/tfra.ts +++ b/lib/src/isobmff/parsers/tfra.ts @@ -1,6 +1,13 @@ import type { FullBox } from '../FullBox.js'; import type { IsoView } from '../IsoView'; +/** + * Track fragment random access entry + * + * @group ISOBMFF + * + * @beta + */ export type TrackFragmentRandomAccessEntry = { time: number; moofOffset: number; @@ -26,7 +33,17 @@ export type TrackFragmentRandomAccessBox = FullBox & { entries: TrackFragmentRandomAccessEntry[]; }; -// ISO/IEC 14496-12:2012 - 8.8.10 Track Fragment Random Access Box +/** + * Parse a TrackFragmentRandomAccessBox from an IsoView + * + * @param view - The IsoView to read data from + * + * @returns A parsed TrackFragmentRandomAccessBox + * + * @group ISOBMFF + * + * @beta + */ export function tfra(view: IsoView): TrackFragmentRandomAccessBox { const { version, flags } = view.readFullBox(); const trackId = view.readUint(4); diff --git a/lib/src/isobmff/parsers/trun.ts b/lib/src/isobmff/parsers/trun.ts index 9265f320..b54e3f36 100644 --- a/lib/src/isobmff/parsers/trun.ts +++ b/lib/src/isobmff/parsers/trun.ts @@ -1,6 +1,13 @@ import type { FullBox } from '../FullBox.js'; import type { IsoView } from '../IsoView.js'; +/** + * Track run sample + * + * @group ISOBMFF + * + * @beta + */ export type TrackRunSample = { sampleDuration?: number; sampleSize?: number; @@ -25,7 +32,17 @@ export type TrackRunBox = FullBox & { samples: TrackRunSample[]; }; -// ISO/IEC 14496-12:2012 - 8.8.8 Track Run Box +/** + * Parse a TrackRunBox from an IsoView + * + * @param view - The IsoView to read data from + * + * @returns A parsed TrackRunBox + * + * @group ISOBMFF + * + * @beta + */ export function trun(view: IsoView): TrackRunBox { const { version, flags } = view.readFullBox(); const sampleCount = view.readUint(4);