Skip to content

Commit

Permalink
DVB Font Downloads (#4338)
Browse files Browse the repository at this point in the history
* Initial dvb font download work

* Continued dvb font download functionality

* Seperate DVBFontUtils and TTML prefixing

* Essential Property descriptors working and refactor DVB font handling

* Ensure fonts are removed and handled with essential property descriptors, tidy up

* Comment tidy up

* Clean up and function commenting

* Team feedback corrections

* Non dvbFonts unit tests

* Add DVBFonts unit tests

* Update types

* Update BSD-3 header in accordance with contributor guide

* Remove font prefixing functionality

* Remove references to prefixing fontFamilies in TTMLParser

* Move events from CoreEvents to MediaPlayerEvents

* Address PR comments on DashAdapter, DashManifestModel and TextSourceBuffer

* Address PR comments for DVBFonts

* Missing semicolon removal

* Add DVB Font Download test streams to reference player

* Use camelCase for DescriptorType dvb extensions

* Handle disabled tracks correctly in the reference player controlbar

* Fix controlbar text track and native track matching

* Fix issue with disabled track cues

* Add DVB font download test streams to functional tests

* Update imscJS version and remove now unneeded fix
  • Loading branch information
mattjuggins committed Jan 22, 2024
1 parent 49257d9 commit 37c68da
Show file tree
Hide file tree
Showing 31 changed files with 1,064 additions and 81 deletions.
81 changes: 75 additions & 6 deletions contrib/akamai/controlbar/ControlBar.js
Expand Up @@ -65,6 +65,7 @@ var ControlBar = function (dashjsMediaPlayer, displayUTCTimeCodes) {
seekbarPlay,
seekbarBuffer,
muteBtn,
nativeTextTracks,
volumebar,
fullscreenBtn,
timeDisplay,
Expand Down Expand Up @@ -595,6 +596,34 @@ var ControlBar = function (dashjsMediaPlayer, displayUTCTimeCodes) {
}
};

// Match up the current dashjs text tracks against native video element tracks by ensuring they have matching properties
var _matchTrackWithNativeTrack = function(track, nativeTrack) {
let label = track.id !== undefined ? track.id.toString() : track.lang;

return !!(
(track.kind === nativeTrack.kind) &&
(track.lang === nativeTrack.language) &&
(track.isTTML === nativeTrack.isTTML) &&
(track.isEmbedded === nativeTrack.isEmbedded) &&
(label === nativeTrack.label)
);
}

// Compare track information against native video element tracks to get the current track mode
var _getNativeVideoTrackMode = function (track) {
const nativeTracks = video.textTracks;
let trackMode;
for (let i = 0; i < nativeTracks.length; i++) {
const nativeTrack = nativeTracks[i];
if (_matchTrackWithNativeTrack(track, nativeTrack)) {
trackMode = nativeTrack.mode;
break;
}
};

return (trackMode === undefined) ? 'showing' : trackMode;
};

var createCaptionSwitchMenu = function (streamId) {
// Subtitles/Captions Menu //XXX we need to add two layers for captions & subtitles if present.
var activeStreamInfo = player.getActiveStream().getStreamInfo();
Expand All @@ -607,15 +636,24 @@ var ControlBar = function (dashjsMediaPlayer, displayUTCTimeCodes) {
var tracks = textTrackList[streamId] || [];
var contentFunc = function (element, index) {
if (isNaN(index)) {
return 'OFF';
return {
mode: 'showing',
text: 'OFF'
};
}

var label = getLabelForLocale(element.labels);
var trackText;
if (label) {
return label + ' : ' + element.type;
trackText = label + ' : ' + element.type;
} else {
trackText = element.lang + ' : ' + element.kind;
}

return element.lang + ' : ' + element.kind;
return {
mode: _getNativeVideoTrackMode(element),
text: trackText
}
};
captionMenu = createMenu({ menuType: 'caption', arr: tracks }, contentFunc);

Expand All @@ -630,13 +668,22 @@ var ControlBar = function (dashjsMediaPlayer, displayUTCTimeCodes) {

};

var _onTracksChanged = function () {
var activeStreamInfo = player.getActiveStream().getStreamInfo();
createCaptionSwitchMenu(activeStreamInfo.id);
}

var _onTracksAdded = function (e) {
// Subtitles/Captions Menu //XXX we need to add two layers for captions & subtitles if present.
if (!textTrackList[e.streamId]) {
textTrackList[e.streamId] = [];
}

textTrackList[e.streamId] = textTrackList[e.streamId].concat(e.tracks);

nativeTextTracks = video.textTracks;
nativeTextTracks.addEventListener('change', _onTracksChanged);

createCaptionSwitchMenu(e.streamId);
};

Expand Down Expand Up @@ -783,8 +830,15 @@ var ControlBar = function (dashjsMediaPlayer, displayUTCTimeCodes) {
item.mediaType = mediaType;
item.name = name;
item.selected = false;
item.textContent = arr[i];

if (isObject(arr[i])) {
// text tracks need extra properties
item.mode = arr[i].mode;
item.textContent = arr[i].text;
} else {
// Other tracks will just have their text
item.textContent = arr[i];
}

item.onmouseover = function (/*e*/) {
if (this.selected !== true) {
this.classList.add('menu-item-over');
Expand All @@ -802,7 +856,13 @@ var ControlBar = function (dashjsMediaPlayer, displayUTCTimeCodes) {
el = menu.querySelector('.' + mediaType + '-menu-content');
}

el.appendChild(item);
if (mediaType === 'caption') {
if (item.mode !== 'disabled') {
el.appendChild(item);
}
} else {
el.appendChild(item);
}
}

return menu;
Expand Down Expand Up @@ -952,6 +1012,14 @@ var ControlBar = function (dashjsMediaPlayer, displayUTCTimeCodes) {
return !!navigator.userAgent.match(/Trident.*rv[ :]*11\./);
};

//************************************************************************************
//Utilities
//************************************************************************************

var isObject = function (obj) {
return typeof obj === 'object' && !Array.isArray(obj) && obj !== null;
}

//************************************************************************************
// PUBLIC API
//************************************************************************************
Expand Down Expand Up @@ -1035,6 +1103,7 @@ var ControlBar = function (dashjsMediaPlayer, displayUTCTimeCodes) {
}
if (menuHandlersList.caption) {
captionBtn.removeEventListener('click', menuHandlersList.caption);
nativeTextTracks.removeEventListener('change', _onTracksChanged);
}
if (captionMenu) {
this.removeMenu(captionMenu, captionBtn);
Expand Down
70 changes: 65 additions & 5 deletions index.d.ts
Expand Up @@ -216,6 +216,10 @@ declare namespace dashjs {

getSelectionPriority(realAdaptation: object): number;

getEssentialPropertiesForAdaptation(adaptation: object): object;

getEssentialPropertiesAsArrayForAdaptation(adaptation: object): any[];

getEssentialPropertiesForRepresentation(realRepresentation: object): {schemeIdUri: string, value: string}

getRepresentationFor(index: number, adaptation: object): object;
Expand Down Expand Up @@ -254,9 +258,19 @@ declare namespace dashjs {

getServiceDescriptions(manifest: object): serviceDescriptions;

getSupplementalProperties(adaptation: object): object;
getSegmentAlignment(adaptation: object): boolean;

getSubSegmentAlignment(adaptation: object): boolean;

getSupplementalPropertiesForAdaptation(adaptation: object): object;

getSupplementalPropertiesAsArrayForAdaptation(adaptation: object): any[];

getSupplementalPropertiesForRepresentation(representation: Representation): object;

getSupplementalPropertiesAsArrayForRepresentation(representation: Representation): any[];

setConfig(config: object): void;
}

export interface PatchManifestModel {
Expand Down Expand Up @@ -472,6 +486,9 @@ declare namespace dashjs {
isEmbedded: any | null;
selectionPriority: number;
supplementalProperties: object;
supplementalPropertiesAsArray: any[];
essentialProperties: object;
essentialPropertiesAsArray: any[];
segmentAlignment: boolean;
subSegmentAlignment: boolean;
}
Expand Down Expand Up @@ -582,6 +599,9 @@ declare namespace dashjs {
schemeIdUri: string;
value: string;
id: string;
dvbUrl?: string;
dvbMimeType?: string;
dvbFontFamily?: string;
}

export class ContentSteeringResponse {
Expand Down Expand Up @@ -1512,7 +1532,10 @@ declare namespace dashjs {
CAN_PLAY_THROUGH: 'canPlayThrough';
CAPTION_RENDERED: 'captionRendered';
CAPTION_CONTAINER_RESIZE: 'captionContainerResize';
CONFORMANCE_VIOLATION: 'conformanceViolation'
CONFORMANCE_VIOLATION: 'conformanceViolation';
DVB_FONT_DOWNLOAD_ADDED: 'dvbFontDownloadAdded';
DVB_FONT_DOWNLOAD_COMPLETE: 'dvbFontDownloadComplete';
DVB_FONT_DOWNLOAD_FAILED: 'dvbFontDownloadFailed';
DYNAMIC_TO_STATIC: 'dynamicToStatic';
ERROR: 'error';
EVENT_MODE_ON_RECEIVE: 'eventModeOnReceive';
Expand Down Expand Up @@ -1722,6 +1745,20 @@ declare namespace dashjs {
type: MediaPlayerEvents['CAPTION_CONTAINER_RESIZE'];
}

export interface dvbFontDownloadAdded extends Event {
type: MediaPlayerEvents['DVB_FONT_DOWNLOAD_ADDED'];
font: FontInfo;
}

export interface dvbFontDownloadComplete extends Event {
type: MediaPlayerEvents['DVB_FONT_DOWNLOAD_COMPLETE'];
font: FontInfo;
}

export interface dvbFontDownloadFailed extends Event {
type: MediaPlayerEvents['DVB_FONT_DOWNLOAD_FAILED'];
font: FontInfo;
}
export interface DynamicToStaticEvent extends Event {
type: MediaPlayerEvents['DYNAMIC_TO_STATIC'];
}
Expand Down Expand Up @@ -3504,7 +3541,32 @@ declare namespace dashjs {
* Streaming - Text
**/

export type TextTrackType = 'subtitles' | 'caption' | 'descriptions' | 'chapters' | 'metadata';
export type TextTrackType = 'subtitles' | 'caption' | 'descriptions' | 'chapters' | 'metadata';

export type FontDownloadStatus = 'unloaded' | 'loaded' | 'error';

export interface FontInfo {
fontFamily: string;
url: string;
mimeType: string;
trackId: number;
streamId: string;
isEssential: boolean;
status: FontDownloadStatus;
fontFace: FontFace;
}

export interface DVBFonts {
addFontsFromTracks(tracks: TextTrackInfo, streamId: string): void;

downloadFonts(): void;

getFonts(): FontInfo[];

getFontsForTrackId(trackId: number): FontInfo[];

reset(): void;
}

export interface EmbeddedTextHtmlRender {
createHTMLCaptionsFromScreen(videoElement: HTMLVideoElement, startTime: number, endTime: number, captionScreen: any): any[];
Expand Down Expand Up @@ -3644,8 +3706,6 @@ declare namespace dashjs {
deleteCuesFromTrackIdx(trackIdx: number, start: number, end: number): void;

deleteAllTextTracks(): void;

deleteTextTrack(idx: number): void;
}

/**
Expand Down

0 comments on commit 37c68da

Please sign in to comment.