mirror of
https://github.com/shaka-project/shaka-player.git
synced 2026-06-14 15:56:38 +03:00
196 lines
5.2 KiB
JavaScript
196 lines
5.2 KiB
JavaScript
/*! @license
|
|
* Shaka Player
|
|
* Copyright 2016 Google LLC
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
goog.provide('shaka.offline.StreamBandwidthEstimator');
|
|
|
|
goog.require('shaka.log');
|
|
goog.requireType('shaka.media.SegmentReference');
|
|
|
|
|
|
/**
|
|
* A utility class to help estimate the size of streams based on stream and
|
|
* variant bandwidths. This class's main purpose is to isolate the logic in
|
|
* creating non-zero bandwidth estimates for all streams so that each stream
|
|
* will have some influence over the progress of the download.
|
|
*/
|
|
shaka.offline.StreamBandwidthEstimator = class {
|
|
/** */
|
|
constructor() {
|
|
/** @private {!Object.<number, number>} */
|
|
this.estimateByStreamId_ = {};
|
|
}
|
|
|
|
/**
|
|
* Add a new variant to the estimator. This will update the estimates for all
|
|
* streams in the variant.
|
|
*
|
|
* @param {shaka.extern.Variant} variant
|
|
*/
|
|
addVariant(variant) {
|
|
// Three cases:
|
|
// 1 - Only Audio
|
|
// 2 - Only Video
|
|
// 3 - Audio and Video
|
|
|
|
const audio = variant.audio;
|
|
const video = variant.video;
|
|
|
|
// Case 1
|
|
if (audio && !video) {
|
|
const audioBitRate = audio.bandwidth || variant.bandwidth;
|
|
this.setBitrate_(audio.id, audioBitRate);
|
|
}
|
|
|
|
// Case 2
|
|
if (!audio && video) {
|
|
const videoBitRate = video.bandwidth || variant.bandwidth;
|
|
this.setBitrate_(video.id, videoBitRate);
|
|
}
|
|
|
|
// Case 3
|
|
if (audio && video) {
|
|
// Get the audio's bandwidth. If it is missing, default to our default
|
|
// audio bandwidth.
|
|
const audioBitRate =
|
|
audio.bandwidth ||
|
|
shaka.offline.StreamBandwidthEstimator.DEFAULT_AUDIO_BITRATE_;
|
|
|
|
// Get the video's bandwidth. If it is missing, use the variant bandwidth
|
|
// less the audio. If we get a negative bit rate, fall back to our
|
|
// default video bandwidth.
|
|
let videoBitRate = video.bandwidth || (variant.bandwidth - audioBitRate);
|
|
if (videoBitRate <= 0) {
|
|
shaka.log.warning(
|
|
'Audio bit rate consumes variants bandwidth. Setting video ' +
|
|
'bandwidth to match variant\'s bandwidth.');
|
|
videoBitRate = variant.bandwidth;
|
|
}
|
|
|
|
this.setBitrate_(audio.id, audioBitRate);
|
|
this.setBitrate_(video.id, videoBitRate);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param {number} stream
|
|
* @param {number} bitRate
|
|
* @private
|
|
*/
|
|
setBitrate_(stream, bitRate) {
|
|
this.estimateByStreamId_[stream] = bitRate;
|
|
}
|
|
|
|
/**
|
|
* Create an estimate for the text stream.
|
|
*
|
|
* @param {shaka.extern.Stream} text
|
|
*/
|
|
addText(text) {
|
|
this.estimateByStreamId_[text.id] =
|
|
shaka.offline.StreamBandwidthEstimator.DEFAULT_TEXT_BITRATE_;
|
|
}
|
|
|
|
/**
|
|
* Create an estimate for the image stream.
|
|
*
|
|
* @param {shaka.extern.Stream} image
|
|
*/
|
|
addImage(image) {
|
|
this.estimateByStreamId_[image.id] = image.bandwidth ||
|
|
shaka.offline.StreamBandwidthEstimator.DEFAULT_IMAGE_BITRATE_;
|
|
}
|
|
|
|
/**
|
|
* Get the estimate for a segment that is part of a stream that has already
|
|
* added to the estimator.
|
|
*
|
|
* @param {number} id
|
|
* @param {!shaka.media.SegmentReference} segment
|
|
* @return {number}
|
|
*/
|
|
getSegmentEstimate(id, segment) {
|
|
const duration = segment.endTime - segment.startTime;
|
|
return this.getEstimate_(id) * duration;
|
|
}
|
|
|
|
/**
|
|
* Get the estimate for an init segment for a stream that has already
|
|
* added to the estimator.
|
|
*
|
|
* @param {number} id
|
|
* @return {number}
|
|
*/
|
|
getInitSegmentEstimate(id) {
|
|
// Assume that the init segment is worth approximately half a second of
|
|
// content.
|
|
const duration = 0.5;
|
|
return this.getEstimate_(id) * duration;
|
|
}
|
|
|
|
/**
|
|
* @param {number} id
|
|
* @return {number}
|
|
* @private
|
|
*/
|
|
getEstimate_(id) {
|
|
let bitRate = this.estimateByStreamId_[id];
|
|
|
|
if (bitRate == null) {
|
|
bitRate = 0;
|
|
shaka.log.error(
|
|
'Asking for bitrate of stream not given to the estimator');
|
|
}
|
|
|
|
if (bitRate == 0) {
|
|
shaka.log.warning(
|
|
'Using bitrate of 0, this stream won\'t affect progress');
|
|
}
|
|
|
|
return bitRate;
|
|
}
|
|
};
|
|
|
|
|
|
/**
|
|
* Since audio bandwidth does not vary much, we are going to use a constant
|
|
* approximation for audio bit rate allowing use to more accurately guess at
|
|
* the video bitrate.
|
|
*
|
|
* YouTube's suggested bitrate for stereo audio is 384 kbps so we are going to
|
|
* assume that: https://support.google.com/youtube/answer/1722171?hl=en
|
|
*
|
|
* @const {number}
|
|
* @private
|
|
*/
|
|
shaka.offline.StreamBandwidthEstimator.DEFAULT_AUDIO_BITRATE_ = 393216;
|
|
|
|
|
|
/**
|
|
* Since we don't normally get the bitrate for text, we still want to create
|
|
* some approximation so that it can influence progress. This will use the
|
|
* bitrate from "Tears of Steal" to give some kind of data-driven result.
|
|
*
|
|
* The file size for English subtitles is 4.7 KB. The video is 12:14 long,
|
|
* which means that the text's bit rate is around 52 bps.
|
|
*
|
|
* @const {number}
|
|
* @private
|
|
*/
|
|
shaka.offline.StreamBandwidthEstimator.DEFAULT_TEXT_BITRATE_ = 52;
|
|
|
|
|
|
/**
|
|
* Since we don't normally get the bitrate for image, we still want to create
|
|
* some approximation so that it can influence progress.
|
|
*
|
|
* The size of the thumbnail usually is 2KB.
|
|
*
|
|
* @const {number}
|
|
* @private
|
|
*/
|
|
shaka.offline.StreamBandwidthEstimator.DEFAULT_IMAGE_BITRATE_ = 2048;
|
|
|