UNPKG

@playkit-js/playkit-js-dash

Version:

[![Build Status](https://github.com/kaltura/playkit-js-dash/actions/workflows/run_canary_full_flow.yaml/badge.svg)](https://github.com/kaltura/playkit-js-dash/actions/workflows/run_canary_full_flow.yaml) [![code style: prettier](https://img.shields.io/bad

111 lines (98 loc) 4.11 kB
import {AdaptationSet} from './parser/adaptation-set'; import {Representation} from './parser/representation'; import {UrlUtils} from './parser/parser-utils'; import {ImageTrack, ThumbnailInfo} from '@playkit-js/playkit-js'; import {EssentialProperty} from './parser/essential-property'; class DashThumbnailController { private _tracks: Array<ImageTrack> = []; constructor(set: AdaptationSet, playerUrl: string, mediaTemplatePrefix: string) { this._parseTracks(set, playerUrl, mediaTemplatePrefix); if (this._tracks.length > 0) { this._tracks.sort((t1: ImageTrack, t2: ImageTrack) => t1.customData.bitrate - t2.customData.bitrate); this.selectTrack(this._tracks[this._tracks.length - 1]); } } public selectTrack(track: ImageTrack): void { this._tracks.forEach((t: ImageTrack) => (t.index === track.index ? (t.active = true) : (t.active = false))); } public getTracks(): Array<ImageTrack> { return this._tracks; } public getActiveTrack(): ImageTrack { return this._tracks.find((t: ImageTrack) => t.active)!; } public getThumbnail(time: number): ThumbnailInfo { const activeTrack = this.getActiveTrack(); const {duration, rows, cols, sliceWidth, sliceHeight, customData} = activeTrack; const page = Math.floor(time / duration) + customData.startNumber; const offset = time % duration; const thumbIndex = Math.floor((offset * rows * cols) / duration); return new ThumbnailInfo({ width: Math.floor(sliceWidth), height: Math.floor(sliceHeight), x: Math.floor(thumbIndex % cols) * sliceWidth, y: Math.floor(thumbIndex / cols) * sliceHeight, url: this._buildUrlFromTemplate(activeTrack, page) }); } private _parseTracks = (set: AdaptationSet, playerUrl: string, mediaTemplatePrefix: string): void => { const {representations, segmentTemplate, essentialProperty} = set; representations.forEach((representation: Representation, index: number) => { const {id, bandwidth, width, height} = representation; const {startNumber, duration, media, timescale, presentationTimeOffset} = segmentTemplate!; const value = this._getEssentialValue(essentialProperty, representation); const [rows, cols] = this._getDimensions(value); this._tracks.push( new ImageTrack({ id, index, active: false, width, height, duration, rows, cols, url: this._buildTemplateUrl(media, id, playerUrl, mediaTemplatePrefix), customData: { bitrate: bandwidth, startNumber, timescale, presentationTimeOffset } }) ); }); }; private _getDimensions = (value: string): Array<number> => { let rows = 1, cols = 1; if (value.includes('x')) { const values = value.split('x'); cols = parseInt(values[0]); rows = parseInt(values[1]); } return [rows, cols]; }; private _getEssentialValue = (essentialProperty: EssentialProperty | undefined, representation: Representation): string => { return essentialProperty ? essentialProperty.value : representation.essentialProperty ? representation.essentialProperty.value : ''; }; private _buildTemplateUrl = (mediaTemplate: string, id: string, url: string, mediaTemplatePrefix: string): string => { const last = url.split('/').pop()!; const baseUrl = url.replace(last, ''); const regex = /^\.\//; mediaTemplatePrefix = mediaTemplatePrefix.replace(regex, ''); if (mediaTemplatePrefix.length > 0 && !mediaTemplatePrefix.endsWith('/')) { mediaTemplatePrefix += '/'; } const urlTemplate = `${baseUrl}${mediaTemplatePrefix}${mediaTemplate}`; return UrlUtils.resolve(urlTemplate, {id}); }; private _buildUrlFromTemplate = (track: ImageTrack, index: number): string => { return UrlUtils.resolve(track.url, { index, time: (index - 1) * track.duration * track.customData.timescale, bitrate: track.customData.bitrate }); }; } export {DashThumbnailController};