Skip to content

Commit

Permalink
feat(player): dash provider (#1212)
Browse files Browse the repository at this point in the history
  • Loading branch information
Dinesh-Gautam authored Mar 25, 2024
1 parent c2bafe7 commit 000c7a4
Show file tree
Hide file tree
Showing 31 changed files with 1,689 additions and 104 deletions.
9 changes: 6 additions & 3 deletions packages/react/.templates/sandbox/player.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,16 +51,18 @@ export function Player() {
}

function changeSource(type: string) {
const muxPlaybackId = 'VZtzUzGRv02OhRnZCxcNg49OilvolTqdnFLEqBsTwaxU';
switch (type) {
case 'audio':
setSrc('https://media-files.vidstack.io/sprite-fight/audio.mp3');
break;
case 'video':
setSrc(`https://stream.mux.com/${muxPlaybackId}/low.mp4`);
setSrc('https://media-files.vidstack.io/sprite-fight/480p.mp4');
break;
case 'hls':
setSrc(`https://stream.mux.com/${muxPlaybackId}.m3u8`);
setSrc('https://media-files.vidstack.io/sprite-fight/hls/stream.m3u8');
break;
case 'dash':
setSrc('https://media-files.vidstack.io/sprite-fight/dash/stream.mpd');
break;
case 'live':
setSrc('https://stream.mux.com/v69RSHhFelSm4701snP22dYz2jICy4E4FUyk02rW4gxRM.m3u8');
Expand Down Expand Up @@ -108,6 +110,7 @@ export function Player() {
<button onClick={() => changeSource('audio')}>Audio</button>
<button onClick={() => changeSource('video')}>Video</button>
<button onClick={() => changeSource('hls')}>HLS</button>
<button onClick={() => changeSource('dash')}>DASH</button>
<button onClick={() => changeSource('live')}>Live</button>
<button onClick={() => changeSource('youtube')}>YouTube</button>
<button onClick={() => changeSource('vimeo')}>Vimeo</button>
Expand Down
1 change: 1 addition & 0 deletions packages/react/rollup.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ const EXTERNAL_PACKAGES = [
'media-icons',
'media-captions',
'hls.js',
'dashjs',
/^remotion/,
],
NPM_BUNDLES = [defineNPMBundle({ dev: true }), defineNPMBundle({ dev: false })],
Expand Down
1 change: 1 addition & 0 deletions packages/vidstack/.templates/sandbox/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
<button id="hls-src-button">HLS</button>
<button id="live-src-button">Live</button>
<button id="youtube-src-button">YouTube</button>
<button id="dash-src-button">DASH</button>
<button id="vimeo-src-button">Vimeo</button>
</div>
</main>
Expand Down
10 changes: 7 additions & 3 deletions packages/vidstack/.templates/sandbox/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,28 +36,32 @@ const audioSrcButton = document.querySelector('#audio-src-button'),
hlsSrcButton = document.querySelector('#hls-src-button'),
liveSrcButton = document.querySelector('#live-src-button'),
youtubeSrcButton = document.querySelector('#youtube-src-button'),
dashSrcButton = document.querySelector('#dash-src-button'),
vimeoSrcButton = document.querySelector('#vimeo-src-button');

audioSrcButton?.addEventListener('click', () => changeSource('audio'));
videoSrcButton?.addEventListener('click', () => changeSource('video'));
hlsSrcButton?.addEventListener('click', () => changeSource('hls'));
dashSrcButton?.addEventListener('click', () => changeSource('dash'));
liveSrcButton?.addEventListener('click', () => changeSource('live'));
youtubeSrcButton?.addEventListener('click', () => changeSource('youtube'));
vimeoSrcButton?.addEventListener('click', () => changeSource('vimeo'));

changeSource('audio');

function changeSource(type: string) {
const muxPlaybackId = 'VZtzUzGRv02OhRnZCxcNg49OilvolTqdnFLEqBsTwaxU';
switch (type) {
case 'audio':
player.src = 'https://media-files.vidstack.io/sprite-fight/audio.mp3';
break;
case 'video':
player.src = `https://stream.mux.com/${muxPlaybackId}/low.mp4`;
player.src = 'https://media-files.vidstack.io/sprite-fight/480p.mp4';
break;
case 'hls':
player.src = `https://stream.mux.com/${muxPlaybackId}.m3u8`;
player.src = 'https://media-files.vidstack.io/sprite-fight/hls/stream.m3u8';
break;
case 'dash':
player.src = 'https://media-files.vidstack.io/sprite-fight/dash/stream.mpd';
break;
case 'live':
player.src = 'https://stream.mux.com/v69RSHhFelSm4701snP22dYz2jICy4E4FUyk02rW4gxRM.m3u8';
Expand Down
9 changes: 8 additions & 1 deletion packages/vidstack/mangle.json
Original file line number Diff line number Diff line change
Expand Up @@ -845,5 +845,12 @@
"_source": "Jo",
"_watchMetadata": "Mo",
"_createError": "Oo",
"_preventTimeUpdates": "No"
"_preventTimeUpdates": "No",
"_attachTTMLRenderingDiv": "To",
"_dispatchDASHEvent": "So",
"_onManifestLoaded": "Uo",
"_onQualitySwitched": "Vo",
"_removeTTMLRenderingDiv": "Po",
"_switchAutoBitrate": "Ro",
"_textManualRendering": "Qo"
}
1 change: 1 addition & 0 deletions packages/vidstack/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@
"@rollup/plugin-node-resolve": "^15.2.0",
"@types/fscreen": "^1.0.1",
"autoprefixer": "^10.4.2",
"dashjs": "^4.7.4",
"es-module-lexer": "^1.4.0",
"esbuild": "^0.19.4",
"esbuild-minify-templates": "^0.11.0",
Expand Down
3 changes: 2 additions & 1 deletion packages/vidstack/rollup.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ const MODE_WATCH = process.argv.includes('-w'),
/** @type {Record<string, string | false>} */
const MANGLE_CACHE = !MODE_TYPES ? await buildMangleCache() : {};

const NPM_EXTERNAL_PACKAGES = ['hls.js', 'media-captions', 'media-icons'],
const NPM_EXTERNAL_PACKAGES = ['hls.js','dashjs', 'media-captions', 'media-icons'],
CDN_EXTERNAL_PACKAGES = ['media-captions', 'media-icons'],
PLUGINS_EXTERNAL_PACKAGES = ['vite', 'rollup', /webpack/, /rspack/, 'esbuild', 'unplugin'];

Expand Down Expand Up @@ -408,6 +408,7 @@ function getProviderInputs() {
[`providers/vidstack-audio`]: 'src/providers/audio/provider.ts',
[`providers/vidstack-video`]: 'src/providers/video/provider.ts',
[`providers/vidstack-hls`]: 'src/providers/hls/provider.ts',
[`providers/vidstack-dash`]: 'src/providers/dash/provider.ts',
[`providers/vidstack-youtube`]: 'src/providers/youtube/provider.ts',
[`providers/vidstack-vimeo`]: 'src/providers/vimeo/provider.ts',
[`providers/vidstack-google-cast`]: 'src/providers/google-cast/provider.ts',
Expand Down
24 changes: 19 additions & 5 deletions packages/vidstack/src/components/provider/source-select.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,12 @@ import {
YouTubeProviderLoader,
type MediaProviderLoader,
} from '../../providers';
import { resolveStreamTypeFromHLSManifest } from '../../utils/hls';
import { isHLSSrc } from '../../utils/mime';
import { DASHProviderLoader } from '../../providers/dash/loader';
import {
resolveStreamTypeFromDASHManifest,
resolveStreamTypeFromHLSManifest,
} from '../../utils/manifest';
import { isDASHSrc, isHLSSrc } from '../../utils/mime';
import { getRequestCredentials, preconnect } from '../../utils/network';
import { isHLSSupported } from '../../utils/support';

Expand All @@ -41,7 +45,8 @@ export class SourceSelection {
private _loader: WriteSignal<MediaProviderLoader | null>,
customLoaders: MediaProviderLoader[] = [],
) {
const HLS_LOADER = new HLSProviderLoader(),
const DASH_LOADER = new DASHProviderLoader(),
HLS_LOADER = new HLSProviderLoader(),
VIDEO_LOADER = new VideoProviderLoader(),
AUDIO_LOADER = new AudioProviderLoader(),
YOUTUBE_LOADER = new YouTubeProviderLoader(),
Expand All @@ -52,8 +57,8 @@ export class SourceSelection {
const remoteLoader = _media.$state.remotePlaybackLoader();

const loaders = _media.$props.preferNativeHLS()
? [VIDEO_LOADER, AUDIO_LOADER, HLS_LOADER, ...EMBED_LOADERS, ...customLoaders]
: [HLS_LOADER, VIDEO_LOADER, AUDIO_LOADER, ...EMBED_LOADERS, ...customLoaders];
? [VIDEO_LOADER, AUDIO_LOADER, DASH_LOADER, HLS_LOADER, ...EMBED_LOADERS, ...customLoaders]
: [HLS_LOADER, VIDEO_LOADER, AUDIO_LOADER, DASH_LOADER, ...EMBED_LOADERS, ...customLoaders];

return remoteLoader ? [remoteLoader, ...loaders] : loaders;
});
Expand Down Expand Up @@ -254,6 +259,15 @@ export class SourceSelection {
})
.catch(noop);
}
} else if (isDASHSrc(source)) {
resolveStreamTypeFromDASHManifest(source.src as string, {
credentials: getRequestCredentials(crossOrigin),
signal: abort.signal,
})
.then((streamType) => {
this._notify('stream-type-change', streamType);
})
.catch(noop);
} else {
this._notify('stream-type-change', 'on-demand');
}
Expand Down
20 changes: 11 additions & 9 deletions packages/vidstack/src/core/api/player-events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,17 @@ import type { HLSProviderEvents } from '../../providers/hls/events';
import type { VideoPresentationEvents } from '../../providers/video/presentation/events';
import type { MediaEvents } from './media-events';
import type { MediaRequestEvents } from './media-request-events';
import type { DashProviderEvents } from '../../providers/dash/events';

export interface MediaPlayerEvents
extends MediaEvents,
MediaRequestEvents,
MediaUserEvents,
LoggerEvents,
VideoPresentationEvents,
HLSProviderEvents,
GoogleCastEvents {
MediaRequestEvents,
MediaUserEvents,
LoggerEvents,
VideoPresentationEvents,
HLSProviderEvents,
DashProviderEvents,
GoogleCastEvents {
'media-player-connect': MediaPlayerConnectEvent;
/** @internal */
'find-media-player': FindMediaPlayerEvent;
Expand All @@ -30,7 +32,7 @@ export interface MediaPlayerEvents
* @composed
* @detail player
*/
export interface MediaPlayerConnectEvent extends DOMEvent<MediaPlayer> {}
export interface MediaPlayerConnectEvent extends DOMEvent<MediaPlayer> { }

export interface FindMediaPlayerEventDetail {
(player: MediaPlayer | null): void;
Expand All @@ -42,6 +44,6 @@ export interface FindMediaPlayerEventDetail {
* @composed
* @detail callback
*/
export interface FindMediaPlayerEvent extends DOMEvent<FindMediaPlayerEventDetail> {}
export interface FindMediaPlayerEvent extends DOMEvent<FindMediaPlayerEventDetail> { }

export interface MediaUserEvents {}
export interface MediaUserEvents { }
8 changes: 0 additions & 8 deletions packages/vidstack/src/core/quality/video-quality.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,14 +59,6 @@ export class VideoQualityList extends SelectList<VideoQuality, VideoQualityListE
this[QualitySymbol._setAuto](true, trigger);
}

indexOf(quality: VideoQuality) {
return this._items.indexOf(quality);
}

getById(id: string) {
return this._items.find((quality) => quality.id === id);
}

getBySrc(src: unknown) {
return this._items.find((quality) => quality.src === src);
}
Expand Down
11 changes: 1 addition & 10 deletions packages/vidstack/src/core/tracks/audio-tracks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,7 @@ import { SelectList, type SelectListItem } from '../../foundation/list/select-li
/**
* @see {@link https://vidstack.io/docs/player/core-concepts/audio-tracks}
*/
export class AudioTrackList extends SelectList<AudioTrack, AudioTrackListEvents> {
getById(id: string): AudioTrack | null {
if (id === '') return null;
return this._items.find((track) => track.id === id) ?? null;
}

indexOf(track: AudioTrack) {
return this._items.indexOf(track);
}
}
export class AudioTrackList extends SelectList<AudioTrack, AudioTrackListEvents> {}

/**
* @see {@link https://vidstack.io/docs/player/core-concepts/audio-tracks}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ export class NativeTextRenderer implements TextRenderer {
const el = (track[TextTrackSymbol._native] ??= this._createTrackElement(track));
if (isHTMLElement(el)) {
this._video.append(el);
el.track.mode = el.default ? 'showing' : 'hidden';
el.track.mode = el.default ? 'showing' : 'disabled';
}
}

Expand Down Expand Up @@ -89,16 +89,17 @@ export class NativeTextRenderer implements TextRenderer {

private _onChange(event?: Event) {
for (const track of this._tracks) {
const nativeTrack = track[TextTrackSymbol._native]?.track;
if (!nativeTrack) continue;
const native = track[TextTrackSymbol._native];

if (!native) continue;

if (!this._display) {
nativeTrack.mode = 'disabled';
native.track.mode = native.managed ? 'hidden' : 'disabled';
continue;
}

const isShowing = nativeTrack.mode === 'showing';
if (isShowing) this._copyCues(track, nativeTrack);
const isShowing = native.track.mode === 'showing';
if (isShowing) this._copyCues(track, native.track);
track.setMode(isShowing ? 'showing' : 'disabled', event);
}
}
Expand Down
Loading

0 comments on commit 000c7a4

Please sign in to comment.