Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,10 @@ Useful for reading codec parameters out of a `codecs=` string, checking support
| EVC | ✅ | ✅ |
| L-HEVC | ✅ | ✅ |
| MP4 (mp4a/mp4v — AAC, MP3, MPEG-4/2) | ✅ | ✅ |
| AVS3 video/audio (avs3/av3a) | ✅ | ✅ |
| AVS3 video/audio (avs3/lav3/av3a) | ✅ | ✅ |
| AVS2 audio (cavs) | ✅ | ✅ |
| MPEG-H 3D Audio (mha1/mhm1) | ✅ | ✅ |
| Parameterless (DTS, VC-1, Opus, FLAC, Vorbis, ALAC, PCM) | ✅ | ✅ |
| Parameterless (DTS, VC-1, Opus, FLAC, Vorbis, ALAC, PCM, AMR, 3GPP text, CEA-608/708, DRA) | ✅ | ✅ |
| Uncompressed (uncv/unci) | ✅ | ✅ |
| Subtitles (WebVTT wvtt, TTML stpp) | ✅ | ✅ |

Expand Down Expand Up @@ -103,7 +103,7 @@ console.log(info.toString()); // 'avc1.640028'

- `codecInfoFactory(codecString)` — dispatches by prefix (`vp08`/`vp8`, `vp09`/`vp9`, `av01`,
`avc1`/`avc2`/`avc3`/`avc4`, `hev1`/`hvc1`, `vvc1`/`vvi1`, `lvc1`, `apv1`, `evc1`, `lhv1`/`lhe1`,
`mp4a`/`mp4v`, `avs3`, `av3a`, `cavs`, `mha1`/`mha2`/`mhm1`/`mhm2`, `uncv`/`unci`, `stpp`) and returns the matching
`mp4a`/`mp4v`, `avs3`/`lav3`, `av3a`, `cavs`, `mha1`/`mha2`/`mhm1`/`mhm2`, `uncv`/`unci`, `stpp`) and returns the matching
info object (`Vp8Info`, `Vp9Info`, `Av1Info`, `H264Info`, `H265Info`, `H266Info`, `LcevcInfo`,
`ApvInfo`, `EvcInfo`, `LhevcInfo`, `Mp4Info`, `Avs3VideoInfo`, `Avs3AudioInfo`, `MpeghInfo`,
`UncvInfo`). Recognised parameterless 4CCs (DTS, VC-1, Opus, FLAC, Vorbis, ALAC, PCM) return a
Expand All @@ -129,7 +129,7 @@ console.log(info.toString()); // 'avc1.640028'
`hAudioObjectType`). Covers the RFC 6381 `mp4a`/`mp4v` ObjectTypeIndication scheme — AAC, MP3,
MPEG-4 Visual, MPEG-2 video/audio and more (`mp4a.40.2`, `mp4a.69`, `mp4v.20.9`, …).
- `avs3` — namespace exporting `Avs3VideoInfo` (`avs3.<profile>.<level>`) and `Avs3AudioInfo`
(`av3a.<codec_id>`) for the AVS3 video/audio standard.
(`av3a.<codec_id>`) for the AVS3 video/audio standard. `lav3` (library track) shares the video format.
- `avs2` — namespace exporting `Avs2AudioInfo` for AVS2 audio (`cavs.<audio_codec_id>`).
- `stpp` — namespace exporting `StppInfo` for TTML / timed-text subtitles
(`stpp[.<mode>[.<profile>]]`, e.g. `stpp.ttml.im1t`), with the TTML profile decoded to a
Expand All @@ -138,7 +138,7 @@ console.log(info.toString()); // 'avc1.640028'
`profileLevelId`, e.g. `mhm1.0c`).
- `simple` — namespace exporting `SimpleCodecInfo` and the `SIMPLE_CODECS` registry for
parameterless 4CCs (DTS `dtsc`/`dtse`/…, `vc-1`, `opus`, `flac`, `vorbis`, `alac`, `wvtt` (WebVTT),
and PCM variants such as `ipcm`/`fpcm`/`twos`/`sowt`).
`tx3g`, `c608`/`c708`, `samr`/`sawb`, `dra1`, and PCM variants such as `ipcm`/`fpcm`/`twos`/`sowt`).
- `uncv` — namespace exporting `UncvInfo` for uncompressed video/images (`uncv`/`unci`), with an
optional profile 4CC (`uncv.rgba`, `uncv.i420`, …) decoded to a pixel-format description.
- Shared ISO/IEC 23001-8:2016 colour enums (`ColourPrimaries`, `TransferCharacteristics`,
Expand Down
7 changes: 7 additions & 0 deletions src/codec/avs3/avs3-video-info.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,17 @@ describe('Avs3VideoInfo', () => {
'avs3.32.50',
'avs3.22.20',
'avs3.ab.cd',
'lav3.20.10',
])('parses and round-trips %s', (str) => {
expect(Avs3VideoInfo.fromString(str).toString()).toBe(str);
});

it('accepts the lav3 library-track sample entry', () => {
const info = Avs3VideoInfo.fromString('lav3.20.10');
expect(info.fourCC).toBe('lav3');
expect(info.codecName).toBe('lav3');
});

it('decodes the fields', () => {
const info = Avs3VideoInfo.fromString('avs3.20.10');
expect(info.fourCC).toBe('avs3');
Expand Down
1 change: 1 addition & 0 deletions src/codec/avs3/avs3-video-info.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export class Avs3VideoInfo extends CodecInfo {
throw new Error(`Invalid AVS3 video sample entry: ${fourCC}`);
}
this._fourCC = fourCC;
this.codecName = fourCC;
}

get profileId(): number {
Expand Down
5 changes: 3 additions & 2 deletions src/codec/avs3/enums.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@
// avs3.<profile_id>.<level_id> (video, hex bytes) e.g. avs3.20.10, avs3.32.50
// av3a.<audio_codec_id> (audio, hex byte) e.g. av3a.00

export type Avs3VideoFourCC = 'avs3';
export const AVS3_VIDEO_FOUR_CCS: readonly Avs3VideoFourCC[] = ['avs3'];
// avs3 = regular video track; lav3 = AVS3 "library track" (same profile/level string).
export type Avs3VideoFourCC = 'avs3' | 'lav3';
export const AVS3_VIDEO_FOUR_CCS: readonly Avs3VideoFourCC[] = ['avs3', 'lav3'];

export type Avs3AudioFourCC = 'av3a';
export const AVS3_AUDIO_FOUR_CCS: readonly Avs3AudioFourCC[] = ['av3a'];
Expand Down
8 changes: 8 additions & 0 deletions src/codec/simple/enums.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,14 @@ export const SIMPLE_CODECS: Readonly<Record<string, string>> = {
'alac': 'Apple Lossless (ALAC)',
// WebVTT subtitles (parameterless; TTML/stpp is handled separately as it carries a profile)
'wvtt': 'WebVTT',
// Other text / caption sample entries
'tx3g': '3GPP Timed Text',
'c608': 'CEA-608 Closed Captions',
'c708': 'CEA-708 Closed Captions',
// 3GPP mobile audio and DRA
'samr': 'AMR (narrow-band)',
'sawb': 'AMR-WB (wide-band)',
'dra1': 'DRA Audio',
// PCM variants
'ipcm': 'Uncompressed PCM',
'fpcm': 'Floating-point PCM',
Expand Down
5 changes: 4 additions & 1 deletion src/codec/simple/simple-codec-info.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ describe('SimpleCodecInfo', () => {
it.each([
'opus', 'flac', 'vorbis', 'alac',
'dtsc', 'dtse', 'dtsh', 'dtsl', 'dtsx', 'dtsy',
'vc-1', 'wvtt',
'vc-1', 'wvtt', 'tx3g', 'c608', 'c708', 'samr', 'sawb', 'dra1',
'twos', 'sowt', 'lpcm', 'ipcm', 'fpcm', 'in24', 'in32', 'fl32', 'fl64',
])('parses and round-trips %s', (str) => {
expect(SimpleCodecInfo.fromString(str).toString()).toBe(str);
Expand Down Expand Up @@ -34,6 +34,9 @@ describe('SimpleCodecInfo', () => {
['twos', 'PCM (big-endian)'],
['sowt', 'PCM (little-endian)'],
['wvtt', 'WebVTT'],
['tx3g', '3GPP Timed Text'],
['samr', 'AMR (narrow-band)'],
['c608', 'CEA-608 Closed Captions'],
])('%s -> %s', (str, name) => {
expect(SimpleCodecInfo.fromString(str).toHumanReadable().codec).toBe(name);
});
Expand Down
11 changes: 9 additions & 2 deletions src/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,11 +79,18 @@ describe('codecInfoFactory', () => {
expect(video.codecName).toBe('mp4v');
});

it('dispatches avs3 strings to Avs3VideoInfo', () => {
it('dispatches avs3 and lav3 strings to Avs3VideoInfo', () => {
const info = codecInfoFactory('avs3.20.10');
expect(info).toBeInstanceOf(avs3.Avs3VideoInfo);
expect(info.codecName).toBe('avs3');
expect((info as avs3.Avs3VideoInfo).profileId).toBe(0x20);
expect(codecInfoFactory('lav3.20.10').codecName).toBe('lav3');
});

it('dispatches tx3g to SimpleCodecInfo', () => {
const info = codecInfoFactory('tx3g');
expect(info).toBeInstanceOf(simple.SimpleCodecInfo);
expect((info as simple.SimpleCodecInfo).toHumanReadable().codec).toBe('3GPP Timed Text');
});

it('dispatches av3a strings to Avs3AudioInfo', () => {
Expand Down Expand Up @@ -139,7 +146,7 @@ describe('codecInfoFactory', () => {

it('throws on an unknown codec', () => {
expect(() => codecInfoFactory('theora')).toThrow('Unknown codec');
expect(() => codecInfoFactory('tx3g')).toThrow('Unknown codec');
expect(() => codecInfoFactory('nope')).toThrow('Unknown codec');
});
});

Expand Down
2 changes: 1 addition & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ export const codecInfoFactory = (codecString: string) => {
if (codecString.startsWith('mp4a') || codecString.startsWith('mp4v')) {
return Mp4Info.fromString(codecString);
}
if (codecString.startsWith('avs3')) {
if (codecString.startsWith('avs3') || codecString.startsWith('lav3')) {
return Avs3VideoInfo.fromString(codecString);
}
if (codecString.startsWith('av3a')) {
Expand Down
Loading