Skip to content

Commit f7fd123

Browse files
committed
Merge remote-tracking branch 'origin/development' into feature/MpdInformationReferenceUi
2 parents 74de535 + 6dee0b1 commit f7fd123

37 files changed

+1426
-28
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: 139 additions & 1 deletion
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,
@@ -1052,6 +1054,126 @@ app.controller('DashController', ['$scope', '$window', 'sources', 'contributors'
10521054
});
10531055
};
10541056

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+
10551177
$scope.toggleCmsdApplyMb = function () {
10561178
$scope.player.updateSettings({
10571179
streaming: {
@@ -1121,7 +1243,8 @@ app.controller('DashController', ['$scope', '$window', 'sources', 'contributors'
11211243
liveDelay: $scope.defaultLiveDelay
11221244
},
11231245
abr: {},
1124-
cmcd: {}
1246+
cmcd: {},
1247+
enhancement: {}
11251248
}
11261249
};
11271250

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

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+
11901328
$scope.player.updateSettings(config);
11911329

11921330
$scope.controlbar.reset();

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
}

samples/dash-if-reference-player/index.html

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@
3434
<script src="app/main.js"></script>
3535
<script src="app/rules/ThroughputRule.js"></script>
3636

37+
<!-- LCEVC Decoder -->
38+
<script src="https://unpkg.com/lcevc_dec.js@latest/dist/lcevc_dec.min.js"></script>
39+
3740
<!-- Google Cast -->
3841
<script src="https://www.gstatic.com/cv/js/sender/v1/cast_sender.js?loadCastFramework=1"></script>
3942

@@ -1003,6 +1006,17 @@
10031006
ng-change="updateCmsdEtpWeightRatio()">
10041007
</div>
10051008
</div>
1009+
<div class="options-item">
1010+
<div class="options-item-title">Enhancement Layer</div>
1011+
<div class="options-item-body">
1012+
<label class="topcoat-checkbox" data-toggle="tooltip" data-placement="right"
1013+
title="Enables enhancement layer. The provided stream should contain two adaptation sets, one containing the base layer and the second containing an enhancement layer. Checkbox selection will be applied the next time a stream is loaded.">
1014+
<input type="checkbox" ng-model="enhancementEnabled" ng-change=""
1015+
ng-checked="enhancementEnabled">
1016+
Enable Enhancement Layer
1017+
</label>
1018+
</div>
1019+
</div>
10061020

10071021
</div>
10081022

@@ -1011,6 +1025,8 @@
10111025
<div class="dash-video-player col-md-9">
10121026
<div id="videoContainer" class="videoContainer">
10131027
<video disableRemotePlayback="true"></video>
1028+
<canvas id="enhacementCanvas" class="enhancementCanvas element-hidden"></canvas>
1029+
<div style="min-height: 1px;"></div>
10141030
<div id="video-caption"></div>
10151031
<div id="cast-msg" ng-if="isCasting">
10161032
{{ castPlayerState === 'IDLE' ? 'Ready to cast stream' : castPlayerState }}

0 commit comments

Comments
 (0)