mirror of
https://github.com/DanielnetoDotCom/YouPHPTube
synced 2025-10-05 19:42:38 +02:00
Update npm
This commit is contained in:
parent
8341712d58
commit
1bd85100b9
5320 changed files with 58396 additions and 344722 deletions
49
node_modules/@videojs/http-streaming/CHANGELOG.md
generated
vendored
49
node_modules/@videojs/http-streaming/CHANGELOG.md
generated
vendored
|
@ -1,3 +1,52 @@
|
|||
<a name="3.12.0"></a>
|
||||
# [3.12.0](https://github.com/videojs/http-streaming/compare/v3.11.3...v3.12.0) (2024-03-12)
|
||||
|
||||
### Features
|
||||
|
||||
* Custom Pixel Ratio ([#1497](https://github.com/videojs/http-streaming/issues/1497)) ([0e9d9d8](https://github.com/videojs/http-streaming/commit/0e9d9d8))
|
||||
|
||||
### Chores
|
||||
|
||||
* **demo:** Remove error on iOS on demo page ([#1493](https://github.com/videojs/http-streaming/issues/1493)) ([c50ba7e](https://github.com/videojs/http-streaming/commit/c50ba7e))
|
||||
* update mux.js to v7.0.3 ([#1498](https://github.com/videojs/http-streaming/issues/1498)) ([bebcafd](https://github.com/videojs/http-streaming/commit/bebcafd))
|
||||
|
||||
<a name="3.11.3"></a>
|
||||
## [3.11.3](https://github.com/videojs/http-streaming/compare/v3.11.2...v3.11.3) (2024-02-28)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* fix repeated segments ([#1489](https://github.com/videojs/http-streaming/issues/1489)) ([ed8f6bd](https://github.com/videojs/http-streaming/commit/ed8f6bd))
|
||||
|
||||
<a name="3.11.2"></a>
|
||||
## [3.11.2](https://github.com/videojs/http-streaming/compare/v3.11.1...v3.11.2) (2024-02-21)
|
||||
|
||||
### Reverts
|
||||
|
||||
* "fix: fix repeated segments issue during bandwidth update ([#1477](https://github.com/videojs/http-streaming/issues/1477))" ([#1488](https://github.com/videojs/http-streaming/issues/1488)) ([75f7b1a](https://github.com/videojs/http-streaming/commit/75f7b1a))
|
||||
|
||||
<a name="3.11.1"></a>
|
||||
## [3.11.1](https://github.com/videojs/http-streaming/compare/v3.11.0...v3.11.1) (2024-02-12)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* changeType on full codec change only ([#1474](https://github.com/videojs/http-streaming/issues/1474)) ([4e51778](https://github.com/videojs/http-streaming/commit/4e51778))
|
||||
|
||||
### Chores
|
||||
|
||||
* Replace old quality selector ([#1482](https://github.com/videojs/http-streaming/issues/1482)) ([64376db](https://github.com/videojs/http-streaming/commit/64376db))
|
||||
|
||||
<a name="3.11.0"></a>
|
||||
# [3.11.0](https://github.com/videojs/http-streaming/compare/v3.10.0...v3.11.0) (2024-01-25)
|
||||
|
||||
### Features
|
||||
|
||||
* add request types ([#1479](https://github.com/videojs/http-streaming/issues/1479)) ([5b87f69](https://github.com/videojs/http-streaming/commit/5b87f69))
|
||||
* error type enhancement ([#1478](https://github.com/videojs/http-streaming/issues/1478)) ([8f3a4d1](https://github.com/videojs/http-streaming/commit/8f3a4d1))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* fix repeated segments issue during bandwidth update ([#1477](https://github.com/videojs/http-streaming/issues/1477)) ([823f072](https://github.com/videojs/http-streaming/commit/823f072))
|
||||
|
||||
<a name="3.10.0"></a>
|
||||
# [3.10.0](https://github.com/videojs/http-streaming/compare/v3.9.1...v3.10.0) (2024-01-17)
|
||||
|
||||
|
|
13
node_modules/@videojs/http-streaming/README.md
generated
vendored
13
node_modules/@videojs/http-streaming/README.md
generated
vendored
|
@ -48,6 +48,7 @@ Video.js Compatibility: 7.x, 8.x
|
|||
- [enableLowInitialPlaylist](#enablelowinitialplaylist)
|
||||
- [limitRenditionByPlayerDimensions](#limitrenditionbyplayerdimensions)
|
||||
- [useDevicePixelRatio](#usedevicepixelratio)
|
||||
- [customPixelRatio](#custompixelratio)
|
||||
- [allowSeeksWithinUnsafeLiveWindow](#allowseekswithinunsafelivewindow)
|
||||
- [customTagParsers](#customtagparsers)
|
||||
- [customTagMappers](#customtagmappers)
|
||||
|
@ -404,6 +405,18 @@ This setting is `true` by default.
|
|||
If true, this will take the device pixel ratio into account when doing rendition switching. This means that if you have a player with the width of `540px` in a high density display with a device pixel ratio of 2, a rendition of `1080p` will be allowed.
|
||||
This setting is `false` by default.
|
||||
|
||||
##### customPixelRatio
|
||||
* Type: `number`
|
||||
* can be used as an initialization option.
|
||||
|
||||
If set, this will take the initial player dimensions and multiply it by a custom ratio when the player automatically selects renditions. This means that if you have a player where the dimension is `540p`, with a custom pixel ratio of `2`, a rendition of `1080p` or a lower rendition closest to this value will be chosen. Additionally, if you have a player where the dimension is `540p`, with a custom pixel ratio of `0.5`, a rendition of `270p` or a lower rendition closest to this value will be chosen. When the custom pixel ratio is 0, the lowest available rendition will be selected.
|
||||
|
||||
It is worth noting that if the player dimension multiplied by the custom pixel ratio is greater than any available rendition resolution, a rendition will be selected based on bandwidth, and the player dimension will be disregarded.
|
||||
|
||||
`limitRenditionByPlayerDimensions` must be `true` in order for this feature to be enabled. This is the default value.
|
||||
|
||||
If `useDevicePixelRatio` is set to `true`, the custom pixel ratio will be prioritized and overwrite any previous pixel ratio.
|
||||
|
||||
##### allowSeeksWithinUnsafeLiveWindow
|
||||
* Type: `boolean`
|
||||
* can be used as a source option
|
||||
|
|
731
node_modules/@videojs/http-streaming/dist/videojs-http-streaming-sync-workers.js
generated
vendored
731
node_modules/@videojs/http-streaming/dist/videojs-http-streaming-sync-workers.js
generated
vendored
File diff suppressed because it is too large
Load diff
731
node_modules/@videojs/http-streaming/dist/videojs-http-streaming.cjs.js
generated
vendored
731
node_modules/@videojs/http-streaming/dist/videojs-http-streaming.cjs.js
generated
vendored
File diff suppressed because it is too large
Load diff
731
node_modules/@videojs/http-streaming/dist/videojs-http-streaming.es.js
generated
vendored
731
node_modules/@videojs/http-streaming/dist/videojs-http-streaming.es.js
generated
vendored
File diff suppressed because it is too large
Load diff
731
node_modules/@videojs/http-streaming/dist/videojs-http-streaming.js
generated
vendored
731
node_modules/@videojs/http-streaming/dist/videojs-http-streaming.js
generated
vendored
File diff suppressed because it is too large
Load diff
10
node_modules/@videojs/http-streaming/dist/videojs-http-streaming.min.js
generated
vendored
10
node_modules/@videojs/http-streaming/dist/videojs-http-streaming.min.js
generated
vendored
File diff suppressed because one or more lines are too long
2
node_modules/@videojs/http-streaming/index.html
generated
vendored
2
node_modules/@videojs/http-streaming/index.html
generated
vendored
|
@ -6,7 +6,7 @@
|
|||
<link rel="icon" href="logo.svg">
|
||||
<link href="node_modules/bootstrap/dist/css/bootstrap.css" rel="stylesheet">
|
||||
<link href="node_modules/video.js/dist/video-js.css" rel="stylesheet">
|
||||
<link href="node_modules/videojs-http-source-selector/dist/videojs-http-source-selector.css" rel="stylesheet">
|
||||
<link href="node_modules/jb-videojs-hls-quality-selector/dist/videojs-hls-quality-selector.css" rel="stylesheet">
|
||||
<style>
|
||||
.form-check {
|
||||
background-color: hsl(0, 0%, 90%);
|
||||
|
|
8
node_modules/@videojs/http-streaming/package.json
generated
vendored
8
node_modules/@videojs/http-streaming/package.json
generated
vendored
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@videojs/http-streaming",
|
||||
"version": "3.10.0",
|
||||
"version": "3.12.0",
|
||||
"description": "Play back HLS and DASH with Video.js, even where it's not natively supported",
|
||||
"main": "dist/videojs-http-streaming.cjs.js",
|
||||
"module": "dist/videojs-http-streaming.es.js",
|
||||
|
@ -63,11 +63,11 @@
|
|||
"global": "^4.4.0",
|
||||
"m3u8-parser": "^7.1.0",
|
||||
"mpd-parser": "^1.3.0",
|
||||
"mux.js": "7.0.2",
|
||||
"mux.js": "7.0.3",
|
||||
"video.js": "^7 || ^8"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"video.js": "^7 || ^8"
|
||||
"video.js": "^8.11.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/cli": "^7.21.0",
|
||||
|
@ -77,6 +77,7 @@
|
|||
"@videojs/generator-helpers": "~3.1.0",
|
||||
"bootstrap": "^5.1.0",
|
||||
"d3": "^3.4.8",
|
||||
"jb-videojs-hls-quality-selector": "^2.0.2",
|
||||
"jsdoc": "^3.6.11",
|
||||
"karma": "^6.4.0",
|
||||
"lodash": "^4.17.4",
|
||||
|
@ -92,7 +93,6 @@
|
|||
"videojs-generate-karma-config": "^8.0.1",
|
||||
"videojs-generate-rollup-config": "^7.0.0",
|
||||
"videojs-generator-verify": "~3.0.1",
|
||||
"videojs-http-source-selector": "^1.1.6",
|
||||
"videojs-standard": "^9.0.0",
|
||||
"water-plant-uml": "^2.0.2"
|
||||
},
|
||||
|
|
9
node_modules/@videojs/http-streaming/scripts/index.js
generated
vendored
9
node_modules/@videojs/http-streaming/scripts/index.js
generated
vendored
|
@ -438,7 +438,7 @@
|
|||
var steeringManifestEl = document.querySelector('.steering-manifest');
|
||||
|
||||
player.one('loadedmetadata', function() {
|
||||
var steeringController = player.tech_.vhs.playlistController_.contentSteeringController_;
|
||||
var steeringController = player.tech_.vhs && player.tech_.vhs.playlistController_.contentSteeringController_;
|
||||
|
||||
if (!steeringController) {
|
||||
return;
|
||||
|
@ -559,7 +559,8 @@
|
|||
'node_modules/video.js/dist/alt/video.core',
|
||||
'node_modules/videojs-contrib-eme/dist/videojs-contrib-eme',
|
||||
'node_modules/videojs-contrib-quality-levels/dist/videojs-contrib-quality-levels',
|
||||
'node_modules/videojs-http-source-selector/dist/videojs-http-source-selector'
|
||||
'node_modules/jb-videojs-hls-quality-selector/dist/jb-videojs-hls-quality-selector'
|
||||
|
||||
].map(function(url) {
|
||||
return url + (event.target.checked ? '.min' : '') + '.js';
|
||||
});
|
||||
|
@ -594,8 +595,8 @@
|
|||
|
||||
player = window.player = window.videojs(videoEl, {
|
||||
plugins: {
|
||||
httpSourceSelector: {
|
||||
default: 'auto'
|
||||
hlsQualitySelector: {
|
||||
displayCurrentQuality: true
|
||||
}
|
||||
},
|
||||
liveui: stateEls.liveui.checked,
|
||||
|
|
6
node_modules/@videojs/http-streaming/scripts/netlify.js
generated
vendored
6
node_modules/@videojs/http-streaming/scripts/netlify.js
generated
vendored
|
@ -10,9 +10,9 @@ const files = [
|
|||
'node_modules/videojs-contrib-eme/dist/videojs-contrib-eme.min.js',
|
||||
'node_modules/videojs-contrib-quality-levels/dist/videojs-contrib-quality-levels.js',
|
||||
'node_modules/videojs-contrib-quality-levels/dist/videojs-contrib-quality-levels.min.js',
|
||||
'node_modules/videojs-http-source-selector/dist/videojs-http-source-selector.css',
|
||||
'node_modules/videojs-http-source-selector/dist/videojs-http-source-selector.js',
|
||||
'node_modules/videojs-http-source-selector/dist/videojs-http-source-selector.min.js',
|
||||
'node_modules/jb-videojs-hls-quality-selector/dist/videojs-hls-quality-selector.css',
|
||||
'node_modules/jb-videojs-hls-quality-selector/dist/jb-videojs-hls-quality-selector.js',
|
||||
'node_modules/jb-videojs-hls-quality-selector/dist/jb-videojs-hls-quality-selector.min.js',
|
||||
'node_modules/bootstrap/dist/js/bootstrap.js',
|
||||
'node_modules/bootstrap/dist/css/bootstrap.css',
|
||||
'node_modules/d3/d3.min.js',
|
||||
|
|
3
node_modules/@videojs/http-streaming/src/content-steering-controller.js
generated
vendored
3
node_modules/@videojs/http-streaming/src/content-steering-controller.js
generated
vendored
|
@ -171,7 +171,8 @@ export default class ContentSteeringController extends videojs.EventTarget {
|
|||
}
|
||||
|
||||
this.request_ = this.xhr_({
|
||||
uri
|
||||
uri,
|
||||
requestType: 'content-steering-manifest'
|
||||
}, (error, errorInfo) => {
|
||||
if (error) {
|
||||
// If the client receives HTTP 410 Gone in response to a manifest request,
|
||||
|
|
24
node_modules/@videojs/http-streaming/src/dash-playlist-loader.js
generated
vendored
24
node_modules/@videojs/http-streaming/src/dash-playlist-loader.js
generated
vendored
|
@ -361,7 +361,8 @@ export default class DashPlaylistLoader extends EventTarget {
|
|||
message: 'DASH request error at URL: ' + request.uri,
|
||||
response: request.response,
|
||||
// MEDIA_ERR_NETWORK
|
||||
code: 2
|
||||
code: 2,
|
||||
metadata: err.metadata
|
||||
};
|
||||
if (startingState) {
|
||||
this.state = startingState;
|
||||
|
@ -390,6 +391,7 @@ export default class DashPlaylistLoader extends EventTarget {
|
|||
const uri = resolveManifestRedirect(playlist.sidx.resolvedUri);
|
||||
|
||||
const fin = (err, request) => {
|
||||
// TODO: add error metdata here once we create an error type in video.js
|
||||
if (this.requestErrored_(err, request, startingState)) {
|
||||
return;
|
||||
}
|
||||
|
@ -400,6 +402,10 @@ export default class DashPlaylistLoader extends EventTarget {
|
|||
try {
|
||||
sidx = parseSidx(toUint8(request.response).subarray(8));
|
||||
} catch (e) {
|
||||
e.metadata = {
|
||||
errorType: videojs.Error.DashManifestSidxParsingError
|
||||
};
|
||||
|
||||
// sidx parsing failed.
|
||||
this.requestErrored_(e, request, startingState);
|
||||
return;
|
||||
|
@ -421,9 +427,11 @@ export default class DashPlaylistLoader extends EventTarget {
|
|||
}
|
||||
|
||||
if (!container || container !== 'mp4') {
|
||||
const sidxContainer = container || 'unknown';
|
||||
|
||||
return fin({
|
||||
status: request.status,
|
||||
message: `Unsupported ${container || 'unknown'} container type for sidx segment at URL: ${uri}`,
|
||||
message: `Unsupported ${sidxContainer} container type for sidx segment at URL: ${uri}`,
|
||||
// response is just bytes in this case
|
||||
// but we really don't want to return that.
|
||||
response: '',
|
||||
|
@ -431,7 +439,11 @@ export default class DashPlaylistLoader extends EventTarget {
|
|||
internal: true,
|
||||
playlistExclusionDuration: Infinity,
|
||||
// MEDIA_ERR_NETWORK
|
||||
code: 2
|
||||
code: 2,
|
||||
metadata: {
|
||||
errorType: videojs.Error.UnsupportedSidxContainer,
|
||||
sidxContainer
|
||||
}
|
||||
}, request);
|
||||
}
|
||||
|
||||
|
@ -636,7 +648,8 @@ export default class DashPlaylistLoader extends EventTarget {
|
|||
requestMain_(cb) {
|
||||
this.request = this.vhs_.xhr({
|
||||
uri: this.mainPlaylistLoader_.srcUrl,
|
||||
withCredentials: this.withCredentials
|
||||
withCredentials: this.withCredentials,
|
||||
requestType: 'dash-manifest'
|
||||
}, (error, req) => {
|
||||
if (this.requestErrored_(error, req)) {
|
||||
if (this.state === 'HAVE_NOTHING') {
|
||||
|
@ -695,7 +708,8 @@ export default class DashPlaylistLoader extends EventTarget {
|
|||
this.request = this.vhs_.xhr({
|
||||
uri: resolveUrl(this.mainPlaylistLoader_.srcUrl, utcTiming.value),
|
||||
method: utcTiming.method,
|
||||
withCredentials: this.withCredentials
|
||||
withCredentials: this.withCredentials,
|
||||
requestType: 'dash-clock-sync'
|
||||
}, (error, req) => {
|
||||
// disposed
|
||||
if (!this.request) {
|
||||
|
|
22
node_modules/@videojs/http-streaming/src/media-segment-request.js
generated
vendored
22
node_modules/@videojs/http-streaming/src/media-segment-request.js
generated
vendored
|
@ -1,3 +1,4 @@
|
|||
import videojs from 'video.js';
|
||||
import { createTransferableMessage } from './bin-utils';
|
||||
import { stringToArrayBuffer } from './util/string-to-array-buffer';
|
||||
import { transmux } from './segment-transmuxer';
|
||||
|
@ -159,11 +160,16 @@ const parseInitSegment = (segment, callback) => {
|
|||
// only know how to parse mp4 init segments at the moment
|
||||
if (type !== 'mp4') {
|
||||
const uri = segment.map.resolvedUri || segment.map.uri;
|
||||
const mediaType = type || 'unknown';
|
||||
|
||||
return callback({
|
||||
internal: true,
|
||||
message: `Found unsupported ${type || 'unknown'} container for initialization segment at URL: ${uri}`,
|
||||
code: REQUEST_ERRORS.FAILURE
|
||||
message: `Found unsupported ${mediaType} container for initialization segment at URL: ${uri}`,
|
||||
code: REQUEST_ERRORS.FAILURE,
|
||||
metadata: {
|
||||
errorType: videojs.Error.UnsupportedMediaInitialization,
|
||||
mediaType
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -988,7 +994,8 @@ export const mediaSegmentRequest = ({
|
|||
}
|
||||
const keyRequestOptions = merge(xhrOptions, {
|
||||
uri: segment.key.resolvedUri,
|
||||
responseType: 'arraybuffer'
|
||||
responseType: 'arraybuffer',
|
||||
requestType: 'segment-key'
|
||||
});
|
||||
const keyRequestCallback = handleKeyResponse(segment, objects, finishProcessingFn);
|
||||
const keyXhr = xhr(keyRequestOptions, keyRequestCallback);
|
||||
|
@ -1003,7 +1010,8 @@ export const mediaSegmentRequest = ({
|
|||
if (differentMapKey) {
|
||||
const mapKeyRequestOptions = merge(xhrOptions, {
|
||||
uri: segment.map.key.resolvedUri,
|
||||
responseType: 'arraybuffer'
|
||||
responseType: 'arraybuffer',
|
||||
requestType: 'segment-key'
|
||||
});
|
||||
const mapKeyRequestCallback = handleKeyResponse(segment, [segment.map.key], finishProcessingFn);
|
||||
const mapKeyXhr = xhr(mapKeyRequestOptions, mapKeyRequestCallback);
|
||||
|
@ -1013,7 +1021,8 @@ export const mediaSegmentRequest = ({
|
|||
const initSegmentOptions = merge(xhrOptions, {
|
||||
uri: segment.map.resolvedUri,
|
||||
responseType: 'arraybuffer',
|
||||
headers: segmentXhrHeaders(segment.map)
|
||||
headers: segmentXhrHeaders(segment.map),
|
||||
requestType: 'segment-media-initialization'
|
||||
});
|
||||
const initSegmentRequestCallback = handleInitSegmentResponse({segment, finishProcessingFn});
|
||||
const initSegmentXhr = xhr(initSegmentOptions, initSegmentRequestCallback);
|
||||
|
@ -1024,7 +1033,8 @@ export const mediaSegmentRequest = ({
|
|||
const segmentRequestOptions = merge(xhrOptions, {
|
||||
uri: segment.part && segment.part.resolvedUri || segment.resolvedUri,
|
||||
responseType: 'arraybuffer',
|
||||
headers: segmentXhrHeaders(segment)
|
||||
headers: segmentXhrHeaders(segment),
|
||||
requestType: 'segment'
|
||||
});
|
||||
|
||||
const segmentRequestCallback = handleSegmentResponse({
|
||||
|
|
19
node_modules/@videojs/http-streaming/src/playlist-loader.js
generated
vendored
19
node_modules/@videojs/http-streaming/src/playlist-loader.js
generated
vendored
|
@ -446,7 +446,8 @@ export default class PlaylistLoader extends EventTarget {
|
|||
|
||||
this.request = this.vhs_.xhr({
|
||||
uri,
|
||||
withCredentials: this.withCredentials
|
||||
withCredentials: this.withCredentials,
|
||||
requestType: 'hls-playlist'
|
||||
}, (error, req) => {
|
||||
// disposed
|
||||
if (!this.request) {
|
||||
|
@ -484,7 +485,10 @@ export default class PlaylistLoader extends EventTarget {
|
|||
status: xhr.status,
|
||||
message: `HLS playlist request error at URL: ${uri}.`,
|
||||
responseText: xhr.responseText,
|
||||
code: (xhr.status >= 500) ? 4 : 2
|
||||
code: (xhr.status >= 500) ? 4 : 2,
|
||||
metadata: {
|
||||
errorType: videojs.Error.HlsPlaylistRequestError
|
||||
}
|
||||
};
|
||||
|
||||
this.trigger('error');
|
||||
|
@ -689,7 +693,8 @@ export default class PlaylistLoader extends EventTarget {
|
|||
|
||||
this.request = this.vhs_.xhr({
|
||||
uri: playlist.resolvedUri,
|
||||
withCredentials: this.withCredentials
|
||||
withCredentials: this.withCredentials,
|
||||
requestType: 'hls-playlist'
|
||||
}, (error, req) => {
|
||||
// disposed
|
||||
if (!this.request) {
|
||||
|
@ -835,7 +840,8 @@ export default class PlaylistLoader extends EventTarget {
|
|||
// request the specified URL
|
||||
this.request = this.vhs_.xhr({
|
||||
uri: this.src,
|
||||
withCredentials: this.withCredentials
|
||||
withCredentials: this.withCredentials,
|
||||
requestType: 'hls-playlist'
|
||||
}, (error, req) => {
|
||||
// disposed
|
||||
if (!this.request) {
|
||||
|
@ -851,7 +857,10 @@ export default class PlaylistLoader extends EventTarget {
|
|||
message: `HLS playlist request error at URL: ${this.src}.`,
|
||||
responseText: req.responseText,
|
||||
// MEDIA_ERR_NETWORK
|
||||
code: 2
|
||||
code: 2,
|
||||
metadata: {
|
||||
errorType: videojs.Error.HlsPlaylistRequestError
|
||||
}
|
||||
};
|
||||
if (this.state === 'HAVE_NOTHING') {
|
||||
this.started = false;
|
||||
|
|
12
node_modules/@videojs/http-streaming/src/playlist-selectors.js
generated
vendored
12
node_modules/@videojs/http-streaming/src/playlist-selectors.js
generated
vendored
|
@ -364,7 +364,11 @@ export const TEST_ONLY_SIMPLE_SELECTOR = (newSimpleSelector) => {
|
|||
* bandwidth variance
|
||||
*/
|
||||
export const lastBandwidthSelector = function() {
|
||||
const pixelRatio = this.useDevicePixelRatio ? window.devicePixelRatio || 1 : 1;
|
||||
let pixelRatio = this.useDevicePixelRatio ? window.devicePixelRatio || 1 : 1;
|
||||
|
||||
if (!isNaN(this.customPixelRatio)) {
|
||||
pixelRatio = this.customPixelRatio;
|
||||
}
|
||||
|
||||
return simpleSelector(
|
||||
this.playlists.main,
|
||||
|
@ -399,7 +403,11 @@ export const movingAverageBandwidthSelector = function(decay) {
|
|||
}
|
||||
|
||||
return function() {
|
||||
const pixelRatio = this.useDevicePixelRatio ? window.devicePixelRatio || 1 : 1;
|
||||
let pixelRatio = this.useDevicePixelRatio ? window.devicePixelRatio || 1 : 1;
|
||||
|
||||
if (!isNaN(this.customPixelRatio)) {
|
||||
pixelRatio = this.customPixelRatio;
|
||||
}
|
||||
|
||||
if (average < 0) {
|
||||
average = this.systemBandwidth;
|
||||
|
|
163
node_modules/@videojs/http-streaming/src/segment-loader.js
generated
vendored
163
node_modules/@videojs/http-streaming/src/segment-loader.js
generated
vendored
|
@ -11,7 +11,7 @@ import segmentTransmuxer from './segment-transmuxer';
|
|||
import { TIME_FUDGE_FACTOR, timeUntilRebuffer as timeUntilRebuffer_ } from './ranges';
|
||||
import { minRebufferMaxBandwidthSelector } from './playlist-selectors';
|
||||
import logger from './util/logger';
|
||||
import { concatSegments } from './util/segment';
|
||||
import {compactSegmentUrlDescription, concatSegments} from './util/segment';
|
||||
import {
|
||||
createCaptionsTrackIfNotExists,
|
||||
addCaptionData,
|
||||
|
@ -678,6 +678,18 @@ export default class SegmentLoader extends videojs.EventTarget {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: Current sync controller consists of many hls-specific strategies
|
||||
* media sequence sync is also hls-specific, and we would like to be protocol-agnostic on this level
|
||||
* this should be a part of the sync-controller and sync controller should expect different strategy list based on the protocol.
|
||||
*
|
||||
* @return {MediaSequenceSync|null}
|
||||
* @private
|
||||
*/
|
||||
get mediaSequenceSync_() {
|
||||
return this.syncController_.getMediaSequenceSync(this.loaderType_);
|
||||
}
|
||||
|
||||
createTransmuxer_() {
|
||||
return segmentTransmuxer.createTransmuxer({
|
||||
remux: false,
|
||||
|
@ -815,6 +827,7 @@ export default class SegmentLoader extends videojs.EventTarget {
|
|||
}
|
||||
|
||||
this.pendingSegment_ = null;
|
||||
|
||||
return this.error_;
|
||||
}
|
||||
|
||||
|
@ -1033,8 +1046,14 @@ export default class SegmentLoader extends videojs.EventTarget {
|
|||
}
|
||||
|
||||
this.logger_(`playlist update [${oldId} => ${newPlaylist.id || newPlaylist.uri}]`);
|
||||
this.syncController_.updateMediaSequenceMap(newPlaylist, this.currentTime_(), this.loaderType_);
|
||||
|
||||
if (this.mediaSequenceSync_) {
|
||||
this.mediaSequenceSync_.update(newPlaylist, this.currentTime_());
|
||||
this.logger_(`Playlist update:
|
||||
currentTime: ${this.currentTime_()}
|
||||
bufferedEnd: ${lastBufferedEnd(this.buffered_())}
|
||||
`, this.mediaSequenceSync_.diagnostics);
|
||||
}
|
||||
// in VOD, this is always a rendition switch (or we updated our syncInfo above)
|
||||
// in LIVE, we always want to update with new playlists (including refreshes)
|
||||
this.trigger('syncinfoupdate');
|
||||
|
@ -1199,6 +1218,9 @@ export default class SegmentLoader extends videojs.EventTarget {
|
|||
*/
|
||||
resetLoader() {
|
||||
this.fetchAtBuffer_ = false;
|
||||
if (this.mediaSequenceSync_) {
|
||||
this.mediaSequenceSync_.resetAppendedStatus();
|
||||
}
|
||||
this.resyncLoader();
|
||||
}
|
||||
|
||||
|
@ -1215,7 +1237,11 @@ export default class SegmentLoader extends videojs.EventTarget {
|
|||
this.partIndex = null;
|
||||
this.syncPoint_ = null;
|
||||
this.isPendingTimestampOffset_ = false;
|
||||
this.shouldForceTimestampOffsetAfterResync_ = true;
|
||||
// this is mainly to sync timing-info when switching between renditions with and without timestamp-rollover,
|
||||
// so we don't want it for DASH
|
||||
if (this.sourceType_ === 'hls') {
|
||||
this.shouldForceTimestampOffsetAfterResync_ = true;
|
||||
}
|
||||
this.callQueue_ = [];
|
||||
this.loadQueue_ = [];
|
||||
this.metadataQueue_.id3 = [];
|
||||
|
@ -1451,18 +1477,50 @@ export default class SegmentLoader extends videojs.EventTarget {
|
|||
next.mediaIndex = this.mediaIndex + 1;
|
||||
}
|
||||
} else {
|
||||
// Find the segment containing the end of the buffer or current time.
|
||||
const {segmentIndex, startTime, partIndex} = Playlist.getMediaInfoForTime({
|
||||
exactManifestTimings: this.exactManifestTimings,
|
||||
playlist: this.playlist_,
|
||||
currentTime: this.fetchAtBuffer_ ? bufferedEnd : this.currentTime_(),
|
||||
startingPartIndex: this.syncPoint_.partIndex,
|
||||
startingSegmentIndex: this.syncPoint_.segmentIndex,
|
||||
startTime: this.syncPoint_.time
|
||||
});
|
||||
let segmentIndex; let partIndex; let startTime;
|
||||
const targetTime = this.fetchAtBuffer_ ? bufferedEnd : this.currentTime_();
|
||||
|
||||
next.getMediaInfoForTime = this.fetchAtBuffer_ ?
|
||||
`bufferedEnd ${bufferedEnd}` : `currentTime ${this.currentTime_()}`;
|
||||
if (this.mediaSequenceSync_) {
|
||||
this.logger_(`chooseNextRequest_ request after Quality Switch:
|
||||
For TargetTime: ${targetTime}.
|
||||
CurrentTime: ${this.currentTime_()}
|
||||
BufferedEnd: ${bufferedEnd}
|
||||
Fetch At Buffer: ${this.fetchAtBuffer_}
|
||||
`, this.mediaSequenceSync_.diagnostics);
|
||||
}
|
||||
|
||||
if (this.mediaSequenceSync_ && this.mediaSequenceSync_.isReliable) {
|
||||
const syncInfo = this.getSyncInfoFromMediaSequenceSync_(targetTime);
|
||||
|
||||
if (!syncInfo) {
|
||||
this.logger_('chooseNextRequest_ - no sync info found using media sequence sync');
|
||||
// no match
|
||||
return null;
|
||||
}
|
||||
|
||||
this.logger_(`chooseNextRequest_ mediaSequence syncInfo (${syncInfo.start} --> ${syncInfo.end})`);
|
||||
|
||||
segmentIndex = syncInfo.segmentIndex;
|
||||
partIndex = syncInfo.partIndex;
|
||||
startTime = syncInfo.start;
|
||||
} else {
|
||||
this.logger_('chooseNextRequest_ - fallback to a regular segment selection algorithm, based on a syncPoint.');
|
||||
// fallback
|
||||
const mediaInfoForTime = Playlist.getMediaInfoForTime({
|
||||
exactManifestTimings: this.exactManifestTimings,
|
||||
playlist: this.playlist_,
|
||||
currentTime: targetTime,
|
||||
startingPartIndex: this.syncPoint_.partIndex,
|
||||
startingSegmentIndex: this.syncPoint_.segmentIndex,
|
||||
startTime: this.syncPoint_.time
|
||||
});
|
||||
|
||||
segmentIndex = mediaInfoForTime.segmentIndex;
|
||||
partIndex = mediaInfoForTime.partIndex;
|
||||
startTime = mediaInfoForTime.startTime;
|
||||
}
|
||||
|
||||
next.getMediaInfoForTime = this.fetchAtBuffer_ ? `bufferedEnd ${targetTime}` : `currentTime ${targetTime}`;
|
||||
next.mediaIndex = segmentIndex;
|
||||
next.startOfSegment = startTime;
|
||||
next.partIndex = partIndex;
|
||||
|
@ -1535,6 +1593,47 @@ export default class SegmentLoader extends videojs.EventTarget {
|
|||
return this.generateSegmentInfo_(next);
|
||||
}
|
||||
|
||||
getSyncInfoFromMediaSequenceSync_(targetTime) {
|
||||
if (!this.mediaSequenceSync_) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// we should pull the target time to the least available time if we drop out of sync for any reason
|
||||
const finalTargetTime = Math.max(targetTime, this.mediaSequenceSync_.start);
|
||||
|
||||
if (targetTime !== finalTargetTime) {
|
||||
this.logger_(`getSyncInfoFromMediaSequenceSync_. Pulled target time from ${targetTime} to ${finalTargetTime}`);
|
||||
}
|
||||
|
||||
const mediaSequenceSyncInfo = this.mediaSequenceSync_.getSyncInfoForTime(finalTargetTime);
|
||||
|
||||
if (!mediaSequenceSyncInfo) {
|
||||
// no match at all
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!mediaSequenceSyncInfo.isAppended) {
|
||||
// has a perfect match
|
||||
return mediaSequenceSyncInfo;
|
||||
}
|
||||
|
||||
// has match, but segment was already appended.
|
||||
// attempt to auto-advance to the nearest next segment:
|
||||
const nextMediaSequenceSyncInfo = this.mediaSequenceSync_.getSyncInfoForTime(mediaSequenceSyncInfo.end);
|
||||
|
||||
if (!nextMediaSequenceSyncInfo) {
|
||||
// no match at all
|
||||
return null;
|
||||
}
|
||||
|
||||
if (nextMediaSequenceSyncInfo.isAppended) {
|
||||
this.logger_('getSyncInfoFromMediaSequenceSync_: We encounter unexpected scenario where next media sequence sync info is also appended!');
|
||||
}
|
||||
|
||||
// got match with the nearest next segment
|
||||
return nextMediaSequenceSyncInfo;
|
||||
}
|
||||
|
||||
generateSegmentInfo_(options) {
|
||||
const {
|
||||
independent,
|
||||
|
@ -2268,7 +2367,10 @@ export default class SegmentLoader extends videojs.EventTarget {
|
|||
`video buffer: ${timeRangesToArray(videoBuffered).join(', ')}, `);
|
||||
this.error({
|
||||
message: 'Quota exceeded error with append of a single segment of content',
|
||||
excludeUntil: Infinity
|
||||
excludeUntil: Infinity,
|
||||
metadata: {
|
||||
errorType: videojs.Error.SegmentExceedsSourceBufferQuota
|
||||
}
|
||||
});
|
||||
this.trigger('error');
|
||||
return;
|
||||
|
@ -2323,14 +2425,19 @@ export default class SegmentLoader extends videojs.EventTarget {
|
|||
}
|
||||
|
||||
this.logger_('Received non QUOTA_EXCEEDED_ERR on append', error);
|
||||
this.error(`${type} append of ${bytes.length}b failed for segment ` +
|
||||
`#${segmentInfo.mediaIndex} in playlist ${segmentInfo.playlist.id}`);
|
||||
|
||||
// If an append errors, we often can't recover.
|
||||
// (see https://w3c.github.io/media-source/#sourcebuffer-append-error).
|
||||
//
|
||||
// Trigger a special error so that it can be handled separately from normal,
|
||||
// recoverable errors.
|
||||
this.error({
|
||||
message: `${type} append of ${bytes.length}b failed for segment ` +
|
||||
`#${segmentInfo.mediaIndex} in playlist ${segmentInfo.playlist.id}`,
|
||||
metadata: {
|
||||
errorType: videojs.Error.SegmentAppendError
|
||||
}
|
||||
});
|
||||
this.trigger('appenderror');
|
||||
}
|
||||
|
||||
|
@ -2484,7 +2591,9 @@ export default class SegmentLoader extends videojs.EventTarget {
|
|||
segmentInfo.timeline > 0;
|
||||
const isEndOfTimeline = isEndOfStream || (isWalkingForward && isDiscontinuity);
|
||||
|
||||
this.logger_(`Requesting ${segmentInfoString(segmentInfo)}`);
|
||||
this.logger_(`Requesting
|
||||
${compactSegmentUrlDescription(segmentInfo.uri)}
|
||||
${segmentInfoString(segmentInfo)}`);
|
||||
|
||||
// If there's an init segment associated with this segment, but it is not cached (identified by a lack of bytes),
|
||||
// then this init segment has never been seen before and should be appended.
|
||||
|
@ -2811,7 +2920,10 @@ export default class SegmentLoader extends videojs.EventTarget {
|
|||
if (!trackInfo) {
|
||||
this.error({
|
||||
message: 'No starting media returned, likely due to an unsupported media format.',
|
||||
playlistExclusionDuration: Infinity
|
||||
playlistExclusionDuration: Infinity,
|
||||
metadata: {
|
||||
errorType: videojs.Error.SegmentUnsupportedMediaFormat
|
||||
}
|
||||
});
|
||||
this.trigger('error');
|
||||
return;
|
||||
|
@ -2892,7 +3004,10 @@ export default class SegmentLoader extends videojs.EventTarget {
|
|||
if (illegalMediaSwitchError) {
|
||||
this.error({
|
||||
message: illegalMediaSwitchError,
|
||||
playlistExclusionDuration: Infinity
|
||||
playlistExclusionDuration: Infinity,
|
||||
metadata: {
|
||||
errorType: videojs.Error.SegmentSwitchError
|
||||
}
|
||||
});
|
||||
this.trigger('error');
|
||||
return true;
|
||||
|
@ -3005,6 +3120,14 @@ export default class SegmentLoader extends videojs.EventTarget {
|
|||
|
||||
const segmentInfo = this.pendingSegment_;
|
||||
|
||||
if (segmentInfo.part && segmentInfo.part.syncInfo) {
|
||||
// low-latency flow
|
||||
segmentInfo.part.syncInfo.markAppended();
|
||||
} else if (segmentInfo.segment.syncInfo) {
|
||||
// normal flow
|
||||
segmentInfo.segment.syncInfo.markAppended();
|
||||
}
|
||||
|
||||
// Now that the end of the segment has been reached, we can set the end time. It's
|
||||
// best to wait until all appends are done so we're sure that the primary media is
|
||||
// finished (and we have its end time).
|
||||
|
|
15
node_modules/@videojs/http-streaming/src/source-updater.js
generated
vendored
15
node_modules/@videojs/http-streaming/src/source-updater.js
generated
vendored
|
@ -9,7 +9,7 @@ import {getMimeForCodec} from '@videojs/vhs-utils/es/codecs.js';
|
|||
import window from 'global/window';
|
||||
import toTitleCase from './util/to-title-case.js';
|
||||
import { QUOTA_EXCEEDED_ERR } from './error-codes';
|
||||
import {createTimeRanges} from './util/vjs-compat';
|
||||
import {createTimeRanges, bufferedRangesToString} from './util/vjs-compat';
|
||||
|
||||
const bufferTypes = [
|
||||
'video',
|
||||
|
@ -275,7 +275,13 @@ const actions = {
|
|||
}
|
||||
|
||||
// do not update codec if we don't need to.
|
||||
if (sourceUpdater.codecs[type] === codec) {
|
||||
// Only update if we change the codec base.
|
||||
// For example, going from avc1.640028 to avc1.64001f does not require a changeType call.
|
||||
const newCodecBase = codec.substring(0, codec.indexOf('.'));
|
||||
const oldCodec = sourceUpdater.codecs[type];
|
||||
const oldCodecBase = oldCodec.substring(0, oldCodec.indexOf('.'));
|
||||
|
||||
if (oldCodecBase === newCodecBase) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -308,6 +314,11 @@ const onUpdateend = (type, sourceUpdater) => (e) => {
|
|||
// updateend events on source buffers. This does not appear to be in the spec. As such,
|
||||
// if we encounter an updateend without a corresponding pending action from our queue
|
||||
// for that source buffer type, process the next action.
|
||||
const bufferedRangesForType = sourceUpdater[`${type}Buffered`]();
|
||||
const descriptiveString = bufferedRangesToString(bufferedRangesForType);
|
||||
|
||||
sourceUpdater.logger_(`received "updateend" event for ${type} Source Buffer: `, descriptiveString);
|
||||
|
||||
if (sourceUpdater.queuePending[type]) {
|
||||
const doneFn = sourceUpdater.queuePending[type].doneFn;
|
||||
|
||||
|
|
151
node_modules/@videojs/http-streaming/src/sync-controller.js
generated
vendored
151
node_modules/@videojs/http-streaming/src/sync-controller.js
generated
vendored
|
@ -5,6 +5,7 @@
|
|||
import {sumDurations, getPartsAndSegments} from './playlist';
|
||||
import videojs from 'video.js';
|
||||
import logger from './util/logger';
|
||||
import MediaSequenceSync from './util/media-sequence-sync';
|
||||
|
||||
// The maximum gap allowed between two media sequence tags when trying to
|
||||
// synchronize expired playlist segments.
|
||||
|
@ -44,71 +45,27 @@ export const syncPointStrategies = [
|
|||
* @param {string} type
|
||||
*/
|
||||
run: (syncController, playlist, duration, currentTimeline, currentTime, type) => {
|
||||
if (!type) {
|
||||
const mediaSequenceSync = syncController.getMediaSequenceSync(type);
|
||||
|
||||
if (!mediaSequenceSync) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const mediaSequenceMap = syncController.getMediaSequenceMap(type);
|
||||
|
||||
if (!mediaSequenceMap || mediaSequenceMap.size === 0) {
|
||||
if (!mediaSequenceSync.isReliable) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (playlist.mediaSequence === undefined || !Array.isArray(playlist.segments) || !playlist.segments.length) {
|
||||
const syncInfo = mediaSequenceSync.getSyncInfoForTime(currentTime);
|
||||
|
||||
if (!syncInfo) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let currentMediaSequence = playlist.mediaSequence;
|
||||
let segmentIndex = 0;
|
||||
|
||||
for (const segment of playlist.segments) {
|
||||
const range = mediaSequenceMap.get(currentMediaSequence);
|
||||
|
||||
if (!range) {
|
||||
// unexpected case
|
||||
// we expect this playlist to be the same playlist in the map
|
||||
// just break from the loop and move forward to the next strategy
|
||||
break;
|
||||
}
|
||||
|
||||
if (currentTime >= range.start && currentTime < range.end) {
|
||||
// we found segment
|
||||
|
||||
if (Array.isArray(segment.parts) && segment.parts.length) {
|
||||
let currentPartStart = range.start;
|
||||
let partIndex = 0;
|
||||
|
||||
for (const part of segment.parts) {
|
||||
const start = currentPartStart;
|
||||
const end = start + part.duration;
|
||||
|
||||
if (currentTime >= start && currentTime < end) {
|
||||
return {
|
||||
time: range.start,
|
||||
segmentIndex,
|
||||
partIndex
|
||||
};
|
||||
}
|
||||
|
||||
partIndex++;
|
||||
currentPartStart = end;
|
||||
}
|
||||
}
|
||||
|
||||
// no parts found, return sync point for segment
|
||||
return {
|
||||
time: range.start,
|
||||
segmentIndex,
|
||||
partIndex: null
|
||||
};
|
||||
}
|
||||
|
||||
segmentIndex++;
|
||||
currentMediaSequence++;
|
||||
}
|
||||
|
||||
// we didn't find any segments for provided current time
|
||||
return null;
|
||||
return {
|
||||
time: syncInfo.start,
|
||||
partIndex: syncInfo.partIndex,
|
||||
segmentIndex: syncInfo.segmentIndex
|
||||
};
|
||||
}
|
||||
},
|
||||
// Stategy "ProgramDateTime": We have a program-date-time tag in this playlist
|
||||
|
@ -272,78 +229,25 @@ export default class SyncController extends videojs.EventTarget {
|
|||
this.timelines = [];
|
||||
this.discontinuities = [];
|
||||
this.timelineToDatetimeMappings = {};
|
||||
|
||||
/**
|
||||
* @type {Map<string, Map<number, { start: number, end: number }>>}
|
||||
* @private
|
||||
*/
|
||||
this.mediaSequenceStorage_ = new Map();
|
||||
|
||||
// TODO: this map should be only available for HLS. Since only HLS has MediaSequence.
|
||||
// For some reason this map helps with syncing between quality switch for MPEG-DASH as well.
|
||||
// Moreover if we disable this map for MPEG-DASH - quality switch will be broken.
|
||||
// MPEG-DASH should have its own separate sync strategy
|
||||
this.mediaSequenceStorage_ = {
|
||||
main: new MediaSequenceSync(),
|
||||
audio: new MediaSequenceSync(),
|
||||
vtt: new MediaSequenceSync()
|
||||
};
|
||||
this.logger_ = logger('SyncController');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get media sequence map by type
|
||||
*
|
||||
* @param {string} type - segment loader type
|
||||
* @return {Map<number, { start: number, end: number }> | undefined}
|
||||
* @param {string} loaderType
|
||||
* @return {MediaSequenceSync|null}
|
||||
*/
|
||||
getMediaSequenceMap(type) {
|
||||
return this.mediaSequenceStorage_.get(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update Media Sequence Map -> <MediaSequence, Range>
|
||||
*
|
||||
* @param {Object} playlist - parsed playlist
|
||||
* @param {number} currentTime - current player's time
|
||||
* @param {string} type - segment loader type
|
||||
* @return {void}
|
||||
*/
|
||||
updateMediaSequenceMap(playlist, currentTime, type) {
|
||||
// we should not process this playlist if it does not have mediaSequence or segments
|
||||
if (playlist.mediaSequence === undefined || !Array.isArray(playlist.segments) || !playlist.segments.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
const currentMap = this.getMediaSequenceMap(type);
|
||||
const result = new Map();
|
||||
|
||||
let currentMediaSequence = playlist.mediaSequence;
|
||||
let currentBaseTime;
|
||||
|
||||
if (!currentMap) {
|
||||
// first playlist setup:
|
||||
currentBaseTime = 0;
|
||||
} else if (currentMap.has(playlist.mediaSequence)) {
|
||||
// further playlists setup:
|
||||
currentBaseTime = currentMap.get(playlist.mediaSequence).start;
|
||||
} else {
|
||||
// it seems like we have a gap between playlists, use current time as a fallback:
|
||||
this.logger_(`MediaSequence sync for ${type} segment loader - received a gap between playlists.
|
||||
Fallback base time to: ${currentTime}.
|
||||
Received media sequence: ${currentMediaSequence}.
|
||||
Current map: `, currentMap);
|
||||
currentBaseTime = currentTime;
|
||||
}
|
||||
|
||||
this.logger_(`MediaSequence sync for ${type} segment loader.
|
||||
Received media sequence: ${currentMediaSequence}.
|
||||
base time is ${currentBaseTime}
|
||||
Current map: `, currentMap);
|
||||
|
||||
playlist.segments.forEach((segment) => {
|
||||
const start = currentBaseTime;
|
||||
const end = start + segment.duration;
|
||||
const range = { start, end };
|
||||
|
||||
result.set(currentMediaSequence, range);
|
||||
|
||||
currentMediaSequence++;
|
||||
currentBaseTime = end;
|
||||
});
|
||||
|
||||
this.mediaSequenceStorage_.set(type, result);
|
||||
getMediaSequenceSync(loaderType) {
|
||||
return this.mediaSequenceStorage_[loaderType] || null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -436,8 +340,7 @@ Current map: `, currentMap);
|
|||
playlist,
|
||||
duration,
|
||||
playlist.discontinuitySequence,
|
||||
0,
|
||||
'main'
|
||||
0
|
||||
);
|
||||
|
||||
// Without sync-points, there is not enough information to determine the expired time
|
||||
|
|
246
node_modules/@videojs/http-streaming/src/util/media-sequence-sync.js
generated
vendored
Normal file
246
node_modules/@videojs/http-streaming/src/util/media-sequence-sync.js
generated
vendored
Normal file
|
@ -0,0 +1,246 @@
|
|||
import {compactSegmentUrlDescription} from './segment';
|
||||
|
||||
class SyncInfo {
|
||||
/**
|
||||
* @param {number} start - media sequence start
|
||||
* @param {number} end - media sequence end
|
||||
* @param {number} segmentIndex - index for associated segment
|
||||
* @param {number|null} [partIndex] - index for associated part
|
||||
* @param {boolean} [appended] - appended indicator
|
||||
*
|
||||
*/
|
||||
constructor({start, end, segmentIndex, partIndex = null, appended = false}) {
|
||||
this.start_ = start;
|
||||
this.end_ = end;
|
||||
this.segmentIndex_ = segmentIndex;
|
||||
this.partIndex_ = partIndex;
|
||||
this.appended_ = appended;
|
||||
}
|
||||
|
||||
isInRange(targetTime) {
|
||||
return targetTime >= this.start && targetTime < this.end;
|
||||
}
|
||||
|
||||
markAppended() {
|
||||
this.appended_ = true;
|
||||
}
|
||||
|
||||
resetAppendedStatus() {
|
||||
this.appended_ = false;
|
||||
}
|
||||
|
||||
get isAppended() {
|
||||
return this.appended_;
|
||||
}
|
||||
|
||||
get start() {
|
||||
return this.start_;
|
||||
}
|
||||
|
||||
get end() {
|
||||
return this.end_;
|
||||
}
|
||||
|
||||
get segmentIndex() {
|
||||
return this.segmentIndex_;
|
||||
}
|
||||
|
||||
get partIndex() {
|
||||
return this.partIndex_;
|
||||
}
|
||||
}
|
||||
|
||||
class SyncInfoData {
|
||||
/**
|
||||
*
|
||||
* @param {SyncInfo} segmentSyncInfo - sync info for a given segment
|
||||
* @param {Array<SyncInfo>} [partsSyncInfo] - sync infos for a list of parts for a given segment
|
||||
*/
|
||||
constructor(segmentSyncInfo, partsSyncInfo = []) {
|
||||
this.segmentSyncInfo_ = segmentSyncInfo;
|
||||
this.partsSyncInfo_ = partsSyncInfo;
|
||||
}
|
||||
|
||||
get segmentSyncInfo() {
|
||||
return this.segmentSyncInfo_;
|
||||
}
|
||||
|
||||
get partsSyncInfo() {
|
||||
return this.partsSyncInfo_;
|
||||
}
|
||||
|
||||
get hasPartsSyncInfo() {
|
||||
return this.partsSyncInfo_.length > 0;
|
||||
}
|
||||
|
||||
resetAppendStatus() {
|
||||
this.segmentSyncInfo_.resetAppendedStatus();
|
||||
this.partsSyncInfo_.forEach((partSyncInfo) => partSyncInfo.resetAppendedStatus());
|
||||
}
|
||||
}
|
||||
|
||||
export default class MediaSequenceSync {
|
||||
constructor() {
|
||||
/**
|
||||
* @type {Map<number, SyncInfoData>}
|
||||
* @private
|
||||
*/
|
||||
this.storage_ = new Map();
|
||||
this.diagnostics_ = '';
|
||||
this.isReliable_ = false;
|
||||
this.start_ = -Infinity;
|
||||
this.end_ = Infinity;
|
||||
}
|
||||
|
||||
get start() {
|
||||
return this.start_;
|
||||
}
|
||||
|
||||
get end() {
|
||||
return this.end_;
|
||||
}
|
||||
|
||||
get diagnostics() {
|
||||
return this.diagnostics_;
|
||||
}
|
||||
|
||||
get isReliable() {
|
||||
return this.isReliable_;
|
||||
}
|
||||
|
||||
resetAppendedStatus() {
|
||||
this.storage_.forEach((syncInfoData) => syncInfoData.resetAppendStatus());
|
||||
}
|
||||
|
||||
/**
|
||||
* update sync storage
|
||||
*
|
||||
* @param {Object} playlist
|
||||
* @param {number} currentTime
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
update(playlist, currentTime) {
|
||||
const { mediaSequence, segments } = playlist;
|
||||
|
||||
this.isReliable_ = this.isReliablePlaylist_(mediaSequence, segments);
|
||||
|
||||
if (!this.isReliable_) {
|
||||
return;
|
||||
}
|
||||
|
||||
return this.updateStorage_(
|
||||
segments,
|
||||
mediaSequence,
|
||||
this.calculateBaseTime_(mediaSequence, currentTime)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {number} targetTime
|
||||
* @return {SyncInfo|null}
|
||||
*/
|
||||
getSyncInfoForTime(targetTime) {
|
||||
for (const { segmentSyncInfo, partsSyncInfo } of this.storage_.values()) {
|
||||
// Normal segment flow:
|
||||
if (!partsSyncInfo.length) {
|
||||
if (segmentSyncInfo.isInRange(targetTime)) {
|
||||
return segmentSyncInfo;
|
||||
}
|
||||
} else {
|
||||
// Low latency flow:
|
||||
for (const partSyncInfo of partsSyncInfo) {
|
||||
if (partSyncInfo.isInRange(targetTime)) {
|
||||
return partSyncInfo;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
updateStorage_(segments, startingMediaSequence, startingTime) {
|
||||
const newStorage = new Map();
|
||||
let newDiagnostics = '\n';
|
||||
|
||||
let currentStart = startingTime;
|
||||
let currentMediaSequence = startingMediaSequence;
|
||||
|
||||
this.start_ = currentStart;
|
||||
|
||||
segments.forEach((segment, segmentIndex) => {
|
||||
const prevSyncInfoData = this.storage_.get(currentMediaSequence);
|
||||
|
||||
const segmentStart = currentStart;
|
||||
const segmentEnd = segmentStart + segment.duration;
|
||||
const segmentIsAppended = Boolean(prevSyncInfoData &&
|
||||
prevSyncInfoData.segmentSyncInfo &&
|
||||
prevSyncInfoData.segmentSyncInfo.isAppended);
|
||||
|
||||
const segmentSyncInfo = new SyncInfo({
|
||||
start: segmentStart,
|
||||
end: segmentEnd,
|
||||
appended: segmentIsAppended,
|
||||
segmentIndex
|
||||
});
|
||||
|
||||
segment.syncInfo = segmentSyncInfo;
|
||||
|
||||
let currentPartStart = currentStart;
|
||||
|
||||
const partsSyncInfo = (segment.parts || []).map((part, partIndex) => {
|
||||
const partStart = currentPartStart;
|
||||
const partEnd = currentPartStart + part.duration;
|
||||
const partIsAppended = Boolean(prevSyncInfoData &&
|
||||
prevSyncInfoData.partsSyncInfo &&
|
||||
prevSyncInfoData.partsSyncInfo[partIndex] &&
|
||||
prevSyncInfoData.partsSyncInfo[partIndex].isAppended);
|
||||
|
||||
const partSyncInfo = new SyncInfo({
|
||||
start: partStart,
|
||||
end: partEnd,
|
||||
appended: partIsAppended,
|
||||
segmentIndex,
|
||||
partIndex
|
||||
});
|
||||
|
||||
currentPartStart = partEnd;
|
||||
newDiagnostics += `Media Sequence: ${currentMediaSequence}.${partIndex} | Range: ${partStart} --> ${partEnd} | Appended: ${partIsAppended}\n`;
|
||||
part.syncInfo = partSyncInfo;
|
||||
|
||||
return partSyncInfo;
|
||||
});
|
||||
|
||||
newStorage.set(currentMediaSequence, new SyncInfoData(segmentSyncInfo, partsSyncInfo));
|
||||
newDiagnostics += `${compactSegmentUrlDescription(segment.resolvedUri)} | Media Sequence: ${currentMediaSequence} | Range: ${segmentStart} --> ${segmentEnd} | Appended: ${segmentIsAppended}\n`;
|
||||
|
||||
currentMediaSequence++;
|
||||
currentStart = segmentEnd;
|
||||
});
|
||||
|
||||
this.end_ = currentStart;
|
||||
this.storage_ = newStorage;
|
||||
this.diagnostics_ = newDiagnostics;
|
||||
}
|
||||
|
||||
calculateBaseTime_(mediaSequence, fallback) {
|
||||
if (!this.storage_.size) {
|
||||
// Initial setup flow.
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (this.storage_.has(mediaSequence)) {
|
||||
// Normal flow.
|
||||
return this.storage_.get(mediaSequence).segmentSyncInfo.start;
|
||||
}
|
||||
|
||||
// Fallback flow.
|
||||
// There is a gap between last recorded playlist and a new one received.
|
||||
return fallback;
|
||||
}
|
||||
|
||||
isReliablePlaylist_(mediaSequence, segments) {
|
||||
return mediaSequence !== undefined && mediaSequence !== null && Array.isArray(segments) && segments.length;
|
||||
}
|
||||
}
|
21
node_modules/@videojs/http-streaming/src/util/segment.js
generated
vendored
21
node_modules/@videojs/http-streaming/src/util/segment.js
generated
vendored
|
@ -21,3 +21,24 @@ export const concatSegments = (segmentObj) => {
|
|||
|
||||
return tempBuffer;
|
||||
};
|
||||
|
||||
/**
|
||||
* Example:
|
||||
* https://host.com/path1/path2/path3/segment.ts?arg1=val1
|
||||
* -->
|
||||
* path3/segment.ts
|
||||
*
|
||||
* @param resolvedUri
|
||||
* @return {string}
|
||||
*/
|
||||
export function compactSegmentUrlDescription(resolvedUri) {
|
||||
try {
|
||||
return new URL(resolvedUri)
|
||||
.pathname
|
||||
.split('/')
|
||||
.slice(-2)
|
||||
.join('/');
|
||||
} catch (e) {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
|
24
node_modules/@videojs/http-streaming/src/util/vjs-compat.js
generated
vendored
24
node_modules/@videojs/http-streaming/src/util/vjs-compat.js
generated
vendored
|
@ -24,3 +24,27 @@ export function createTimeRanges(...args) {
|
|||
|
||||
return fn.apply(context, args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts provided buffered ranges to a descriptive string
|
||||
*
|
||||
* @param {TimeRanges} buffered - received buffered time ranges
|
||||
*
|
||||
* @return {string} - descriptive string
|
||||
*/
|
||||
export function bufferedRangesToString(buffered) {
|
||||
if (buffered.length === 0) {
|
||||
return 'Buffered Ranges are empty';
|
||||
}
|
||||
|
||||
let bufferedRangesStr = 'Buffered Ranges: \n';
|
||||
|
||||
for (let i = 0; i < buffered.length; i++) {
|
||||
const start = buffered.start(i);
|
||||
const end = buffered.end(i);
|
||||
|
||||
bufferedRangesStr += `${start} --> ${end}. Duration (${end - start})\n`;
|
||||
}
|
||||
|
||||
return bufferedRangesStr;
|
||||
}
|
||||
|
|
13
node_modules/@videojs/http-streaming/src/videojs-http-streaming.js
generated
vendored
13
node_modules/@videojs/http-streaming/src/videojs-http-streaming.js
generated
vendored
|
@ -738,6 +738,7 @@ class VhsHandler extends Component {
|
|||
[
|
||||
'withCredentials',
|
||||
'useDevicePixelRatio',
|
||||
'customPixelRatio',
|
||||
'limitRenditionByPlayerDimensions',
|
||||
'bandwidth',
|
||||
'customTagParsers',
|
||||
|
@ -761,6 +762,13 @@ class VhsHandler extends Component {
|
|||
|
||||
this.limitRenditionByPlayerDimensions = this.options_.limitRenditionByPlayerDimensions;
|
||||
this.useDevicePixelRatio = this.options_.useDevicePixelRatio;
|
||||
|
||||
const customPixelRatio = this.options_.customPixelRatio;
|
||||
|
||||
// Ensure the custom pixel ratio is a number greater than or equal to 0
|
||||
if (typeof customPixelRatio === 'number' && customPixelRatio >= 0) {
|
||||
this.customPixelRatio = customPixelRatio;
|
||||
}
|
||||
}
|
||||
// alias for public method to set options
|
||||
setOptions(options = {}) {
|
||||
|
@ -1088,7 +1096,10 @@ class VhsHandler extends Component {
|
|||
this.logger_('error while creating EME key session', err);
|
||||
this.player_.error({
|
||||
message: 'Failed to initialize media keys for EME',
|
||||
code: 3
|
||||
code: 3,
|
||||
metadata: {
|
||||
errorType: videojs.Error.EMEKeySessionCreationError
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
14
node_modules/@videojs/http-streaming/src/vtt-segment-loader.js
generated
vendored
14
node_modules/@videojs/http-streaming/src/vtt-segment-loader.js
generated
vendored
|
@ -37,8 +37,6 @@ export default class VTTSegmentLoader extends SegmentLoader {
|
|||
|
||||
this.subtitlesTrack_ = null;
|
||||
|
||||
this.loaderType_ = 'subtitle';
|
||||
|
||||
this.featuresNativeTextTracks_ = settings.featuresNativeTextTracks;
|
||||
|
||||
this.loadVttJs = settings.loadVttJs;
|
||||
|
@ -314,7 +312,12 @@ export default class VTTSegmentLoader extends SegmentLoader {
|
|||
this.loadVttJs()
|
||||
.then(
|
||||
() => this.segmentRequestFinished_(error, simpleSegment, result),
|
||||
() => this.stopForError({ message: 'Error loading vtt.js' })
|
||||
() => this.stopForError({
|
||||
message: 'Error loading vtt.js',
|
||||
metadata: {
|
||||
errorType: videojs.Error.VttLoadError
|
||||
}
|
||||
})
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
@ -325,7 +328,10 @@ export default class VTTSegmentLoader extends SegmentLoader {
|
|||
this.parseVTTCues_(segmentInfo);
|
||||
} catch (e) {
|
||||
this.stopForError({
|
||||
message: e.message
|
||||
message: e.message,
|
||||
metadata: {
|
||||
errorType: videojs.Error.VttCueParsingError
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
|
6
node_modules/@videojs/http-streaming/src/xhr.js
generated
vendored
6
node_modules/@videojs/http-streaming/src/xhr.js
generated
vendored
|
@ -13,10 +13,6 @@ import videojs from 'video.js';
|
|||
import window from 'global/window';
|
||||
import {merge} from './util/vjs-compat';
|
||||
|
||||
const {
|
||||
xhr: videojsXHR
|
||||
} = videojs;
|
||||
|
||||
const callbackWrapper = function(request, error, response, callback) {
|
||||
const reqResponse = request.responseType === 'arraybuffer' ? request.response : request.responseText;
|
||||
|
||||
|
@ -115,7 +111,7 @@ const xhrFactory = function() {
|
|||
|
||||
// Use the standard videojs.xhr() method unless `videojs.Vhs.xhr` has been overriden
|
||||
// TODO: switch back to videojs.Vhs.xhr.name === 'XhrFunction' when we drop IE11
|
||||
const xhrMethod = videojs.Vhs.xhr.original === true ? videojsXHR : videojs.Vhs.xhr;
|
||||
const xhrMethod = videojs.Vhs.xhr.original === true ? videojs.xhr : videojs.Vhs.xhr;
|
||||
|
||||
// call all registered onRequest hooks, assign new options.
|
||||
const beforeRequestOptions = callAllRequestHooks(_requestCallbackSet, options);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue