Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add preferredVideoHdrLevel config. #5370

Merged
merged 8 commits into from
Jun 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions demo/common/message_ids.js
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,12 @@ shakaDemo.MessageIds = {
FORCE_TRANSMUX: 'DEMO_FORCE_TRANSMUX',
FUZZ_FACTOR: 'DEMO_FUZZ_FACTOR',
GAP_DETECTION_THRESHOLD: 'DEMO_GAP_DETECTION_THRESHOLD',
HDR_LEVEL: 'DEMO_HDR_LEVEL',
HDR_LEVEL_AUTO: 'DEMO_HDR_LEVEL_AUTO',
HDR_LEVEL_HLG: 'DEMO_HDR_LEVEL_HLG',
HDR_LEVEL_NONE: 'DEMO_HDR_LEVEL_NONE',
HDR_LEVEL_PQ: 'DEMO_HDR_LEVEL_PQ',
HDR_LEVEL_SDR: 'DEMO_HDR_LEVEL_SDR',
HLS_SEQUENCE_MODE: 'DEMO_HLS_SEQUENCE_MODE',
IGNORE_DASH_EMPTY_ADAPTATION_SET: 'DEMO_IGNORE_DASH_EMPTY_ADAPTATION_SET',
IGNORE_DASH_DRM: 'DEMO_IGNORE_DASH_DRM',
Expand Down
18 changes: 18 additions & 0 deletions demo/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -456,6 +456,24 @@ shakaDemo.Config = class {
this.latestInput_.input().checked = true;
}

const hdrLevels = {
'': '',
'AUTO': 'AUTO',
'SDR': 'SDR',
'PQ': 'PQ',
'HLG': 'HLG',
};
const localize = (name) => shakaDemoMain.getLocalizedString(name);
const hdrLevelNames = {
'AUTO': localize(MessageIds.HDR_LEVEL_AUTO),
'SDR': localize(MessageIds.HDR_LEVEL_SDR),
'PQ': localize(MessageIds.HDR_LEVEL_PQ),
'HLG': localize(MessageIds.HDR_LEVEL_HLG),
'': localize(MessageIds.HDR_LEVEL_NONE),
};
this.addSelectInput_(MessageIds.HDR_LEVEL, 'preferredVideoHdrLevel',
hdrLevels, hdrLevelNames);

this.addBoolInput_(MessageIds.START_AT_SEGMENT_BOUNDARY,
'streaming.startAtSegmentBoundary')
.addBoolInput_(MessageIds.IGNORE_TEXT_FAILURES,
Expand Down
6 changes: 6 additions & 0 deletions demo/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,12 @@
"DEMO_GAP_DETECTION_THRESHOLD": "Gap detection threshold",
"DEMO_GPAC": "GPAC",
"DEMO_HEADERS_TAB": "Headers",
"DEMO_HDR_LEVEL": "Preferred HDR Level",
"DEMO_HDR_LEVEL_AUTO": "Auto Detect",
"DEMO_HDR_LEVEL_HLG": "HLG",
"DEMO_HDR_LEVEL_NONE": "No Preference",
"DEMO_HDR_LEVEL_PQ": "PQ",
"DEMO_HDR_LEVEL_SDR": "SDR",
"DEMO_HIGH_DEFINITION": "High definition",
"DEMO_HIGH_DEFINITION_SEARCH": "Filters for assets with at least one high-definition video stream.",
"DEMO_HLS": "HLS",
Expand Down
24 changes: 24 additions & 0 deletions demo/locales/source.json
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,30 @@
"description": "The header for a tab within the custom asset creation dialog.",
"message": "Headers"
},
"DEMO_HDR_LEVEL": {
"description": "The name of a configuration value.",
"message": "Preferred HDR Level"
},
"DEMO_HDR_LEVEL_AUTO": {
"description": "The name of a configuration value.",
"message": "Auto Detect"
},
"DEMO_HDR_LEVEL_HLG": {
"description": "The name of a configuration value.",
"message": "[PROPER_NAME:HLG]"
},
"DEMO_HDR_LEVEL_NONE": {
"description": "The name of a configuration value.",
"message": "No Preference"
},
"DEMO_HDR_LEVEL_PQ": {
"description": "The name of a configuration value.",
"message": "[PROPER_NAME:PQ]"
},
"DEMO_HDR_LEVEL_SDR": {
"description": "The name of a configuration value.",
"message": "[PROPER_NAME:SDR]"
},
"DEMO_HIGH_DEFINITION": {
"description": "Text that describes an asset that has a high definition video stream.",
"message": "High definition"
Expand Down
5 changes: 4 additions & 1 deletion demo/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -1394,7 +1394,10 @@ shakaDemo.Main = class {
// NaN != NaN, so there has to be a special check for it to prevent
// false positives.
const bothAreNaN = isNaN(currentValue) && isNaN(defaultValue);
if (currentValue != defaultValue && !bothAreNaN) {
// Strings count as NaN too, so check for them specifically.
const bothAreStrings = (typeof currentValue) == 'string' &&
(typeof defaultValue) == 'string';
if (currentValue != defaultValue && (!bothAreNaN || bothAreStrings)) {
// Don't bother saving in the hash unless it's a non-default value.
params.push(hashName + '=' + currentValue);
}
Expand Down
9 changes: 9 additions & 0 deletions externs/shaka/player.js
Original file line number Diff line number Diff line change
Expand Up @@ -1472,6 +1472,7 @@ shaka.extern.OfflineConfiguration;
* preferredVideoCodecs: !Array.<string>,
* preferredAudioCodecs: !Array.<string>,
* preferredAudioChannelCount: number,
* preferredVideoHdrLevel: string,
* preferredDecodingAttributes: !Array.<string>,
* preferForcedSubs: boolean,
* restrictions: shaka.extern.Restrictions,
Expand Down Expand Up @@ -1524,6 +1525,14 @@ shaka.extern.OfflineConfiguration;
* The list of preferred audio codecs, in order of highest to lowest priority.
* @property {number} preferredAudioChannelCount
* The preferred number of audio channels.
* @property {string} preferredVideoHdrLevel
* The preferred HDR level of the video. If possible, this will cause the
* player to filter to assets that either have that HDR level, or no HDR level
* at all.
* Can be 'SDR', 'PQ', 'HLG', 'AUTO' for auto-detect, or '' for no preference.
* Defaults to 'AUTO'.
* Note that one some platforms, such as Chrome, attempting to play PQ content
* may cause problems.
* @property {!Array.<string>} preferredDecodingAttributes
* The list of preferred attributes of decodingInfo, in the order of their
* priorities.
Expand Down
44 changes: 42 additions & 2 deletions lib/media/adaptation_set_criteria.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,14 @@ shaka.media.ExampleBasedCriteria = class {
// role and label for this.
const role = '';
const label = '';
const hdrLevel = '';
const channelCount = example.audio && example.audio.channelsCount ?
example.audio.channelsCount :
0;

/** @private {!shaka.media.AdaptationSetCriteria} */
this.fallback_ = new shaka.media.PreferenceBasedCriteria(
example.language, role, channelCount, label);
example.language, role, channelCount, hdrLevel, label);
}

/** @override */
Expand Down Expand Up @@ -87,16 +88,19 @@ shaka.media.PreferenceBasedCriteria = class {
* @param {string} language
* @param {string} role
* @param {number} channelCount
* @param {string} hdrLevel
* @param {string=} label
*/
constructor(language, role, channelCount, label = '') {
constructor(language, role, channelCount, hdrLevel, label = '') {
/** @private {string} */
this.language_ = language;
/** @private {string} */
this.role_ = role;
/** @private {number} */
this.channelCount_ = channelCount;
/** @private {string} */
this.hdrLevel_ = hdrLevel;
/** @private {string} */
this.label_ = label;
}

Expand Down Expand Up @@ -127,6 +131,17 @@ shaka.media.PreferenceBasedCriteria = class {
shaka.log.warning('No exact match for variant role could be found.');
}

if (this.hdrLevel_) {
const byHdrLevel = Class.filterVariantsByHDRLevel_(
current, this.hdrLevel_);
if (byHdrLevel.length) {
current = byHdrLevel;
} else {
shaka.log.warning(
'No exact match for the hdr level could be found.');
}
}

if (this.channelCount_) {
const byChannel = StreamUtils.filterVariantsByAudioChannelCount(
current, this.channelCount_);
Expand Down Expand Up @@ -227,4 +242,29 @@ shaka.media.PreferenceBasedCriteria = class {
return label1 == label2;
});
}


/**
* Filters variants according to the given hdr level config.
*
* @param {!Array.<shaka.extern.Variant>} variants
* @param {string} hdrLevel
* @private
*/
static filterVariantsByHDRLevel_(variants, hdrLevel) {
if (hdrLevel == 'AUTO') {
// Auto detect the ideal HDR level.
if (window.matchMedia('(color-gamut: p3)').matches) {
hdrLevel = 'PQ';
} else {
hdrLevel = 'SDR';
}
}
return variants.filter((variant) => {
if (variant.video && variant.video.hdr && variant.video.hdr != hdrLevel) {
return false;
}
return true;
});
}
};
8 changes: 5 additions & 3 deletions lib/player.js
Original file line number Diff line number Diff line change
Expand Up @@ -588,7 +588,8 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
new shaka.media.PreferenceBasedCriteria(
this.config_.preferredAudioLanguage,
this.config_.preferredVariantRole,
this.config_.preferredAudioChannelCount);
this.config_.preferredAudioChannelCount,
this.config_.preferredVideoHdrLevel);

/** @private {string} */
this.currentTextLanguage_ = this.config_.preferredTextLanguage;
Expand Down Expand Up @@ -2108,6 +2109,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
this.config_.preferredAudioLanguage,
this.config_.preferredVariantRole,
this.config_.preferredAudioChannelCount,
this.config_.preferredVideoHdrLevel,
this.config_.preferredAudioLabel);

this.currentTextLanguage_ = this.config_.preferredTextLanguage;
Expand Down Expand Up @@ -4197,7 +4199,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
if (this.manifest_ && this.playhead_) {
this.currentAdaptationSetCriteria_ =
new shaka.media.PreferenceBasedCriteria(language, role || '',
channelsCount, /* label= */ '');
channelsCount, /* hdrLevel= */ '', /* label= */ '');

const diff = (a, b) => {
if (!a.video && !b.video) {
Expand Down Expand Up @@ -4344,7 +4346,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
// label have the same language.
this.currentAdaptationSetCriteria_ =
new shaka.media.PreferenceBasedCriteria(
firstVariantWithLabel.language, '', 0, label);
firstVariantWithLabel.language, '', 0, '', label);

this.chooseVariantAndSwitch_(clearBuffer, safeMargin);
} else if (this.video_ && this.video_.audioTracks) {
Expand Down
1 change: 1 addition & 0 deletions lib/util/player_configuration.js
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,7 @@ shaka.util.PlayerConfiguration = class {
preferredVariantRole: '',
preferredTextRole: '',
preferredAudioChannelCount: 2,
preferredVideoHdrLevel: 'AUTO',
preferredVideoCodecs: [],
preferredAudioCodecs: [],
preferForcedSubs: false,
Expand Down
4 changes: 2 additions & 2 deletions lib/util/stream_utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ shaka.util.StreamUtils = class {
const StreamUtils = shaka.util.StreamUtils;

let variants = manifest.variants;

// To start, choose the codecs based on configured preferences if available.
if (preferredVideoCodecs.length || preferredAudioCodecs.length) {
variants = StreamUtils.choosePreferredCodecs(variants,
Expand Down Expand Up @@ -404,8 +405,7 @@ shaka.util.StreamUtils = class {
* @param {?shaka.extern.Variant} currentVariant
* @param {shaka.extern.Manifest} manifest
*/
static async filterManifest(
drmEngine, currentVariant, manifest) {
static async filterManifest(drmEngine, currentVariant, manifest) {
await shaka.util.StreamUtils.filterManifestByMediaCapabilities(manifest,
manifest.offlineSessionIds.length > 0);
shaka.util.StreamUtils.filterManifestByCurrentVariant(
Expand Down
Loading