@tianfeng98/hls.js
Version:
HLS.js is a JavaScript library that supports playing MPEG-TS and HEVC encoded HLS streams in browsers with support for MSE.
188 lines (171 loc) • 4.33 kB
text/typescript
import { getMediaSource } from './mediasource-helper';
// from http://mp4ra.org/codecs.html
// values indicate codec selection preference (lower is higher priority)
const sampleEntryCodesISO = {
audio: {
a3ds: 1,
'ac-3': 0.95,
'ac-4': 1,
alac: 0.9,
alaw: 1,
dra1: 1,
'dts+': 1,
'dts-': 1,
dtsc: 1,
dtse: 1,
dtsh: 1,
'ec-3': 0.9,
enca: 1,
fLaC: 0.9, // MP4-RA listed codec entry for FLAC
flac: 0.9, // legacy browser codec name for FLAC
FLAC: 0.9, // some manifests may list "FLAC" with Apple's tools
g719: 1,
g726: 1,
m4ae: 1,
mha1: 1,
mha2: 1,
mhm1: 1,
mhm2: 1,
mlpa: 1,
mp4a: 1,
'raw ': 1,
Opus: 1,
opus: 1, // browsers expect this to be lowercase despite MP4RA says 'Opus'
samr: 1,
sawb: 1,
sawp: 1,
sevc: 1,
sqcp: 1,
ssmv: 1,
twos: 1,
ulaw: 1,
},
video: {
avc1: 1,
avc2: 1,
avc3: 1,
avc4: 1,
avcp: 1,
av01: 0.8,
drac: 1,
dva1: 1,
dvav: 1,
dvh1: 0.7,
dvhe: 0.7,
encv: 1,
hev1: 0.75,
hvc1: 0.75,
mjp2: 1,
mp4v: 1,
mvc1: 1,
mvc2: 1,
mvc3: 1,
mvc4: 1,
resv: 1,
rv60: 1,
s263: 1,
svc1: 1,
svc2: 1,
'vc-1': 1,
vp08: 1,
vp09: 0.9,
},
text: {
stpp: 1,
wvtt: 1,
},
} as const;
export type CodecType = 'audio' | 'video';
export function isCodecType(codec: string, type: CodecType): boolean {
const typeCodes = sampleEntryCodesISO[type];
return !!typeCodes && !!typeCodes[codec.slice(0, 4)];
}
export function areCodecsMediaSourceSupported(
codecs: string,
type: CodecType,
preferManagedMediaSource = true,
): boolean {
return !codecs
.split(',')
.some(
(codec) =>
!isCodecMediaSourceSupported(codec, type, preferManagedMediaSource),
);
}
function isCodecMediaSourceSupported(
codec: string,
type: CodecType,
preferManagedMediaSource = true,
): boolean {
const MediaSource = getMediaSource(preferManagedMediaSource);
return MediaSource?.isTypeSupported(mimeTypeForCodec(codec, type)) ?? false;
}
export function mimeTypeForCodec(codec: string, type: CodecType): string {
return `${type}/mp4;codecs="${codec}"`;
}
export function codecsSetSelectionPreferenceValue(codecSet: string): number {
return codecSet.split(',').reduce((num, fourCC) => {
const preferenceValue = sampleEntryCodesISO.video[fourCC];
if (preferenceValue) {
return (preferenceValue * 2 + num) / (num ? 3 : 2);
}
return (sampleEntryCodesISO.audio[fourCC] + num) / (num ? 2 : 1);
}, 0);
}
interface CodecNameCache {
flac?: string;
opus?: string;
}
const CODEC_COMPATIBLE_NAMES: CodecNameCache = {};
type LowerCaseCodecType = 'flac' | 'opus';
function getCodecCompatibleNameLower(
lowerCaseCodec: LowerCaseCodecType,
preferManagedMediaSource = true,
): string {
if (CODEC_COMPATIBLE_NAMES[lowerCaseCodec]) {
return CODEC_COMPATIBLE_NAMES[lowerCaseCodec]!;
}
// Idealy fLaC and Opus would be first (spec-compliant) but
// some browsers will report that fLaC is supported then fail.
// see: https://bugs.chromium.org/p/chromium/issues/detail?id=1422728
const codecsToCheck = {
flac: ['flac', 'fLaC', 'FLAC'],
opus: ['opus', 'Opus'],
}[lowerCaseCodec];
for (let i = 0; i < codecsToCheck.length; i++) {
if (
isCodecMediaSourceSupported(
codecsToCheck[i],
'audio',
preferManagedMediaSource,
)
) {
CODEC_COMPATIBLE_NAMES[lowerCaseCodec] = codecsToCheck[i];
return codecsToCheck[i];
}
}
return lowerCaseCodec;
}
const AUDIO_CODEC_REGEXP = /flac|opus/i;
export function getCodecCompatibleName(
codec: string,
preferManagedMediaSource = true,
): string {
return codec.replace(AUDIO_CODEC_REGEXP, (m) =>
getCodecCompatibleNameLower(
m.toLowerCase() as LowerCaseCodecType,
preferManagedMediaSource,
),
);
}
export function pickMostCompleteCodecName(
parsedCodec: string,
levelCodec: string | undefined,
): string | undefined {
// Parsing of mp4a codecs strings in mp4-tools from media is incomplete as of d8c6c7a
// so use level codec is parsed codec is unavailable or incomplete
if (parsedCodec && parsedCodec !== 'mp4a') {
return parsedCodec;
}
return levelCodec;
}