Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DVB Font Downloads #4338

Merged
Merged
Show file tree
Hide file tree
Changes from 27 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
b072cd8
Initial dvb font download work
mattjuggins Dec 13, 2023
73b94b1
Continued dvb font download functionality
mattjuggins Dec 14, 2023
6595f05
Seperate DVBFontUtils and TTML prefixing
mattjuggins Dec 18, 2023
bda2328
Essential Property descriptors working and refactor DVB font handling
mattjuggins Dec 19, 2023
7fe0967
Ensure fonts are removed and handled with essential property descript…
mattjuggins Dec 20, 2023
9754efd
Comment tidy up
mattjuggins Dec 21, 2023
4a11c52
Merge branch 'development' into dvb-font-download
mattjuggins Dec 21, 2023
d15e1bf
Clean up and function commenting
mattjuggins Dec 21, 2023
71c8d9c
Team feedback corrections
mattjuggins Dec 22, 2023
3bad472
Non dvbFonts unit tests
Jan 4, 2024
313a4ee
Merge branch 'dvb-font-download' of https://github.com/mattjuggins/da…
mattjuggins Jan 4, 2024
7c457a4
Add DVBFonts unit tests
mattjuggins Jan 5, 2024
e42ed8e
Update types
mattjuggins Jan 5, 2024
d90e2b3
Update BSD-3 header in accordance with contributor guide
mattjuggins Jan 8, 2024
97a662b
Remove font prefixing functionality
mattjuggins Jan 8, 2024
2555830
Merge branch 'development' into dvb-font-download
mattjuggins Jan 8, 2024
37b877f
Remove references to prefixing fontFamilies in TTMLParser
mattjuggins Jan 8, 2024
2ee0deb
Merge branch 'development' into dvb-font-download
dsilhavy Jan 10, 2024
f0bc9a2
Move events from CoreEvents to MediaPlayerEvents
mattjuggins Jan 12, 2024
7d68cee
Address PR comments on DashAdapter, DashManifestModel and TextSourceB…
mattjuggins Jan 12, 2024
839a57f
Address PR comments for DVBFonts
mattjuggins Jan 12, 2024
e97e8f5
Missing semicolon removal
mattjuggins Jan 12, 2024
07df70e
Add DVB Font Download test streams to reference player
mattjuggins Jan 12, 2024
ccc09e3
Merge branch 'development' into dvb-font-download
dsilhavy Jan 16, 2024
eecb7d0
Use camelCase for DescriptorType dvb extensions
mattjuggins Jan 16, 2024
9e19434
Handle disabled tracks correctly in the reference player controlbar
mattjuggins Jan 16, 2024
e7eb834
Merge branch 'development' into dvb-font-download
dsilhavy Jan 18, 2024
c6b527b
Fix controlbar text track and native track matching
mattjuggins Jan 18, 2024
8fb343c
Fix issue with disabled track cues
mattjuggins Jan 18, 2024
762ce16
Add DVB font download test streams to functional tests
mattjuggins Jan 18, 2024
9374959
Update imscJS version and remove now unneeded fix
mattjuggins Jan 20, 2024
668d75d
Merge branch 'development' into dvb-font-download
mattjuggins Jan 20, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 61 additions & 6 deletions contrib/akamai/controlbar/ControlBar.js
Original file line number Diff line number Diff line change
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,20 @@ var ControlBar = function (dashjsMediaPlayer, displayUTCTimeCodes) {
}
};

