Skip to content

Commit e3ab832

Browse files
committed
Merge remote-tracking branch 'origin/development' into fix/#4867
2 parents 6058429 + c752672 commit e3ab832

37 files changed

+1487
-34
lines changed

index.d.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -984,6 +984,8 @@ export interface Representation {
984984
bitsPerPixel: number;
985985
codecPrivateData: string | null;
986986
codecs: string | null;
987+
dependencyId: string | null;
988+
dependentRepresentation: object | null;
987989
fragmentDuration: number | null;
988990
frameRate: number;
989991
height: number;
@@ -2868,6 +2870,7 @@ export interface conformanceViolationConstants {
28682870
export interface Constants {
28692871
STREAM: 'stream',
28702872
VIDEO: 'video',
2873+
ENHANCEMENT: 'enhancement',
28712874
AUDIO: 'audio',
28722875
TEXT: 'text',
28732876
MUXED: 'muxed',
@@ -5907,13 +5910,43 @@ export interface StreamProcessor {
59075910

59085911
selectMediaInfo(selectionInput: object): Promise<any>;
59095912

5913+
setEnhancementStreamProcessor(value: StreamProcessor): void;
5914+
59105915
setExplicitBufferingTime(value: number): void;
59115916

59125917
setMediaSource(mediaSource: MediaSource): void;
59135918

59145919
updateStreamInfo(newStreamInfo: StreamInfo): Promise<any>;
59155920
}
59165921

5922+
export interface ExternalMediaSource {
5923+
duration: number | null;
5924+
5925+
readyState: string;
5926+
5927+
addSourceBuffer(mimeType: string): ExternalSourceBuffer;
5928+
5929+
close(): void;
5930+
5931+
endOfStream(): void;
5932+
5933+
open(): void;
5934+
5935+
removeSourceBuffer(sourceBuffer: ExternalSourceBuffer): void;
5936+
5937+
reset(): void;
5938+
}
5939+
5940+
export interface ExternalSourceBuffer {
5941+
buffered: TimeRanges;
5942+
5943+
abort(): void;
5944+
5945+
appendBuffer(segmentData: ArrayBuffer, segmentStartTime: number, segmentEndTime: number): void;
5946+
5947+
remove(start: number, end: number): void;
5948+
}
5949+
59175950
export interface XlinkLoader {
59185951
load(url: string, element: any, resolveObject: object): void;
59195952

samples/dash-if-reference-player/app/contributors.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,11 @@
6868
"name": "Broadpeak",
6969
"logo": "app/img/broadpeak.png",
7070
"link": "https://broadpeak.tv/"
71+
},
72+
{
73+
"name": "V-Nova",
74+
"logo": "app/img/v-nova.png",
75+
"link": "https://v-nova.com/"
7176
}
7277
]
7378
}

samples/dash-if-reference-player/app/css/main.css

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ a:hover {
153153

154154
.dash-video-player {
155155
background-color: #000000;
156+
position: relative;
156157
}
157158

158159
.col-md-9 video {
@@ -179,6 +180,10 @@ a:hover {
179180
margin-top: -5px !important;
180181
}
181182

183+
.element-hidden {
184+
display: none !important;
185+
}
186+
182187
.btn-play-pause,
183188
.control-icon-layout {
184189
padding: 4px 10px !important;
91.5 KB
Loading

samples/dash-if-reference-player/app/main.js

Lines changed: 162 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,8 @@ app.controller('DashController', ['$scope', '$window', 'sources', 'contributors'
238238

239239
$scope.conformanceViolations = [];
240240

241+
$scope.enhancementDecoder = null;
242+
241243
var defaultExternalSettings = {
242244
mpd: encodeURIComponent('https://dash.akamaized.net/akamai/bbb_30fps/bbb_30fps.mpd'),
243245
loop: true,
@@ -294,6 +296,12 @@ app.controller('DashController', ['$scope', '$window', 'sources', 'contributors'
294296
$scope.audioLiveLatency = 0;
295297
$scope.audioPlaybackRate = 1.00;
296298

299+
$scope.activePeriod = '';
300+
$scope.bufferingPeriod = '';
301+
302+
$scope.mpdType = '';
303+
$scope.numberOfPeriods = 0;
304+
297305
// Starting Options
298306
$scope.autoPlaySelected = true;
299307
$scope.autoLoadSelected = false;
@@ -434,6 +442,12 @@ app.controller('DashController', ['$scope', '$window', 'sources', 'contributors'
434442

435443
$scope.player.on(dashjs.MediaPlayer.events.MANIFEST_LOADED, function (e) {
436444
$scope.isDynamic = e.data.type === 'dynamic';
445+
if (e.data.Period) {
446+
$scope.numberOfPeriods = e.data.Period.length;
447+
}
448+
if (e.data.type) {
449+
$scope.mpdType = e.data.type;
450+
}
437451
}, $scope);
438452

439453

@@ -450,11 +464,16 @@ app.controller('DashController', ['$scope', '$window', 'sources', 'contributors'
450464
$scope[e.mediaType + 'Bitrate'] = bitrate;
451465
$scope.plotPoint('pendingIndex', e.mediaType, e.newQuality + 1, getTimeForPlot());
452466
$scope.safeApply();
467+
468+
if (e.currentRepresentation && e.currentRepresentation.adaptation && e.currentRepresentation.adaptation.period) {
469+
$scope.bufferingPeriod = e.currentRepresentation.adaptation.period.id;
470+
}
453471
}, $scope);
454472

455473

456474
$scope.player.on(dashjs.MediaPlayer.events.PERIOD_SWITCH_COMPLETED, function (e) {
457475
$scope.currentStreamInfo = e.toStreamInfo;
476+
$scope.activePeriod = e.toStreamInfo.id;
458477
}, $scope);
459478

460479
$scope.player.on(dashjs.MediaPlayer.events.QUALITY_CHANGE_RENDERED, function (e) {
@@ -1035,6 +1054,126 @@ app.controller('DashController', ['$scope', '$window', 'sources', 'contributors'
10351054
});
10361055
};
10371056

1057+
$scope.toggleEnhancementEnabled = function () {
1058+
const video = document.querySelector('video');
1059+
const canvas = document.querySelector('canvas');
1060+
1061+
if ($scope.enhancementEnabled) {
1062+
canvas.classList.remove('element-hidden');
1063+
video.classList.add('element-hidden');
1064+
} else {
1065+
canvas.classList.add('element-hidden');
1066+
video.classList.remove('element-hidden');
1067+
}
1068+
};
1069+
1070+
$scope.setupEnhancementDecoder = function () {
1071+
/**
1072+
* MPEG-5 LCEVC Integration for Dash.js Player.
1073+
*
1074+
* These are the changes needed for passing the correct
1075+
* data to lcevc_dec.js and trigger the correct methods
1076+
* at the correct time.
1077+
*/
1078+
1079+
/**
1080+
* Let the LCEVC Decoder Library make the decision as to when to switch, based on the currently
1081+
* rendered frame. If disabled, the player needs to signal LCEVC when there is a render change
1082+
* after an ABR switch happens.
1083+
*
1084+
* @readonly
1085+
* @enum {number}
1086+
* @public
1087+
*/
1088+
const AutoRenderMode = {
1089+
DISABLED: 0,
1090+
ENABLED: 1
1091+
};
1092+
1093+
dashjs.Extensions = {
1094+
...dashjs.Extensions,
1095+
/**
1096+
* Attaches LCEVC functionality and methods to the provided Dash.js player instance.
1097+
*
1098+
* @param {object} player the Dash.js player instance to attach LCEVC to
1099+
*/
1100+
useLcevc: function useLcevc(player) {
1101+
if (!player) {
1102+
throw new TypeError('The provided Dash.js player instance was null or undefined.');
1103+
}
1104+
const { LCEVCdec } = window;
1105+
if (!LCEVCdec) {
1106+
throw new TypeError('LCEVC Decoder Libraries could not be loaded.');
1107+
}
1108+
1109+
let abrIndex = -1;
1110+
1111+
player.attachLcevc = function attachLcevc(media, canvas, LCEVCdecConfig) {
1112+
player.LCEVCdec = new LCEVCdec.LCEVCdec(
1113+
media,
1114+
canvas,
1115+
LCEVCdecConfig
1116+
);
1117+
1118+
/* Signal profile information and switches to LCEVCdecJS */
1119+
player.on(dashjs.MediaPlayer.events.QUALITY_CHANGE_REQUESTED, handleQualityChange);
1120+
player.on(dashjs.MediaPlayer.events.FRAGMENT_LOADING_COMPLETED, handleFragmentLoadingCompleted);
1121+
player.on(dashjs.MediaPlayer.events.REPRESENTATION_SWITCH, handleRepresentationSwitch);
1122+
player.on('externalSourceBufferUpdateStart', handleBufferUpdates);
1123+
};
1124+
1125+
function handleFragmentLoadingCompleted(event) {
1126+
if (event.mediaType === 'enhancement') {
1127+
abrIndex = event.request.representation.absoluteIndex;
1128+
}
1129+
}
1130+
1131+
function handleQualityChange(event) {
1132+
if (event.mediaType === 'video' || event.mediaType === 'enhancement') {
1133+
const index = event.newRepresentation.absoluteIndex;
1134+
console.log('>>> requested:', event.mediaType, index);
1135+
player.LCEVCdec.setLevelSwitching(index, AutoRenderMode.ENABLED);
1136+
}
1137+
}
1138+
1139+
function handleRepresentationSwitch(event) {
1140+
if (event.mediaType === 'video' || event.mediaType === 'enhancement') {
1141+
const rep = event.currentRepresentation;
1142+
const index = rep.absoluteIndex;
1143+
// Workaround for very first representation played for which no QUALITY_CHANGE_REQUESTED arrives
1144+
if (rep && rep.dependentRepresentation) {
1145+
console.log('>>> rep switch:', event.mediaType, index);
1146+
player.LCEVCdec.setLevelSwitching(index, AutoRenderMode.ENABLED);
1147+
}
1148+
}
1149+
}
1150+
1151+
function handleBufferUpdates(event) {
1152+
if (event.request === 'appendBuffer') {
1153+
player.LCEVCdec.appendBuffer(event.data, 'video', abrIndex, 0, /* isMuxed */ false);
1154+
}
1155+
else if (event.request === 'remove') {
1156+
player.LCEVCdec.flushBuffer(event.start, event.end);
1157+
}
1158+
}
1159+
}
1160+
};
1161+
1162+
const video = document.querySelector('video');
1163+
const canvas = document.querySelector('canvas');
1164+
const LCEVCdecConfig = {
1165+
dynamicPerformanceScaling: false
1166+
};
1167+
1168+
window.LCEVCdec.ready.then(() => {
1169+
/* Attach LCEVC to the Dash.js player instance */
1170+
const player = $scope.player;
1171+
dashjs.Extensions.useLcevc(player);
1172+
player.attachLcevc(video, canvas, LCEVCdecConfig);
1173+
$scope.enhancementDecoder = player.LCEVCdec;
1174+
});
1175+
};
1176+
10381177
$scope.toggleCmsdApplyMb = function () {
10391178
$scope.player.updateSettings({
10401179
streaming: {
@@ -1104,7 +1243,8 @@ app.controller('DashController', ['$scope', '$window', 'sources', 'contributors'
11041243
liveDelay: $scope.defaultLiveDelay
11051244
},
11061245
abr: {},
1107-
cmcd: {}
1246+
cmcd: {},
1247+
enhancement: {}
11081248
}
11091249
};
11101250

@@ -1170,6 +1310,21 @@ app.controller('DashController', ['$scope', '$window', 'sources', 'contributors'
11701310
config.streaming.cmcd.rtpSafetyFactor = $scope.cmcdRtpSafetyFactor ? $scope.cmcdRtpSafetyFactor : null;
11711311
config.streaming.cmcd.enabledKeys = $scope.cmcdEnabledKeys ? $scope._getFormatedCmcdEnabledKeys() : [];
11721312

1313+
// Cleanup enhancement decoder if it exists from previous playback
1314+
if ($scope.enhancementDecoder) {
1315+
$scope.enhancementDecoder.close();
1316+
$scope.enhancementDecoder = null;
1317+
}
1318+
1319+
// Setup enhancement decoder if checkbox is checked or if stream is from V-Nova
1320+
if ($scope.enhancementEnabled || $scope.selectedItem.provider === 'v-nova') {
1321+
config.streaming.enhancement.enabled = true;
1322+
$scope.enhancementEnabled = true;
1323+
$scope.setupEnhancementDecoder();
1324+
}
1325+
1326+
$scope.toggleEnhancementEnabled();
1327+
11731328
$scope.player.updateSettings(config);
11741329

11751330
$scope.controlbar.reset();
@@ -1343,11 +1498,11 @@ app.controller('DashController', ['$scope', '$window', 'sources', 'contributors'
13431498
protectionData[input.drmKeySystem]['httpRequestHeaders'] = input.httpRequestHeaders;
13441499
}
13451500

1346-
if(input.audioRobustness){
1501+
if (input.audioRobustness) {
13471502
protectionData[input.drmKeySystem]['audioRobustness'] = input.audioRobustness;
13481503
}
13491504

1350-
if(input.videoRobustness){
1505+
if (input.videoRobustness) {
13511506
protectionData[input.drmKeySystem]['videoRobustness'] = input.videoRobustness;
13521507
}
13531508
} else {
@@ -1391,11 +1546,11 @@ app.controller('DashController', ['$scope', '$window', 'sources', 'contributors'
13911546
protectionData[input.drmKeySystem]['httpRequestHeaders'] = input.httpRequestHeaders;
13921547
}
13931548

1394-
if(input.audioRobustness){
1549+
if (input.audioRobustness) {
13951550
protectionData[input.drmKeySystem]['audioRobustness'] = input.audioRobustness;
13961551
}
13971552

1398-
if(input.videoRobustness){
1553+
if (input.videoRobustness) {
13991554
protectionData[input.drmKeySystem]['videoRobustness'] = input.videoRobustness;
14001555
}
14011556
}
@@ -2039,8 +2194,8 @@ app.controller('DashController', ['$scope', '$window', 'sources', 'contributors'
20392194
else if (value === 'null') typedValue = null;
20402195
else if (value === 'undefined') typedValue = undefined;
20412196
else integerRegEx.test(value) ? typedValue = parseInt(value) :
2042-
(floatRegEx.test(value) ? typedValue = parseFloat(value) :
2043-
typedValue = value);
2197+
(floatRegEx.test(value) ? typedValue = parseFloat(value) :
2198+
typedValue = value);
20442199

20452200
return typedValue;
20462201
}

samples/dash-if-reference-player/app/sources.json

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,11 @@
9393
"acronym": "ARTE",
9494
"name": "ARTE",
9595
"url": "https://www.arte.tv/en/"
96+
},
97+
"v-nova": {
98+
"acronym": "V-Nova",
99+
"name": "V-Nova",
100+
"url": "https://v-nova.com/"
96101
}
97102
},
98103
"items": [
@@ -1303,6 +1308,21 @@
13031308
"provider": "microsoft"
13041309
}
13051310
]
1311+
},
1312+
{
1313+
"name": "MPEG-5 Part 2 - LCEVC",
1314+
"submenu": [
1315+
{
1316+
"url": "https://s3.eu-west-1.amazonaws.com/origin-prod-lon-v-nova.com/lcevcDualTrack/1080p30_4Mbps_no_dR/master.mpd",
1317+
"name": "Scalable Carriage",
1318+
"provider": "v-nova"
1319+
},
1320+
{
1321+
"url": "https://s3.eu-west-1.amazonaws.com/origin-prod-lon-v-nova.com/lcevcDualTrack/1080p30_4Mbps_with_dR/master.mpd",
1322+
"name": "Scalable with Debug Residuals",
1323+
"provider": "v-nova"
1324+
}
1325+
]
13061326
}
13071327
]
13081328
}

0 commit comments

Comments
 (0)