-
Notifications
You must be signed in to change notification settings - Fork 88
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #571 from bitmovin/feature/PW-10573/implementing-e…
…co-mode-toggle Implementing Eco Mode Toggle
- Loading branch information
Showing
16 changed files
with
443 additions
and
85 deletions.
There are no files selected for viewing
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
@import '../variables'; | ||
@import '../mixins'; | ||
|
||
.#{$prefix}-ui-ecomodetogglebutton { | ||
@extend %ui-button; | ||
height: 1em; | ||
min-width: 5em; | ||
|
||
&:hover { | ||
@include svg-icon-shadow; | ||
} | ||
|
||
&.#{$prefix}-on { | ||
background-image: url('../../assets/skin-modern/images/toggleOn.svg'); | ||
background-position: 20px center; | ||
background-size: 45% auto; | ||
margin-left: 2%; | ||
} | ||
|
||
&.#{$prefix}-off { | ||
background-image: url('../../assets/skin-modern/images/toggleOff.svg'); | ||
background-position: 20px center; | ||
background-size: 45% auto; | ||
} | ||
} | ||
|
||
#ecomodelabel::before { | ||
Check warning on line 27 in src/scss/skin-modern/components/_ecomodetogglebutton.scss GitHub Actions / test_and_build
|
||
background-image: url('../../assets/skin-modern/images/leaf.svg'); | ||
background-repeat: no-repeat; | ||
background-size: 1.7em auto; | ||
content: ' '; | ||
display: inline-block; | ||
height: 1.5em; | ||
width: 2em; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
import { PlayerAPI, SegmentPlaybackEvent, VideoQuality } from 'bitmovin-player'; | ||
import { i18n } from '../localization/i18n'; | ||
import { Container, ContainerConfig } from './container'; | ||
import { EcoModeToggleButton } from './ecomodetogglebutton'; | ||
import { Label, LabelConfig } from './label'; | ||
import { SettingsPanelItem } from './settingspanelitem'; | ||
|
||
export class EcoModeContainer extends Container<ContainerConfig> { | ||
private ecoModeSavedEmissionsItem: SettingsPanelItem; | ||
private ecoModeToggleButtonItem: SettingsPanelItem; | ||
private emissionsSavedLabel: Label<LabelConfig>; | ||
private savedEmissons = 0; | ||
private currentEnergyEmission: number; | ||
|
||
constructor(config: ContainerConfig = {}) { | ||
super(config); | ||
|
||
const ecoModeToggleButton = new EcoModeToggleButton(); | ||
const labelEcoMode = new Label({ | ||
text: i18n.getLocalizer('ecoMode.title'), | ||
for: ecoModeToggleButton.getConfig().id, | ||
id: 'ecomodelabel', | ||
}); | ||
this.emissionsSavedLabel = new Label({ | ||
text: `${this.savedEmissons.toFixed(4)} gCO2`, | ||
cssClass: 'ui-label-savedEnergy', | ||
}); | ||
|
||
this.ecoModeToggleButtonItem = new SettingsPanelItem(labelEcoMode, ecoModeToggleButton); | ||
this.ecoModeSavedEmissionsItem = new SettingsPanelItem('Saved Emissions', this.emissionsSavedLabel, { | ||
hidden: true, | ||
}); | ||
|
||
this.addComponent(this.ecoModeToggleButtonItem); | ||
this.addComponent(this.ecoModeSavedEmissionsItem); | ||
|
||
ecoModeToggleButton.onToggleOn.subscribe(() => { | ||
this.ecoModeSavedEmissionsItem.show(); | ||
this.onToggleCallback(); | ||
}); | ||
|
||
ecoModeToggleButton.onToggleOff.subscribe(() => { | ||
this.ecoModeSavedEmissionsItem.hide(); | ||
this.onToggleCallback(); | ||
}); | ||
} | ||
|
||
private onToggleCallback: () => void; | ||
|
||
public setOnToggleCallback(callback: () => void) { | ||
this.onToggleCallback = callback; | ||
} | ||
|
||
configure(player: PlayerAPI): void { | ||
player.on(player.exports.PlayerEvent.SegmentPlayback, (segment: SegmentPlaybackEvent) => { | ||
if (!segment.mimeType.includes('video')) { | ||
return; | ||
} | ||
|
||
const { height, width, bitrate, frameRate } = segment.mediaInfo; | ||
const { | ||
height: maxHeight, | ||
bitrate: maxBitrate, | ||
width: maxWidth, | ||
} = this.getMaxQualityAvailable(player.getAvailableVideoQualities()); | ||
|
||
const currentEnergyKwh = this.calculateEnergyConsumption(frameRate, height, width, bitrate, segment.duration); | ||
|
||
const maxEnergyKwh = this.calculateEnergyConsumption( | ||
frameRate, | ||
maxHeight, | ||
maxWidth, | ||
maxBitrate, | ||
segment.duration, | ||
); | ||
|
||
if (this.ecoModeSavedEmissionsItem.isShown()) { | ||
this.updateSavedEmissions(currentEnergyKwh, maxEnergyKwh, this.emissionsSavedLabel); | ||
} | ||
}); | ||
} | ||
|
||
updateSavedEmissions( | ||
currentEnergyConsuption: number, | ||
maxEnergyConsuption: number, | ||
emissionsSavedLabel: Label<LabelConfig>, | ||
) { | ||
// 475 is the average carbon intensity of all countries in gCO2/kWh | ||
const averageCarbonIntensity = 475; | ||
|
||
this.currentEnergyEmission = currentEnergyConsuption * averageCarbonIntensity; | ||
const maxEnergyEmisson = maxEnergyConsuption * averageCarbonIntensity; | ||
this.savedEmissons += maxEnergyEmisson - this.currentEnergyEmission; | ||
emissionsSavedLabel.setText(this.savedEmissons.toFixed(4) + ' gCO2'); | ||
} | ||
|
||
/** | ||
* The calculations are based on the following paper: https://arxiv.org/pdf/2210.05444.pdf | ||
*/ | ||
calculateEnergyConsumption(fps: number, height: number, width: number, bitrate: number, duration: number): number { | ||
const fpsWeight = 0.035; | ||
const pixeldWeight = 5.76e-9; | ||
const birateWeight = 6.97e-6; | ||
const constantOffset = 8.52; | ||
const bitrateInternetWeight = 3.24e-5; | ||
const internetConnectionOffset = 1.15; | ||
const videoCodec = 4.16; | ||
|
||
const energyConsumptionW = | ||
fpsWeight * fps + | ||
pixeldWeight * height * width + | ||
(birateWeight + bitrateInternetWeight) * (bitrate / 1000) + | ||
videoCodec + | ||
constantOffset + | ||
internetConnectionOffset; | ||
|
||
// Convert energy consumption from Watts (W) to Kilowatt-hours (kWh) for the given time duration of the segment | ||
const energyConsumptionKwh = (energyConsumptionW * duration) / 3.6e6; | ||
|
||
return energyConsumptionKwh; | ||
} | ||
getMaxQualityAvailable(availableVideoQualities: VideoQuality[]) { | ||
const sortedQualities = availableVideoQualities.sort((a, b) => a.bitrate - b.bitrate); | ||
return sortedQualities[sortedQualities.length - 1]; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
import { ToggleButton, ToggleButtonConfig } from './togglebutton'; | ||
import { UIInstanceManager } from '../uimanager'; | ||
import { DynamicAdaptationConfig, PlayerAPI, VideoQualityChangedEvent } from 'bitmovin-player'; | ||
import { i18n } from '../localization/i18n'; | ||
|
||
export class EcoModeToggleButton extends ToggleButton<ToggleButtonConfig> { | ||
private adaptationConfig: DynamicAdaptationConfig; | ||
|
||
constructor(config: ToggleButtonConfig = {}) { | ||
super(config); | ||
|
||
const defaultConfig: ToggleButtonConfig = { | ||
text: i18n.getLocalizer('ecoMode'), | ||
cssClass: 'ui-ecomodetogglebutton', | ||
onClass: 'on', | ||
offClass: 'off', | ||
ariaLabel: i18n.getLocalizer('ecoMode'), | ||
}; | ||
|
||
this.config = this.mergeConfig(config, defaultConfig, this.config); | ||
} | ||
|
||
configure(player: PlayerAPI, uimanager: UIInstanceManager): void { | ||
super.configure(player, uimanager); | ||
|
||
if (this.areAdaptationApisAvailable(player)) { | ||
this.onClick.subscribe(() => { | ||
this.toggle(); | ||
}); | ||
|
||
this.onToggleOn.subscribe(() => { | ||
this.enableEcoMode(player); | ||
player.setVideoQuality('auto'); | ||
}); | ||
|
||
this.onToggleOff.subscribe(() => { | ||
this.disableEcoMode(player); | ||
}); | ||
|
||
player.on(player.exports.PlayerEvent.VideoQualityChanged, (quality: VideoQualityChangedEvent) => { | ||
if (quality.targetQuality.id !== 'auto') { | ||
this.off(); | ||
this.disableEcoMode(player); | ||
} | ||
}); | ||
} else { | ||
super.disable(); | ||
} | ||
|
||
} | ||
|
||
private areAdaptationApisAvailable(player: PlayerAPI): boolean { | ||
const isGetConfigAvailable = Boolean(player.adaptation.getConfig && typeof player.adaptation.getConfig === 'function'); | ||
const isSetConfigAvailable = Boolean(player.adaptation.setConfig && typeof player.adaptation.setConfig === 'function'); | ||
|
||
return Boolean(player.adaptation && isGetConfigAvailable && isSetConfigAvailable); | ||
} | ||
|
||
enableEcoMode(player: PlayerAPI): void { | ||
this.adaptationConfig = player.adaptation.getConfig(); | ||
const codec = player.getAvailableVideoQualities()[0].codec; | ||
|
||
if (codec.includes('avc')) { | ||
player.adaptation.setConfig({ | ||
resolution: { maxSelectableVideoHeight: 720 }, | ||
limitToPlayerSize: true, | ||
}); | ||
} | ||
if (codec.includes('hvc') || codec.includes('hev')) { | ||
player.adaptation.setConfig({ | ||
resolution: { maxSelectableVideoHeight: 1080 }, | ||
limitToPlayerSize: true, | ||
}); | ||
} | ||
if (codec.includes('av1') || codec.includes('av01')) { | ||
player.adaptation.setConfig({ | ||
resolution: { maxSelectableVideoHeight: 1440 }, | ||
limitToPlayerSize: true, | ||
}); | ||
} | ||
} | ||
|
||
disableEcoMode(player: PlayerAPI): void { | ||
player.adaptation.setConfig(this.adaptationConfig); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.