@@ -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 }
0 commit comments