Skip to content

Commit

Permalink
Merge pull request #6006 from video-dev/feature/is-supported-codec-ex…
Browse files Browse the repository at this point in the history
…pansion

Expand isSupported check to allow alternative codecs
  • Loading branch information
robwalch committed Dec 5, 2023
2 parents f53fed3 + df759ae commit fad22f2
Show file tree
Hide file tree
Showing 5 changed files with 61 additions and 18 deletions.
2 changes: 2 additions & 0 deletions api-extractor/report/hls.js.api.md
Expand Up @@ -1592,6 +1592,8 @@ class Hls implements HlsEventEmitter {
// Warning: (ae-setter-with-docs) The doc comment for the property "firstLevel" must appear on the getter, not the setter.
set firstLevel(newLevel: number);
get forceStartLoad(): boolean;
static getMediaSource(): typeof MediaSource | undefined;
static isMSESupported(): boolean;
static isSupported(): boolean;
get latency(): number;
// (undocumented)
Expand Down
15 changes: 13 additions & 2 deletions docs/API.md
Expand Up @@ -191,17 +191,28 @@ First include `https://cdn.jsdelivr.net/npm/hls.js@1` (or `/hls.js` for unminifi
<script src="//cdn.jsdelivr.net/npm/hls.js@1"></script>
```

Invoke the following static method: `Hls.isSupported()` to check whether your browser is supporting [MediaSource Extensions](http://w3c.github.io/media-source/).
Invoke the following static method: `Hls.isSupported()` to check whether your browser supports [MediaSource Extensions](http://w3c.github.io/media-source/) with any baseline codecs.

```html
<script src="https://cdn.jsdelivr.net/npm/hls.js@1"></script>
<script>
if (Hls.isSupported()) {
console.log('hello hls.js!');
console.log('Hello HLS.js!');
}
</script>
```

If you want to test for MSE support without testing for baseline codecs, use `isMSESupported`:

```js
if (
Hls.isMSESupported() &&
Hls.getMediaSource().isTypeSupported('video/mp4;codecs="av01.0.01M.08"')
) {
console.log('Hello AV1 playback! AVC who?');
}
```

### Second step: instantiate Hls object and bind it to `<video>` element

Let's
Expand Down
2 changes: 2 additions & 0 deletions src/exports-named.ts
Expand Up @@ -55,3 +55,5 @@ export {
ErrorActionFlags,
} from './controller/error-controller';
export { AttrList } from './utils/attr-list';
export { isSupported, isMSESupported } from './is-supported';
export { getMediaSource } from './utils/mediasource-helper';
17 changes: 16 additions & 1 deletion src/hls.ts
Expand Up @@ -6,7 +6,8 @@ import LevelController from './controller/level-controller';
import { FragmentTracker } from './controller/fragment-tracker';
import KeyLoader from './loader/key-loader';
import StreamController from './controller/stream-controller';
import { isSupported } from './is-supported';
import { isMSESupported, isSupported } from './is-supported';
import { getMediaSource } from './utils/mediasource-helper';
import { logger, enableLogs } from './utils/logger';
import { enableStreamingMode, hlsDefaultConfig, mergeConfig } from './config';
import { EventEmitter } from 'eventemitter3';
Expand Down Expand Up @@ -88,10 +89,24 @@ export default class Hls implements HlsEventEmitter {
/**
* Check if the required MediaSource Extensions are available.
*/
static isMSESupported(): boolean {
return isMSESupported();
}

/**
* Check if MediaSource Extensions are available and isTypeSupported checks pass for any baseline codecs.
*/
static isSupported(): boolean {
return isSupported();
}

/**
* Get the MediaSource global used for MSE playback (ManagedMediaSource, MediaSource, or WebKitMediaSource).
*/
static getMediaSource(): typeof MediaSource | undefined {
return getMediaSource();
}

static get Events(): typeof Events {
return Events;
}
Expand Down
43 changes: 28 additions & 15 deletions src/is-supported.ts
@@ -1,37 +1,50 @@
import { getMediaSource } from './utils/mediasource-helper';
import { mimeTypeForCodec } from './utils/codecs';
import type { ExtendedSourceBuffer } from './types/buffer';

function getSourceBuffer(): typeof self.SourceBuffer {
return self.SourceBuffer || (self as any).WebKitSourceBuffer;
}

/**
* @ignore
*/
export function isSupported(): boolean {
export function isMSESupported(): boolean {
const mediaSource = getMediaSource();
if (!mediaSource) {
return false;
}
const sourceBuffer = getSourceBuffer();
const isTypeSupported =
mediaSource &&
typeof mediaSource.isTypeSupported === 'function' &&
mediaSource.isTypeSupported('video/mp4; codecs="avc1.42E01E,mp4a.40.2"');

// if SourceBuffer is exposed ensure its API is valid
// Older browsers do not expose SourceBuffer globally so checking SourceBuffer.prototype is impossible
const sourceBufferValidAPI =
const sourceBuffer = getSourceBuffer();
return (
!sourceBuffer ||
(sourceBuffer.prototype &&
typeof sourceBuffer.prototype.appendBuffer === 'function' &&
typeof sourceBuffer.prototype.remove === 'function');
return !!isTypeSupported && !!sourceBufferValidAPI;
typeof sourceBuffer.prototype.remove === 'function')
);
}

export function isSupported(): boolean {
if (!isMSESupported()) {
return false;
}

const mediaSource = getMediaSource();
return (
typeof mediaSource?.isTypeSupported === 'function' &&
(['avc1.42E01E,mp4a.40.2', 'av01.0.01M.08', 'vp09.00.50.08'].some(
(codecsForVideoContainer) =>
mediaSource.isTypeSupported(
mimeTypeForCodec(codecsForVideoContainer, 'video'),
),
) ||
['mp4a.40.2', 'fLaC'].some((codecForAudioContainer) =>
mediaSource.isTypeSupported(
mimeTypeForCodec(codecForAudioContainer, 'audio'),
),
))
);
}

/**
* @ignore
*/
export function changeTypeSupported(): boolean {
const sourceBuffer = getSourceBuffer();
return (
Expand Down

0 comments on commit fad22f2

Please sign in to comment.