Skip to content

Commit

Permalink
Add "highestEfficiency" initial track selection mode (#3498)
Browse files Browse the repository at this point in the history
  • Loading branch information
chromakode committed Jan 11, 2021
1 parent e1098fc commit 9d91e39
Show file tree
Hide file tree
Showing 5 changed files with 186 additions and 43 deletions.
4 changes: 2 additions & 2 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1088,7 +1088,7 @@ declare namespace dashjs {

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

export type TrackSelectionMode = 'highestBitrate' | 'highestEfficiency' | 'widestRange';
export function supportsMediaSource(): boolean;

}
7 changes: 5 additions & 2 deletions src/streaming/MediaPlayer.js
Original file line number Diff line number Diff line change
Expand Up @@ -1592,10 +1592,13 @@ function MediaPlayer() {
* if no initial media settings are set. If initial media settings are set this parameter will be ignored. Available options are:
*
* 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. This mode is a default mode.
*
* Constants.TRACK_SELECTION_MODE_HIGHEST_EFFICIENCY
* This mode makes the player select the track with the lowest bitrate per pixel average.
*
* Constants.TRACK_SELECTION_MODE_WIDEST_RANGE
* this mode makes the player select the track with a widest range of bitrates
* This mode makes the player select the track with a widest range of bitrates.
*
* @param {string} mode
* @memberof module:MediaPlayer
Expand Down
9 changes: 8 additions & 1 deletion src/streaming/constants/Constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,14 @@ class Constants {
this.TRACK_SELECTION_MODE_HIGHEST_BITRATE = 'highestBitrate';

/**
* @constant {string} TRACK_SELECTION_MODE_WIDEST_RANGE this mode makes the player select the track with a widest range of bitrates
* @constant {string} TRACK_SELECTION_MODE_HIGHEST_EFFICIENCY makes the player select the track with the lowest bitrate per pixel average.
* @memberof Constants#
* @static
*/
this.TRACK_SELECTION_MODE_HIGHEST_EFFICIENCY = 'highestEfficiency';

/**
* @constant {string} TRACK_SELECTION_MODE_WIDEST_RANGE makes the player select the track with a widest range of bitrates.
* @memberof Constants#
* @static
*/
Expand Down
113 changes: 75 additions & 38 deletions src/streaming/controllers/MediaController.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ function MediaController() {

const validTrackSelectionModes = [
Constants.TRACK_SELECTION_MODE_HIGHEST_BITRATE,
Constants.TRACK_SELECTION_MODE_HIGHEST_EFFICIENCY,
Constants.TRACK_SELECTION_MODE_WIDEST_RANGE
];

Expand Down Expand Up @@ -87,10 +88,10 @@ function MediaController() {
}

if (tracks.length === 0) {
setTrack(selectInitialTrack(type, tracksForType), true);
setTrack(this.selectInitialTrack(type, tracksForType), true);
} else {
if (tracks.length > 1) {
setTrack(selectInitialTrack(type, tracks));
setTrack(this.selectInitialTrack(type, tracks));
} else {
setTrack(tracks[0]);
}
Expand Down Expand Up @@ -403,48 +404,73 @@ function MediaController() {
};
}

function selectInitialTrack(type, tracks) {
if (type === Constants.FRAGMENTED_TEXT) return tracks[0];
function getTracksWithHighestBitrate (trackArr) {
let max = 0;
let result = [];
let tmp;

let mode = getSelectionModeForInitialTrack();
let tmpArr = [];
trackArr.forEach(function (track) {
tmp = Math.max.apply(Math, track.bitrateList.map(function (obj) { return obj.bandwidth; }));

const getTracksWithHighestBitrate = function (trackArr) {
let max = 0;
let result = [];
let tmp;
if (tmp > max) {
max = tmp;
result = [track];
} else if (tmp === max) {
result.push(track);
}
});

trackArr.forEach(function (track) {
tmp = Math.max.apply(Math, track.bitrateList.map(function (obj) { return obj.bandwidth; }));
return result;
}

if (tmp > max) {
max = tmp;
result = [track];
} else if (tmp === max) {
result.push(track);
}
});
function getTracksWithHighestEfficiency (trackArr) {
let min = Infinity;
let result = [];
let tmp;

trackArr.forEach(function (track) {
const sum = track.bitrateList.reduce(function (acc, obj) {
const resolution = Math.max(1, obj.width * obj.height);
const efficiency = obj.bandwidth / resolution;
return acc + efficiency;
}, 0);
tmp = sum / track.bitrateList.length;

if (tmp < min) {
min = tmp;
result = [track];
} else if (tmp === min) {
result.push(track);
}
});

return result;
};
const getTracksWithWidestRange = function (trackArr) {
let max = 0;
let result = [];
let tmp;

trackArr.forEach(function (track) {
tmp = track.representationCount;

if (tmp > max) {
max = tmp;
result = [track];
} else if (tmp === max) {
result.push(track);
}
});
return result;
}

return result;
};
function getTracksWithWidestRange (trackArr) {
let max = 0;
let result = [];
let tmp;

trackArr.forEach(function (track) {
tmp = track.representationCount;

if (tmp > max) {
max = tmp;
result = [track];
} else if (tmp === max) {
result.push(track);
}
});

return result;
}

function selectInitialTrack(type, tracks) {
if (type === Constants.FRAGMENTED_TEXT) return tracks[0];

let mode = getSelectionModeForInitialTrack();
let tmpArr = [];

switch (mode) {
case Constants.TRACK_SELECTION_MODE_HIGHEST_BITRATE:
Expand All @@ -454,6 +480,13 @@ function MediaController() {
tmpArr = getTracksWithWidestRange(tmpArr);
}
break;
case Constants.TRACK_SELECTION_MODE_HIGHEST_EFFICIENCY:
tmpArr = getTracksWithHighestEfficiency(tracks);

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

Expand Down Expand Up @@ -510,6 +543,10 @@ function MediaController() {
getInitialSettings: getInitialSettings,
setSwitchMode: setSwitchMode,
getSwitchMode: getSwitchMode,
selectInitialTrack: selectInitialTrack,
getTracksWithHighestBitrate: getTracksWithHighestBitrate,
getTracksWithHighestEfficiency: getTracksWithHighestEfficiency,
getTracksWithWidestRange: getTracksWithWidestRange,
setSelectionModeForInitialTrack: setSelectionModeForInitialTrack,
getSelectionModeForInitialTrack: getSelectionModeForInitialTrack,
isMultiTrackSupportedByType: isMultiTrackSupportedByType,
Expand Down
96 changes: 96 additions & 0 deletions test/unit/streaming.controllers.MediaController.js
Original file line number Diff line number Diff line change
Expand Up @@ -545,4 +545,100 @@ describe('MediaController', function () {
});
});

describe('Initial Track Selection', function () {

function testSelectInitialTrack(type, expectedBitrateList, otherBitrateList) {
const tracks = [ expectedBitrateList, otherBitrateList ].map(function (bitrateList) {
return {
bitrateList: bitrateList,
representationCount: bitrateList.length
};
});
const selection = mediaController.selectInitialTrack(type, tracks);
expect(objectUtils.areEqual(selection.bitrateList, expectedBitrateList)).to.be.true; // jshint ignore:line
}

describe('"highestBitrate" mode', function () {
beforeEach(function () {
mediaController.setSelectionModeForInitialTrack(Constants.TRACK_SELECTION_MODE_HIGHEST_BITRATE);
});

it('should select track with highest bitrate', function () {
testSelectInitialTrack(
'video',
[ { bandwidth: 2000 } ],
[ { bandwidth: 1000 } ]
);
});

it('should tie break using "widestRange"', function () {
testSelectInitialTrack(
'video',
[ { bandwidth: 2000 }, { bandwidth: 1000 } ],
[ { bandwidth: 2000 } ]
);
});
});

describe('"highestEfficiency" mode', function () {
beforeEach(function () {
mediaController.setSelectionModeForInitialTrack(Constants.TRACK_SELECTION_MODE_HIGHEST_EFFICIENCY);
});

it('should select video track with lowest bitrate among equal resolutions', function () {
testSelectInitialTrack(
'video',
[ { bandwidth: 1000, width: 1920, height: 1280 } ],
[ { bandwidth: 2000, width: 1920, height: 1280 } ]
);
});

it('should select video track with lowest bitrate among different resolutions', function () {
testSelectInitialTrack(
'video',
[ { bandwidth: 1000, width: 1920, height: 1280 } ],
[ { bandwidth: 1000, width: 1080, height: 720 } ]
);
});

it('should select audio track with lowest avg bitrate', function () {
testSelectInitialTrack(
'audio',
[ { bandwidth: 1000, width: 0, height: 0 } ],
[ { bandwidth: 2000, width: 0, height: 0 } ]
);
});

it('should tie break using "highestBitrate"', function () {
testSelectInitialTrack(
'video',
[ { bandwidth: 1500, width: 1920, height: 1280 }, { bandwidth: 1000, width: 1080, height: 720 } ],
[ { bandwidth: 1000, width: 1080, height: 720 } ]
);
});
});

describe('"widestRange" mode', function () {
beforeEach(function () {
mediaController.setSelectionModeForInitialTrack(Constants.TRACK_SELECTION_MODE_WIDEST_RANGE);
});

it('should select track with most bitrates', function () {
testSelectInitialTrack(
'video',
[ { bandwidth: 2000 }, { bandwidth: 1000 } ],
[ { bandwidth: 2000 } ]
);
});

it('should tie break using "highestBitrate"', function () {
testSelectInitialTrack(
'video',
[ { bandwidth: 3000 }, { bandwidth: 2000 } ],
[ { bandwidth: 2000 }, { bandwidth: 1000 } ]
);
});
});
});

});

0 comments on commit 9d91e39

Please sign in to comment.