Skip to content

Commit

Permalink
Add track selection mode based on selectionPriority attribute (#3751)
Browse files Browse the repository at this point in the history
* Add track selection mode based on selectionPriority attribute in the manifest. Make this the default mode and fallback to TRACK_SELECTION_MODE_HIGHEST_BITRATE and TRACK_SELECTION_MODE_WIDEST_RANGE in case no selectionPriority is given.
  • Loading branch information
dsilhavy authored Sep 5, 2021
1 parent 283df6b commit 5e31f9f
Show file tree
Hide file tree
Showing 9 changed files with 257 additions and 95 deletions.
2 changes: 1 addition & 1 deletion index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1475,7 +1475,7 @@ declare namespace dashjs {

export type MetricType = 'ManifestUpdate' | 'RequestsQueue';
export type TrackSwitchMode = 'alwaysReplace' | 'neverReplace';
export type TrackSelectionMode = 'highestBitrate' | 'firstTrack' | 'highestEfficiency' | 'widestRange';
export type TrackSelectionMode = 'highestSelectionPriority' | 'highestBitrate' | 'firstTrack' | 'highestEfficiency' | 'widestRange';

export function supportsMediaSource(): boolean;

Expand Down
9 changes: 6 additions & 3 deletions src/core/Settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ import {HTTPRequest} from '../streaming/vo/metrics/HTTPRequest';
* audio: Constants.TRACK_SWITCH_MODE_ALWAYS_REPLACE,
* video: Constants.TRACK_SWITCH_MODE_NEVER_REPLACE
* },
* selectionModeForInitialTrack: Constants.TRACK_SELECTION_MODE_HIGHEST_BITRATE,
* selectionModeForInitialTrack: Constants.TRACK_SELECTION_MODE_HIGHEST_SELECTION_PRIORITY,
* fragmentRequestTimeout: 0,
* retryIntervals: {
* [HTTPRequest.MPD_TYPE]: 500,
Expand Down Expand Up @@ -682,8 +682,11 @@ import {HTTPRequest} from '../streaming/vo/metrics/HTTPRequest';
*
* Possible values
*
* - Constants.TRACK_SELECTION_MODE_HIGHEST_SELECTION_PRIORITY
* This mode makes the player select the track with the highest selectionPriority as defined in the manifest. If not selectionPriority is given we fallback to TRACK_SELECTION_MODE_HIGHEST_BITRATE. This mode is a default mode.
*
* - Constants.TRACK_SELECTION_MODE_HIGHEST_BITRATE
* This mode makes the player select the track with a highest bitrate. This mode is a default mode.
* This mode makes the player select the track with a highest bitrate.
*
* - Constants.TRACK_SELECTION_MODE_FIRST_TRACK
* This mode makes the player select the first track found in the manifest.
Expand Down Expand Up @@ -825,7 +828,7 @@ function Settings() {
audio: Constants.TRACK_SWITCH_MODE_ALWAYS_REPLACE,
video: Constants.TRACK_SWITCH_MODE_NEVER_REPLACE
},
selectionModeForInitialTrack: Constants.TRACK_SELECTION_MODE_HIGHEST_BITRATE,
selectionModeForInitialTrack: Constants.TRACK_SELECTION_MODE_HIGHEST_SELECTION_PRIORITY,
fragmentRequestTimeout: 0,
retryIntervals: {
[HTTPRequest.MPD_TYPE]: 500,
Expand Down
1 change: 1 addition & 0 deletions src/dash/DashAdapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -1023,6 +1023,7 @@ function DashAdapter() {
mediaInfo.mimeType = dashManifestModel.getMimeType(realAdaptation);
mediaInfo.contentProtection = dashManifestModel.getContentProtectionData(realAdaptation);
mediaInfo.bitrateList = dashManifestModel.getBitrateListForAdaptation(realAdaptation);
mediaInfo.selectionPriority = dashManifestModel.getSelectionPriority(realAdaptation);

if (mediaInfo.contentProtection) {
mediaInfo.contentProtection.forEach(function (item) {
Expand Down
11 changes: 11 additions & 0 deletions src/dash/models/DashManifestModel.js
Original file line number Diff line number Diff line change
Expand Up @@ -406,6 +406,16 @@ function DashManifestModel() {
});
}

function getSelectionPriority(realAdaption) {
try {
const priority = realAdaption && typeof realAdaption.selectionPriority !== 'undefined' ? parseInt(realAdaption.selectionPriority) : 1;

return isNaN(priority) ? 1 : priority;
} catch (e) {
return 1;
}
}

function getEssentialPropertiesForRepresentation(realRepresentation) {
if (!realRepresentation || !realRepresentation.EssentialProperty_asArray || !realRepresentation.EssentialProperty_asArray.length) return null;

Expand Down Expand Up @@ -1169,6 +1179,7 @@ function DashManifestModel() {
getRealPeriods,
getRealPeriodForIndex,
getCodec,
getSelectionPriority,
getMimeType,
getKID,
getLabelsForAdaptation,
Expand Down
1 change: 1 addition & 0 deletions src/dash/vo/MediaInfo.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ class MediaInfo {
this.bitrateList = null;
this.isFragmented = null;
this.isEmbedded = null;
this.selectionPriority = 1;
}

}
Expand Down
7 changes: 7 additions & 0 deletions src/streaming/constants/Constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,13 @@ class Constants {
*/
this.TRACK_SELECTION_MODE_WIDEST_RANGE = 'widestRange';

/**
* @constant {string} TRACK_SELECTION_MODE_WIDEST_RANGE makes the player select the track with the highest selectionPriority as defined in the manifest
* @memberof Constants#
* @static
*/
this.TRACK_SELECTION_MODE_HIGHEST_SELECTION_PRIORITY = 'highestSelectionPriority';

/**
* @constant {string} CMCD_MODE_QUERY specifies to attach CMCD metrics as query parameters.
* @memberof Constants#
Expand Down
102 changes: 83 additions & 19 deletions src/streaming/controllers/MediaController.js
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,28 @@ function MediaController() {
};
}

function getTracksWithHighestSelectionPriority(trackArr) {
let max = 0;
let result = [];

trackArr.forEach((track) => {
if(!isNaN(track.selectionPriority)) {
// Higher max value. Reset list and add new entry
if (track.selectionPriority > max) {
max = track.selectionPriority;
result = [track];
}
// Same max value add to list
else if (track.selectionPriority === max) {
result.push(track);
}

}
})

return result;
}

function getTracksWithHighestBitrate(trackArr) {
let max = 0;
let result = [];
Expand Down Expand Up @@ -402,45 +424,87 @@ function MediaController() {
if (type === Constants.TEXT) return tracks[0];

let mode = settings.get().streaming.selectionModeForInitialTrack;
let tmpArr = [];
let tmpArr;

if (customInitialTrackSelectionFunction && typeof customInitialTrackSelectionFunction === 'function') {
tmpArr = customInitialTrackSelectionFunction(tracks);
} else {
switch (mode) {
case Constants.TRACK_SELECTION_MODE_HIGHEST_SELECTION_PRIORITY:
tmpArr = _trackSelectionModeHighestSelectionPriority(tracks);
break;
case Constants.TRACK_SELECTION_MODE_HIGHEST_BITRATE:
tmpArr = getTracksWithHighestBitrate(tracks);

if (tmpArr.length > 1) {
tmpArr = getTracksWithWidestRange(tmpArr);
}
tmpArr = _trackSelectionModeHighestBitrate(tracks);
break;
case Constants.TRACK_SELECTION_MODE_FIRST_TRACK:
tmpArr.push(tracks[0]);
tmpArr = _trackSelectionModeFirstTrack(tracks);
break;
case Constants.TRACK_SELECTION_MODE_HIGHEST_EFFICIENCY:
tmpArr = getTracksWithHighestEfficiency(tracks);

if (tmpArr.length > 1) {
tmpArr = getTracksWithHighestBitrate(tmpArr);
}
tmpArr = _trackSelectionModeHighestEfficiency(tracks);
break;
case Constants.TRACK_SELECTION_MODE_WIDEST_RANGE:
tmpArr = getTracksWithWidestRange(tracks);

if (tmpArr.length > 1) {
tmpArr = getTracksWithHighestBitrate(tracks);
}
tmpArr = _trackSelectionModeWidestRange(tracks);
break;
default:
logger.warn('Track selection mode is not supported: ' + mode);
logger.warn(`Track selection mode ${mode} is not supported. Falling back to TRACK_SELECTION_MODE_FIRST_TRACK`);
tmpArr = _trackSelectionModeFirstTrack(tracks);
break;
}
}

return tmpArr[0];
return tmpArr.length > 0 ? tmpArr[0] : tracks[0];
}


function _trackSelectionModeHighestSelectionPriority(tracks) {
let tmpArr = getTracksWithHighestSelectionPriority(tracks);

if (tmpArr.length > 1) {
tmpArr = getTracksWithHighestBitrate(tmpArr);
}

if (tmpArr.length > 1) {
tmpArr = getTracksWithWidestRange(tmpArr);
}

return tmpArr;
}

function _trackSelectionModeHighestBitrate(tracks) {
let tmpArr = getTracksWithHighestBitrate(tracks);

if (tmpArr.length > 1) {
tmpArr = getTracksWithWidestRange(tmpArr);
}

return tmpArr;
}

function _trackSelectionModeFirstTrack(tracks) {
return tracks[0];
}

function _trackSelectionModeHighestEfficiency(tracks) {
let tmpArr = getTracksWithHighestEfficiency(tracks);

if (tmpArr.length > 1) {
tmpArr = getTracksWithHighestBitrate(tmpArr);
}

return tmpArr;
}

function _trackSelectionModeWidestRange(tracks) {
let tmpArr = getTracksWithWidestRange(tracks);

if (tmpArr.length > 1) {
tmpArr = getTracksWithHighestBitrate(tracks);
}

return tmpArr;
}


function createTrackInfo() {
return {
audio: {
Expand Down
Loading

0 comments on commit 5e31f9f

Please sign in to comment.