var _getNativeVideoTrackMode = function (element) {
const videoTracks = video.textTracks;
let trackMode;
for (let i = 0; i < videoTracks.length; i++) {
const track = videoTracks[i];
if (track.label === element.id.toString() || track.label === element.lang) {
trackMode = track.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 +622,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 +654,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 +816,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 +842,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 +998,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 +1089,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
Original file line number Diff line number Diff line change
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
24 changes: 24 additions & 0 deletions samples/dash-if-reference-player/app/sources.json
Original file line number Diff line number Diff line change
Expand Up @@ -424,6 +424,30 @@
"moreInfo": "https://rdmedia.bbc.co.uk/testcard/simulcast/",
"provider": "bbc"
},
{
dsilhavy marked this conversation as resolved.
Show resolved Hide resolved
"name": "On-demand Testcard - WOFF Font Download signalled with supplemental property descriptor",
"url": "https://rdmedia.bbc.co.uk/testcard/vod/manifests/avc-ctv-stereo-en-sfdt-woff.mpd",
"moreInfo": "https://rdmedia.bbc.co.uk/testcard/vod/#feature-tests-font-downloads-for-subtitles",
"provider": "bbc"
},
{
"name": "On-demand Testcard - WOFF Font Download signalled with essential property descriptor",
"url": "https://rdmedia.bbc.co.uk/testcard/vod/manifests/avc-ctv-stereo-en-efdt-woff.mpd",
"moreInfo": "https://rdmedia.bbc.co.uk/testcard/vod/#feature-tests-font-downloads-for-subtitles",
"provider": "bbc"
},
{
"name": "Live Testcard - WOFF Font Download signalled with supplemental property descriptor",
"url": "https://rdmedia.bbc.co.uk/testcard/simulcast/manifests/avc-ctv-stereo-en-sfdt-woff.mpd",
"moreInfo": "https://rdmedia.bbc.co.uk/testcard/simulcast/#feature-tests-font-downloads-for-subtitles",
"provider": "bbc"
},
{
"name": "Live Testcard - WOFF Font Download signalled with essential property descriptor",
"url": "https://rdmedia.bbc.co.uk/testcard/simulcast/manifests/avc-ctv-stereo-en-efdt-woff.mpd",
"moreInfo": "https://rdmedia.bbc.co.uk/testcard/simulcast/#feature-tests-font-downloads-for-subtitles",
"provider": "bbc"
},
{
"url": "https://dash.akamaized.net/dash264/CTA/imsc1/IT1-20171027_dash.mpd",
"name": "IMSC1 Text Subtitles via sidecar file",
Expand Down
3 changes: 3 additions & 0 deletions src/dash/DashAdapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -1121,6 +1121,9 @@ function DashAdapter() {
}
}

mediaInfo.essentialProperties = dashManifestModel.getEssentialPropertiesForAdaptation(realAdaptation);
mediaInfo.essentialPropertiesAsArray = dashManifestModel.getEssentialPropertiesAsArrayForAdaptation(realAdaptation);

mediaInfo.isFragmented = dashManifestModel.getIsFragmented(realAdaptation);
mediaInfo.isEmbedded = false;

Expand Down
4 changes: 4 additions & 0 deletions src/dash/constants/DashConstants.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ class DashConstants {
this.AUDIO_CHANNEL_CONFIGURATION = 'AudioChannelConfiguration';
this.CONTENT_PROTECTION = 'ContentProtection';
this.ESSENTIAL_PROPERTY = 'EssentialProperty';
this.ESSENTIAL_PROPERTY_ASARRAY = 'EssentialProperty_asArray';
this.SUPPLEMENTAL_PROPERTY = 'SupplementalProperty';
this.SUPPLEMENTAL_PROPERTY_ASARRAY = 'SupplementalProperty_asArray';
this.INBAND_EVENT_STREAM = 'InbandEventStream';
Expand Down Expand Up @@ -133,6 +134,9 @@ class DashConstants {
this.CENC_DEFAULT_KID = 'cenc:default_KID';
this.DVB_PRIORITY = 'dvb:priority';
this.DVB_WEIGHT = 'dvb:weight';
this.DVB_URL = 'dvb:url';
this.DVB_MIMETYPE = 'dvb:mimeType';
this.DVB_FONTFAMILY = 'dvb:fontFamily';
this.SUGGESTED_PRESENTATION_DELAY = 'suggestedPresentationDelay';
this.SERVICE_DESCRIPTION = 'ServiceDescription';
this.SERVICE_DESCRIPTION_SCOPE = 'Scope';
Expand Down
34 changes: 30 additions & 4 deletions src/dash/models/DashManifestModel.js
Original file line number Diff line number Diff line change
Expand Up @@ -1295,8 +1295,9 @@ function DashManifestModel() {

if (adaptation && adaptation.hasOwnProperty(DashConstants.SUPPLEMENTAL_PROPERTY_ASARRAY)) {
for (const sp of adaptation.SupplementalProperty_asArray) {
if (sp.hasOwnProperty(Constants.SCHEME_ID_URI) && sp.hasOwnProperty(DashConstants.VALUE)) {
supplementalProperties[sp[Constants.SCHEME_ID_URI]] = sp[DashConstants.VALUE];
if (sp.hasOwnProperty(Constants.SCHEME_ID_URI)) {
// N.B this will only work where there is a single SupplementalProperty descriptor with this SchemeIdUri
supplementalProperties[sp[Constants.SCHEME_ID_URI]] = {...sp};
}
}
}
Expand All @@ -1316,8 +1317,9 @@ function DashManifestModel() {

if (representation && representation.hasOwnProperty(DashConstants.SUPPLEMENTAL_PROPERTY_ASARRAY)) {
for (const sp of representation.SupplementalProperty_asArray) {
if (sp.hasOwnProperty(Constants.SCHEME_ID_URI) && sp.hasOwnProperty(DashConstants.VALUE)) {
supplementalProperties[sp[Constants.SCHEME_ID_URI]] = sp[DashConstants.VALUE];
if (sp.hasOwnProperty(Constants.SCHEME_ID_URI)) {
// N.B this will only work where there is a single SupplementalProperty descriptor with this SchemeIdUri
supplementalProperties[sp[Constants.SCHEME_ID_URI]] = {...sp};
}
}
}
Expand All @@ -1332,6 +1334,28 @@ function DashManifestModel() {
});
}

function getEssentialPropertiesForAdaptation(adaptation) {
const essentialProperties = {};

if (adaptation && adaptation.hasOwnProperty(DashConstants.ESSENTIAL_PROPERTY_ASARRAY)) {
for (const ep of adaptation.EssentialProperty_asArray) {
if (ep.hasOwnProperty(Constants.SCHEME_ID_URI)) {
// N.B this will only work where there is a single EssentialProperty descriptor with this SchemeIdUri
essentialProperties[ep[Constants.SCHEME_ID_URI]] = {...ep};
}
}
}
return essentialProperties;
}

function getEssentialPropertiesAsArrayForAdaptation(adaptation) {
if (!adaptation || !adaptation.hasOwnProperty(DashConstants.ESSENTIAL_PROPERTY_ASARRAY) || !adaptation.EssentialProperty_asArray.length) return [];
return adaptation.EssentialProperty_asArray.map( ep => {
const s = new DescriptorType();
return s.init(ep);
});
}

function setConfig(config) {
if (!config) return;

Expand Down Expand Up @@ -1382,6 +1406,8 @@ function DashManifestModel() {
getRegularPeriods,
getMpd,
getEventsForPeriod,
getEssentialPropertiesForAdaptation,
getEssentialPropertiesAsArrayForAdaptation,
getEssentialPropertiesForRepresentation,
getEventStreamForAdaptationSet,
getEventStreamForRepresentation,
Expand Down
Loading