rx-player 3.27.0 → 3.27.1-dev.2022041500
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/VERSION +1 -1
- package/dist/_esm5.processed/core/abr/abr_manager.d.ts +7 -3
- package/dist/_esm5.processed/core/abr/abr_manager.js +4 -3
- package/dist/_esm5.processed/core/abr/representation_estimator.d.ts +13 -8
- package/dist/_esm5.processed/core/abr/representation_estimator.js +4 -4
- package/dist/_esm5.processed/core/api/public_api.js +13 -14
- package/dist/_esm5.processed/core/init/content_time_boundaries_observer.d.ts +52 -0
- package/dist/_esm5.processed/core/init/content_time_boundaries_observer.js +223 -0
- package/dist/_esm5.processed/core/init/create_stream_playback_observer.js +17 -6
- package/dist/_esm5.processed/core/init/get_initial_time.d.ts +30 -5
- package/dist/_esm5.processed/core/init/get_initial_time.js +20 -13
- package/dist/_esm5.processed/core/init/load_on_media_source.js +16 -3
- package/dist/_esm5.processed/core/init/media_duration_updater.d.ts +56 -0
- package/dist/_esm5.processed/core/init/media_duration_updater.js +188 -0
- package/dist/_esm5.processed/core/stream/adaptation/adaptation_stream.d.ts +2 -5
- package/dist/_esm5.processed/core/stream/adaptation/create_representation_estimator.d.ts +3 -2
- package/dist/_esm5.processed/core/stream/adaptation/create_representation_estimator.js +3 -3
- package/dist/_esm5.processed/core/stream/orchestrator/stream_orchestrator.js +2 -22
- package/dist/_esm5.processed/core/stream/period/period_stream.d.ts +2 -5
- package/dist/_esm5.processed/core/stream/period/period_stream.js +6 -4
- package/dist/_esm5.processed/core/stream/representation/get_buffer_status.d.ts +4 -2
- package/dist/_esm5.processed/core/stream/representation/get_buffer_status.js +85 -42
- package/dist/_esm5.processed/core/stream/representation/representation_stream.js +3 -3
- package/dist/_esm5.processed/manifest/manifest.d.ts +14 -5
- package/dist/_esm5.processed/manifest/manifest.js +31 -12
- package/dist/_esm5.processed/manifest/period.d.ts +6 -0
- package/dist/_esm5.processed/manifest/period.js +9 -0
- package/dist/_esm5.processed/manifest/representation_index/types.d.ts +7 -2
- package/dist/_esm5.processed/parsers/manifest/dash/common/get_minimum_and_maximum_positions.d.ts +5 -1
- package/dist/_esm5.processed/parsers/manifest/dash/common/get_minimum_and_maximum_positions.js +6 -4
- package/dist/_esm5.processed/parsers/manifest/dash/common/indexes/base.js +2 -1
- package/dist/_esm5.processed/parsers/manifest/dash/common/indexes/list.d.ts +4 -0
- package/dist/_esm5.processed/parsers/manifest/dash/common/indexes/list.js +4 -2
- package/dist/_esm5.processed/parsers/manifest/dash/common/indexes/template.js +4 -2
- package/dist/_esm5.processed/parsers/manifest/dash/common/indexes/timeline/timeline_representation_index.js +3 -3
- package/dist/_esm5.processed/parsers/manifest/dash/common/parse_mpd.js +28 -20
- package/dist/_esm5.processed/parsers/manifest/local/parse_local_manifest.js +3 -2
- package/dist/_esm5.processed/parsers/manifest/metaplaylist/metaplaylist_parser.js +9 -3
- package/dist/_esm5.processed/parsers/manifest/smooth/create_parser.js +26 -17
- package/dist/_esm5.processed/parsers/manifest/types.d.ts +45 -17
- package/dist/_esm5.processed/parsers/manifest/utils/{get_maximum_position.d.ts → get_maximum_positions.d.ts} +4 -1
- package/dist/_esm5.processed/parsers/manifest/utils/{get_maximum_position.js → get_maximum_positions.js} +10 -6
- package/dist/rx-player.js +854 -351
- package/dist/rx-player.min.js +1 -1
- package/package.json +1 -1
- package/sonar-project.properties +1 -1
- package/src/core/abr/abr_manager.ts +11 -3
- package/src/core/abr/representation_estimator.ts +17 -10
- package/src/core/api/public_api.ts +13 -15
- package/src/core/init/content_time_boundaries_observer.ts +312 -0
- package/src/core/init/create_stream_playback_observer.ts +18 -7
- package/src/core/init/get_initial_time.ts +52 -19
- package/src/core/init/load_on_media_source.ts +22 -5
- package/src/core/init/media_duration_updater.ts +268 -0
- package/src/core/stream/adaptation/adaptation_stream.ts +2 -5
- package/src/core/stream/adaptation/create_representation_estimator.ts +6 -3
- package/src/core/stream/orchestrator/stream_orchestrator.ts +2 -29
- package/src/core/stream/period/period_stream.ts +12 -9
- package/src/core/stream/representation/get_buffer_status.ts +102 -41
- package/src/core/stream/representation/representation_stream.ts +3 -3
- package/src/manifest/__tests__/manifest.test.ts +94 -68
- package/src/manifest/manifest.ts +73 -33
- package/src/manifest/period.ts +10 -0
- package/src/manifest/representation_index/types.ts +7 -2
- package/src/parsers/manifest/dash/common/get_minimum_and_maximum_positions.ts +10 -5
- package/src/parsers/manifest/dash/common/indexes/base.ts +4 -3
- package/src/parsers/manifest/dash/common/indexes/list.ts +8 -1
- package/src/parsers/manifest/dash/common/indexes/template.ts +8 -3
- package/src/parsers/manifest/dash/common/indexes/timeline/timeline_representation_index.ts +7 -7
- package/src/parsers/manifest/dash/common/parse_mpd.ts +38 -20
- package/src/parsers/manifest/local/parse_local_manifest.ts +3 -2
- package/src/parsers/manifest/metaplaylist/metaplaylist_parser.ts +9 -4
- package/src/parsers/manifest/smooth/create_parser.ts +36 -18
- package/src/parsers/manifest/types.ts +45 -17
- package/src/parsers/manifest/utils/{get_maximum_position.ts → get_maximum_positions.ts} +13 -7
- package/dist/_esm5.processed/core/init/duration_updater.d.ts +0 -27
- package/dist/_esm5.processed/core/init/duration_updater.js +0 -136
- package/src/core/init/duration_updater.ts +0 -206
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
* limitations under the License.
|
|
15
15
|
*/
|
|
16
16
|
import config from "../../../config";
|
|
17
|
+
import isNullOrUndefined from "../../../utils/is_null_or_undefined";
|
|
17
18
|
import { SegmentBufferOperation, } from "../../segment_buffers";
|
|
18
19
|
import checkForDiscontinuity from "./check_for_discontinuity";
|
|
19
20
|
import getNeededSegments from "./get_needed_segments";
|
|
@@ -26,20 +27,19 @@ import getSegmentPriority from "./get_segment_priority";
|
|
|
26
27
|
* be filled by any segment, even in the future.
|
|
27
28
|
*
|
|
28
29
|
* @param {Object} content
|
|
29
|
-
* @param {
|
|
30
|
+
* @param {number} initialWantedTime
|
|
31
|
+
* @param {Object} playbackObserver
|
|
30
32
|
* @param {number|undefined} fastSwitchThreshold
|
|
31
33
|
* @param {number} bufferGoal
|
|
34
|
+
* @param {number} maxBufferSize
|
|
32
35
|
* @param {Object} segmentBuffer
|
|
33
36
|
* @returns {Object}
|
|
34
37
|
*/
|
|
35
|
-
export default function getBufferStatus(content,
|
|
36
|
-
var _a;
|
|
37
|
-
var period = content.period, representation = content.representation;
|
|
38
|
+
export default function getBufferStatus(content, initialWantedTime, playbackObserver, fastSwitchThreshold, bufferGoal, maxBufferSize, segmentBuffer) {
|
|
38
39
|
segmentBuffer.synchronizeInventory();
|
|
39
|
-
var
|
|
40
|
-
var neededRange =
|
|
41
|
-
|
|
42
|
-
var shouldRefreshManifest = representation.index.shouldRefresh(wantedStartPosition, wantedEndPosition);
|
|
40
|
+
var representation = content.representation;
|
|
41
|
+
var neededRange = getRangeOfNeededSegments(content, initialWantedTime, bufferGoal);
|
|
42
|
+
var shouldRefreshManifest = representation.index.shouldRefresh(neededRange.start, neededRange.end);
|
|
43
43
|
/**
|
|
44
44
|
* Every segment awaiting an "EndOfSegment" operation, which indicates that a
|
|
45
45
|
* completely-loaded segment is still being pushed to the SegmentBuffer.
|
|
@@ -55,47 +55,18 @@ export default function getBufferStatus(content, wantedStartPosition, playbackOb
|
|
|
55
55
|
/** Callback allowing to retrieve a segment's history in the buffer. */
|
|
56
56
|
var getBufferedHistory = segmentBuffer.getSegmentHistory.bind(segmentBuffer);
|
|
57
57
|
/** List of segments we will need to download. */
|
|
58
|
-
var
|
|
58
|
+
var _a = getNeededSegments({ content: content, bufferedSegments: bufferedSegments, currentPlaybackTime: currentPlaybackTime, fastSwitchThreshold: fastSwitchThreshold, getBufferedHistory: getBufferedHistory, neededRange: neededRange, segmentsBeingPushed: segmentsBeingPushed, maxBufferSize: maxBufferSize }), segmentsToLoad = _a.segmentsToLoad, segmentsOnHold = _a.segmentsOnHold, isBufferFull = _a.isBufferFull;
|
|
59
59
|
var prioritizedNeededSegments = segmentsToLoad.map(function (segment) { return ({
|
|
60
|
-
priority: getSegmentPriority(segment.time,
|
|
60
|
+
priority: getSegmentPriority(segment.time, initialWantedTime),
|
|
61
61
|
segment: segment,
|
|
62
62
|
}); });
|
|
63
63
|
/**
|
|
64
64
|
* `true` if the current `RepresentationStream` has loaded all the
|
|
65
65
|
* needed segments for this Representation until the end of the Period.
|
|
66
66
|
*/
|
|
67
|
-
var hasFinishedLoading
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
period.end === undefined ||
|
|
71
|
-
prioritizedNeededSegments.length > 0 ||
|
|
72
|
-
segmentsOnHold.length > 0) {
|
|
73
|
-
hasFinishedLoading = false;
|
|
74
|
-
}
|
|
75
|
-
else {
|
|
76
|
-
if (lastPosition === undefined) {
|
|
77
|
-
// We do not know the end of this index.
|
|
78
|
-
// If we reached the end of the period, check that all segments are
|
|
79
|
-
// available.
|
|
80
|
-
hasFinishedLoading = neededRange.end >= period.end &&
|
|
81
|
-
representation.index.isFinished();
|
|
82
|
-
}
|
|
83
|
-
else if (lastPosition === null) {
|
|
84
|
-
// There is no available segment in the index currently. If the index
|
|
85
|
-
// tells us it has finished generating new segments, we're done.
|
|
86
|
-
hasFinishedLoading = representation.index.isFinished();
|
|
87
|
-
}
|
|
88
|
-
else {
|
|
89
|
-
// We have a declared end. Check that our range went until the last
|
|
90
|
-
// position available in the index. If that's the case and we're left
|
|
91
|
-
// with no segments after filtering them, it means we already have
|
|
92
|
-
// downloaded the last segments and have nothing left to do: full.
|
|
93
|
-
var endOfRange = period.end !== undefined ? Math.min(period.end, lastPosition) :
|
|
94
|
-
lastPosition;
|
|
95
|
-
hasFinishedLoading = neededRange.end >= endOfRange &&
|
|
96
|
-
representation.index.isFinished();
|
|
97
|
-
}
|
|
98
|
-
}
|
|
67
|
+
var hasFinishedLoading = neededRange.hasReachedPeriodEnd &&
|
|
68
|
+
prioritizedNeededSegments.length === 0 &&
|
|
69
|
+
segmentsOnHold.length === 0;
|
|
99
70
|
var imminentDiscontinuity;
|
|
100
71
|
if (!representation.index.isInitialized() ||
|
|
101
72
|
// TODO better handle contents not chronologically generated
|
|
@@ -127,6 +98,78 @@ export default function getBufferStatus(content, wantedStartPosition, playbackOb
|
|
|
127
98
|
}
|
|
128
99
|
return { imminentDiscontinuity: imminentDiscontinuity, hasFinishedLoading: hasFinishedLoading, neededSegments: prioritizedNeededSegments, isBufferFull: isBufferFull, shouldRefreshManifest: shouldRefreshManifest };
|
|
129
100
|
}
|
|
101
|
+
/**
|
|
102
|
+
* Returns both the time range of segments that should be loaded (from a
|
|
103
|
+
* starting position to an ending position) and whether the end of the Period is
|
|
104
|
+
* reached by that range.
|
|
105
|
+
* @param {Object} content
|
|
106
|
+
* @param {number} initialWantedTime
|
|
107
|
+
* @param {number} bufferGoal
|
|
108
|
+
* @returns {Object}
|
|
109
|
+
*/
|
|
110
|
+
function getRangeOfNeededSegments(content, initialWantedTime, bufferGoal) {
|
|
111
|
+
var _a;
|
|
112
|
+
var wantedStartPosition;
|
|
113
|
+
var manifest = content.manifest, period = content.period, representation = content.representation;
|
|
114
|
+
var lastIndexPosition = representation.index.getLastPosition();
|
|
115
|
+
var representationIndex = representation.index;
|
|
116
|
+
// There is an exception for when the current initially wanted time is already
|
|
117
|
+
// after the last position with segments AND when we're playing the absolute
|
|
118
|
+
// last Period in the Manifest.
|
|
119
|
+
// In that case, we want to actually request at least the last segment to
|
|
120
|
+
// avoid ending the last Period - and by extension the content - with a
|
|
121
|
+
// segment which isn't the last one.
|
|
122
|
+
if (!isNullOrUndefined(lastIndexPosition) &&
|
|
123
|
+
initialWantedTime >= lastIndexPosition &&
|
|
124
|
+
representationIndex.isInitialized() &&
|
|
125
|
+
representationIndex.isFinished() &&
|
|
126
|
+
isPeriodTheCurrentAndLastOne(manifest, period, initialWantedTime)) {
|
|
127
|
+
wantedStartPosition = lastIndexPosition - 1;
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
130
|
+
wantedStartPosition = initialWantedTime;
|
|
131
|
+
}
|
|
132
|
+
var wantedEndPosition = wantedStartPosition + bufferGoal;
|
|
133
|
+
var hasReachedPeriodEnd;
|
|
134
|
+
if (!representation.index.isInitialized() ||
|
|
135
|
+
!representation.index.isFinished() ||
|
|
136
|
+
period.end === undefined) {
|
|
137
|
+
hasReachedPeriodEnd = false;
|
|
138
|
+
}
|
|
139
|
+
else if (lastIndexPosition === undefined) {
|
|
140
|
+
// We do not know the end of this index.
|
|
141
|
+
hasReachedPeriodEnd = wantedEndPosition >= period.end;
|
|
142
|
+
}
|
|
143
|
+
else if (lastIndexPosition === null) {
|
|
144
|
+
// There is no available segment in the index currently.
|
|
145
|
+
hasReachedPeriodEnd = true;
|
|
146
|
+
}
|
|
147
|
+
else {
|
|
148
|
+
// We have a declared end. Check that our range went until the last
|
|
149
|
+
// position available in the index. If that's the case and we're left
|
|
150
|
+
// with no segments after filtering them, it means we already have
|
|
151
|
+
// downloaded the last segments and have nothing left to do: full.
|
|
152
|
+
hasReachedPeriodEnd = wantedEndPosition >= lastIndexPosition;
|
|
153
|
+
}
|
|
154
|
+
return { start: Math.max(wantedStartPosition, period.start),
|
|
155
|
+
end: Math.min(wantedEndPosition, (_a = period.end) !== null && _a !== void 0 ? _a : Infinity), hasReachedPeriodEnd: hasReachedPeriodEnd };
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Returns `true` if the given Period is both:
|
|
159
|
+
* - the one being played (the current position is known from `time`)
|
|
160
|
+
* - the absolute last one in the Manifest (that is, there will never be a
|
|
161
|
+
* Period after it).
|
|
162
|
+
* @param {Object} manifest
|
|
163
|
+
* @param {Object} period
|
|
164
|
+
* @param {number} time
|
|
165
|
+
* @returns {boolean}
|
|
166
|
+
*/
|
|
167
|
+
function isPeriodTheCurrentAndLastOne(manifest, period, time) {
|
|
168
|
+
var _a;
|
|
169
|
+
return period.containsTime(time) &&
|
|
170
|
+
manifest.isLastPeriodKnown &&
|
|
171
|
+
period.id === ((_a = manifest.periods[manifest.periods.length - 1]) === null || _a === void 0 ? void 0 : _a.id);
|
|
172
|
+
}
|
|
130
173
|
/**
|
|
131
174
|
* From the given SegmentInventory, filters the "playable" (in a supported codec
|
|
132
175
|
* and not known to be undecipherable) buffered Segment Objects which overlap
|
|
@@ -99,8 +99,8 @@ export default function RepresentationStream(_a) {
|
|
|
99
99
|
reCheckNeededSegments$.pipe(startWith(undefined)),
|
|
100
100
|
]).pipe(withLatestFrom(fastSwitchThreshold$), mergeMap(function (_a) {
|
|
101
101
|
var _b = _a[0], observation = _b[0], bufferGoal = _b[1], maxBufferSize = _b[2], terminate = _b[3], fastSwitchThreshold = _a[1];
|
|
102
|
-
var
|
|
103
|
-
var status = getBufferStatus(content,
|
|
102
|
+
var initialWantedTime = observation.position + observation.wantedTimeOffset;
|
|
103
|
+
var status = getBufferStatus(content, initialWantedTime, playbackObserver, fastSwitchThreshold, bufferGoal, maxBufferSize, segmentBuffer);
|
|
104
104
|
var neededSegments = status.neededSegments;
|
|
105
105
|
var neededInitSegment = null;
|
|
106
106
|
// Add initialization segment if required
|
|
@@ -165,7 +165,7 @@ export default function RepresentationStream(_a) {
|
|
|
165
165
|
var bufferRemoval = EMPTY;
|
|
166
166
|
var UPTO_CURRENT_POSITION_CLEANUP = config.getCurrent().UPTO_CURRENT_POSITION_CLEANUP;
|
|
167
167
|
if (status.isBufferFull) {
|
|
168
|
-
var gcedPosition = Math.max(0,
|
|
168
|
+
var gcedPosition = Math.max(0, initialWantedTime - UPTO_CURRENT_POSITION_CLEANUP);
|
|
169
169
|
if (gcedPosition > 0) {
|
|
170
170
|
bufferRemoval = segmentBuffer
|
|
171
171
|
.removeBuffer(0, gcedPosition)
|
|
@@ -254,15 +254,24 @@ export default class Manifest extends EventEmitter<IManifestEvents> {
|
|
|
254
254
|
*/
|
|
255
255
|
update(newManifest: Manifest): void;
|
|
256
256
|
/**
|
|
257
|
-
*
|
|
257
|
+
* Returns the theoretical minimum playable position on the content
|
|
258
|
+
* regardless of the current Adaptation chosen, as estimated at parsing
|
|
259
|
+
* time.
|
|
258
260
|
* @returns {number}
|
|
259
261
|
*/
|
|
260
|
-
|
|
262
|
+
getMinimumSafePosition(): number;
|
|
261
263
|
/**
|
|
262
|
-
* Get the
|
|
263
|
-
*
|
|
264
|
+
* Get the position of the live edge - that is, the position of what is
|
|
265
|
+
* currently being broadcasted, in seconds.
|
|
266
|
+
* @returns {number|undefined}
|
|
267
|
+
*/
|
|
268
|
+
getLivePosition(): number | undefined;
|
|
269
|
+
/**
|
|
270
|
+
* Returns the theoretical maximum playable position on the content
|
|
271
|
+
* regardless of the current Adaptation chosen, as estimated at parsing
|
|
272
|
+
* time.
|
|
264
273
|
*/
|
|
265
|
-
|
|
274
|
+
getMaximumSafePosition(): number;
|
|
266
275
|
/**
|
|
267
276
|
* Look in the Manifest for Representations linked to the given key ID,
|
|
268
277
|
* and mark them as being impossible to decrypt.
|
|
@@ -194,38 +194,57 @@ var Manifest = /** @class */ (function (_super) {
|
|
|
194
194
|
this._performUpdate(newManifest, MANIFEST_UPDATE_TYPE.Partial);
|
|
195
195
|
};
|
|
196
196
|
/**
|
|
197
|
-
*
|
|
197
|
+
* Returns the theoretical minimum playable position on the content
|
|
198
|
+
* regardless of the current Adaptation chosen, as estimated at parsing
|
|
199
|
+
* time.
|
|
198
200
|
* @returns {number}
|
|
199
201
|
*/
|
|
200
|
-
Manifest.prototype.
|
|
202
|
+
Manifest.prototype.getMinimumSafePosition = function () {
|
|
201
203
|
var _a, _b;
|
|
202
204
|
var windowData = this._timeBounds;
|
|
203
205
|
if (windowData.timeshiftDepth === null) {
|
|
204
|
-
return (_a = windowData.
|
|
206
|
+
return (_a = windowData.minimumSafePosition) !== null && _a !== void 0 ? _a : 0;
|
|
205
207
|
}
|
|
206
208
|
var maximumTimeData = windowData.maximumTimeData;
|
|
207
209
|
var maximumTime;
|
|
208
210
|
if (!windowData.maximumTimeData.isLinear) {
|
|
209
|
-
maximumTime = maximumTimeData.
|
|
211
|
+
maximumTime = maximumTimeData.maximumSafePosition;
|
|
210
212
|
}
|
|
211
213
|
else {
|
|
212
214
|
var timeDiff = performance.now() - maximumTimeData.time;
|
|
213
|
-
maximumTime = maximumTimeData.
|
|
215
|
+
maximumTime = maximumTimeData.maximumSafePosition + timeDiff / 1000;
|
|
214
216
|
}
|
|
215
217
|
var theoricalMinimum = maximumTime - windowData.timeshiftDepth;
|
|
216
|
-
return Math.max((_b = windowData.
|
|
218
|
+
return Math.max((_b = windowData.minimumSafePosition) !== null && _b !== void 0 ? _b : 0, theoricalMinimum);
|
|
217
219
|
};
|
|
218
220
|
/**
|
|
219
|
-
* Get the
|
|
220
|
-
*
|
|
221
|
+
* Get the position of the live edge - that is, the position of what is
|
|
222
|
+
* currently being broadcasted, in seconds.
|
|
223
|
+
* @returns {number|undefined}
|
|
224
|
+
*/
|
|
225
|
+
Manifest.prototype.getLivePosition = function () {
|
|
226
|
+
var maximumTimeData = this._timeBounds.maximumTimeData;
|
|
227
|
+
if (!this.isLive || maximumTimeData.livePosition === undefined) {
|
|
228
|
+
return undefined;
|
|
229
|
+
}
|
|
230
|
+
if (!maximumTimeData.isLinear) {
|
|
231
|
+
return maximumTimeData.livePosition;
|
|
232
|
+
}
|
|
233
|
+
var timeDiff = performance.now() - maximumTimeData.time;
|
|
234
|
+
return maximumTimeData.livePosition + timeDiff / 1000;
|
|
235
|
+
};
|
|
236
|
+
/**
|
|
237
|
+
* Returns the theoretical maximum playable position on the content
|
|
238
|
+
* regardless of the current Adaptation chosen, as estimated at parsing
|
|
239
|
+
* time.
|
|
221
240
|
*/
|
|
222
|
-
Manifest.prototype.
|
|
241
|
+
Manifest.prototype.getMaximumSafePosition = function () {
|
|
223
242
|
var maximumTimeData = this._timeBounds.maximumTimeData;
|
|
224
243
|
if (!maximumTimeData.isLinear) {
|
|
225
|
-
return maximumTimeData.
|
|
244
|
+
return maximumTimeData.maximumSafePosition;
|
|
226
245
|
}
|
|
227
246
|
var timeDiff = performance.now() - maximumTimeData.time;
|
|
228
|
-
return maximumTimeData.
|
|
247
|
+
return maximumTimeData.maximumSafePosition + timeDiff / 1000;
|
|
229
248
|
};
|
|
230
249
|
/**
|
|
231
250
|
* Look in the Manifest for Representations linked to the given key ID,
|
|
@@ -403,7 +422,7 @@ var Manifest = /** @class */ (function (_super) {
|
|
|
403
422
|
// Partial updates do not remove old Periods.
|
|
404
423
|
// This can become a memory problem when playing a content long enough.
|
|
405
424
|
// Let's clean manually Periods behind the minimum possible position.
|
|
406
|
-
var min = this.
|
|
425
|
+
var min = this.getMinimumSafePosition();
|
|
407
426
|
while (this.periods.length > 0) {
|
|
408
427
|
var period = this.periods[0];
|
|
409
428
|
if (period.end === undefined || period.end > min) {
|
|
@@ -80,4 +80,10 @@ export default class Period {
|
|
|
80
80
|
* @returns {Array.<Adaptation>}
|
|
81
81
|
*/
|
|
82
82
|
getSupportedAdaptations(type?: IAdaptationType): Adaptation[];
|
|
83
|
+
/**
|
|
84
|
+
* Returns true if the give time is in the time boundaries of this `Period`.
|
|
85
|
+
* @param {number} time
|
|
86
|
+
* @returns {boolean}
|
|
87
|
+
*/
|
|
88
|
+
containsTime(time: number): boolean;
|
|
83
89
|
}
|
|
@@ -127,6 +127,15 @@ var Period = /** @class */ (function () {
|
|
|
127
127
|
return ada.isSupported;
|
|
128
128
|
});
|
|
129
129
|
};
|
|
130
|
+
/**
|
|
131
|
+
* Returns true if the give time is in the time boundaries of this `Period`.
|
|
132
|
+
* @param {number} time
|
|
133
|
+
* @returns {boolean}
|
|
134
|
+
*/
|
|
135
|
+
Period.prototype.containsTime = function (time) {
|
|
136
|
+
return time >= this.start && (this.end === undefined ||
|
|
137
|
+
time < this.end);
|
|
138
|
+
};
|
|
130
139
|
return Period;
|
|
131
140
|
}());
|
|
132
141
|
export default Period;
|
|
@@ -248,10 +248,15 @@ export interface IRepresentationIndex {
|
|
|
248
248
|
*/
|
|
249
249
|
getFirstPosition(): number | null | undefined;
|
|
250
250
|
/**
|
|
251
|
-
* Returns the ending time, in seconds, of the last
|
|
252
|
-
* available in this index.
|
|
251
|
+
* Returns the ending time, in seconds, of the last playable position
|
|
252
|
+
* currently available in this index.
|
|
253
253
|
* Returns `null` if nothing is in the index
|
|
254
254
|
* Returns `undefined` if we cannot know this value.
|
|
255
|
+
*
|
|
256
|
+
* The last playable position is generally equivalent to the end of the last
|
|
257
|
+
* segment associated to this index, excepted when it goes over the end limit
|
|
258
|
+
* of the corresponding `Period`, in which case it will be equal to this end
|
|
259
|
+
* instead.
|
|
255
260
|
* @returns {Number|null|undefined}
|
|
256
261
|
*/
|
|
257
262
|
getLastPosition(): number | null | undefined;
|
package/dist/_esm5.processed/parsers/manifest/dash/common/get_minimum_and_maximum_positions.d.ts
CHANGED
|
@@ -18,4 +18,8 @@ import { IParsedPeriod } from "../../types";
|
|
|
18
18
|
* @param {Object} periods
|
|
19
19
|
* @returns {Array.<number>}
|
|
20
20
|
*/
|
|
21
|
-
export default function
|
|
21
|
+
export default function getMinimumAndMaximumPositions(periods: IParsedPeriod[]): {
|
|
22
|
+
minimumSafePosition: number | undefined;
|
|
23
|
+
maximumSafePosition: number | undefined;
|
|
24
|
+
maximumUnsafePosition: number | undefined;
|
|
25
|
+
};
|
package/dist/_esm5.processed/parsers/manifest/dash/common/get_minimum_and_maximum_positions.js
CHANGED
|
@@ -13,16 +13,18 @@
|
|
|
13
13
|
* See the License for the specific language governing permissions and
|
|
14
14
|
* limitations under the License.
|
|
15
15
|
*/
|
|
16
|
-
import
|
|
16
|
+
import getMaximumPositions from "../../utils/get_maximum_positions";
|
|
17
17
|
import getMinimumPosition from "../../utils/get_minimum_position";
|
|
18
18
|
/**
|
|
19
19
|
* @param {Object} periods
|
|
20
20
|
* @returns {Array.<number>}
|
|
21
21
|
*/
|
|
22
|
-
export default function
|
|
22
|
+
export default function getMinimumAndMaximumPositions(periods) {
|
|
23
23
|
if (periods.length === 0) {
|
|
24
24
|
throw new Error("DASH Parser: no period available for a dynamic content");
|
|
25
25
|
}
|
|
26
|
-
|
|
27
|
-
|
|
26
|
+
var minimumSafePosition = getMinimumPosition(periods);
|
|
27
|
+
var maxPositions = getMaximumPositions(periods);
|
|
28
|
+
return { minimumSafePosition: minimumSafePosition, maximumSafePosition: maxPositions.safe,
|
|
29
|
+
maximumUnsafePosition: maxPositions.unsafe };
|
|
28
30
|
}
|
|
@@ -129,12 +129,13 @@ var BaseRepresentationIndex = /** @class */ (function () {
|
|
|
129
129
|
* @returns {Number|null}
|
|
130
130
|
*/
|
|
131
131
|
BaseRepresentationIndex.prototype.getLastPosition = function () {
|
|
132
|
+
var _a;
|
|
132
133
|
var timeline = this._index.timeline;
|
|
133
134
|
if (timeline.length === 0) {
|
|
134
135
|
return null;
|
|
135
136
|
}
|
|
136
137
|
var lastTimelineElement = timeline[timeline.length - 1];
|
|
137
|
-
var lastTime = getIndexSegmentEnd(lastTimelineElement, null, this._scaledPeriodEnd);
|
|
138
|
+
var lastTime = Math.min(getIndexSegmentEnd(lastTimelineElement, null, this._scaledPeriodEnd), (_a = this._scaledPeriodEnd) !== null && _a !== void 0 ? _a : Infinity);
|
|
138
139
|
return fromIndexTime(lastTime, this._index);
|
|
139
140
|
};
|
|
140
141
|
/**
|
|
@@ -84,6 +84,8 @@ export interface IListIndexIndexArgument {
|
|
|
84
84
|
export interface IListIndexContextArgument {
|
|
85
85
|
/** Start of the period concerned by this RepresentationIndex, in seconds. */
|
|
86
86
|
periodStart: number;
|
|
87
|
+
/** End of the period concerned by this RepresentationIndex, in seconds. */
|
|
88
|
+
periodEnd: number | undefined;
|
|
87
89
|
/** Base URL for the Representation concerned. */
|
|
88
90
|
representationBaseURLs: IResolvedBaseUrl[];
|
|
89
91
|
/** ID of the Representation concerned. */
|
|
@@ -97,6 +99,8 @@ export default class ListRepresentationIndex implements IRepresentationIndex {
|
|
|
97
99
|
private _index;
|
|
98
100
|
/** Start of the period concerned by this RepresentationIndex, in seconds. */
|
|
99
101
|
protected _periodStart: number;
|
|
102
|
+
/** End of the period concerned by this RepresentationIndex, in seconds. */
|
|
103
|
+
protected _periodEnd: number | undefined;
|
|
100
104
|
private _isEMSGWhitelisted;
|
|
101
105
|
/**
|
|
102
106
|
* @param {Object} index
|
|
@@ -27,9 +27,10 @@ var ListRepresentationIndex = /** @class */ (function () {
|
|
|
27
27
|
if (index.duration === undefined) {
|
|
28
28
|
throw new Error("Invalid SegmentList: no duration");
|
|
29
29
|
}
|
|
30
|
-
var periodStart = context.periodStart, representationBaseURLs = context.representationBaseURLs, representationId = context.representationId, representationBitrate = context.representationBitrate, isEMSGWhitelisted = context.isEMSGWhitelisted;
|
|
30
|
+
var periodStart = context.periodStart, periodEnd = context.periodEnd, representationBaseURLs = context.representationBaseURLs, representationId = context.representationId, representationBitrate = context.representationBitrate, isEMSGWhitelisted = context.isEMSGWhitelisted;
|
|
31
31
|
this._isEMSGWhitelisted = isEMSGWhitelisted;
|
|
32
32
|
this._periodStart = periodStart;
|
|
33
|
+
this._periodEnd = periodEnd;
|
|
33
34
|
var presentationTimeOffset = index.presentationTimeOffset != null ? index.presentationTimeOffset :
|
|
34
35
|
0;
|
|
35
36
|
var timescale = (_a = index.timescale) !== null && _a !== void 0 ? _a : 1;
|
|
@@ -111,9 +112,10 @@ var ListRepresentationIndex = /** @class */ (function () {
|
|
|
111
112
|
* @returns {Number}
|
|
112
113
|
*/
|
|
113
114
|
ListRepresentationIndex.prototype.getLastPosition = function () {
|
|
115
|
+
var _a;
|
|
114
116
|
var index = this._index;
|
|
115
117
|
var duration = index.duration, list = index.list;
|
|
116
|
-
return ((list.length * duration) / index.timescale) + this._periodStart;
|
|
118
|
+
return Math.min(((list.length * duration) / index.timescale) + this._periodStart, (_a = this._periodEnd) !== null && _a !== void 0 ? _a : Infinity);
|
|
117
119
|
};
|
|
118
120
|
/**
|
|
119
121
|
* Returns true if a Segment returned by this index is still considered
|
|
@@ -55,7 +55,8 @@ var TemplateRepresentationIndex = /** @class */ (function () {
|
|
|
55
55
|
mediaURLs: createIndexURLs(urlSources, index.media, representationId, representationBitrate), presentationTimeOffset: presentationTimeOffset, startNumber: index.startNumber };
|
|
56
56
|
this._isDynamic = isDynamic;
|
|
57
57
|
this._periodStart = periodStart;
|
|
58
|
-
this._scaledPeriodEnd = periodEnd
|
|
58
|
+
this._scaledPeriodEnd = periodEnd === undefined ?
|
|
59
|
+
undefined :
|
|
59
60
|
(periodEnd - periodStart) * timescale;
|
|
60
61
|
this._isEMSGWhitelisted = isEMSGWhitelisted;
|
|
61
62
|
}
|
|
@@ -143,6 +144,7 @@ var TemplateRepresentationIndex = /** @class */ (function () {
|
|
|
143
144
|
* @returns {number|null}
|
|
144
145
|
*/
|
|
145
146
|
TemplateRepresentationIndex.prototype.getLastPosition = function () {
|
|
147
|
+
var _a;
|
|
146
148
|
var lastSegmentStart = this._getLastSegmentStart();
|
|
147
149
|
if (lastSegmentStart == null) {
|
|
148
150
|
// In that case (null or undefined), getLastPosition should reflect
|
|
@@ -150,7 +152,7 @@ var TemplateRepresentationIndex = /** @class */ (function () {
|
|
|
150
152
|
// the two functions. So, we return the result of the latter.
|
|
151
153
|
return lastSegmentStart;
|
|
152
154
|
}
|
|
153
|
-
var lastSegmentEnd = lastSegmentStart + this._index.duration;
|
|
155
|
+
var lastSegmentEnd = Math.min(lastSegmentStart + this._index.duration, (_a = this._scaledPeriodEnd) !== null && _a !== void 0 ? _a : Infinity);
|
|
154
156
|
return (lastSegmentEnd / this._index.timescale) + this._periodStart;
|
|
155
157
|
};
|
|
156
158
|
/**
|
|
@@ -74,7 +74,7 @@ var TimelineRepresentationIndex = /** @class */ (function () {
|
|
|
74
74
|
startNumber: index.startNumber,
|
|
75
75
|
timeline: (_c = index.timeline) !== null && _c !== void 0 ? _c : null, timescale: timescale };
|
|
76
76
|
this._scaledPeriodStart = toIndexTime(periodStart, this._index);
|
|
77
|
-
this._scaledPeriodEnd = periodEnd
|
|
77
|
+
this._scaledPeriodEnd = periodEnd === undefined ? undefined :
|
|
78
78
|
toIndexTime(periodEnd, this._index);
|
|
79
79
|
}
|
|
80
80
|
/**
|
|
@@ -136,7 +136,7 @@ var TimelineRepresentationIndex = /** @class */ (function () {
|
|
|
136
136
|
if (this._index.timeline === null) {
|
|
137
137
|
this._index.timeline = this._getTimeline();
|
|
138
138
|
}
|
|
139
|
-
var lastTime = TimelineRepresentationIndex.getIndexEnd(this._index.timeline, this.
|
|
139
|
+
var lastTime = TimelineRepresentationIndex.getIndexEnd(this._index.timeline, this._scaledPeriodEnd);
|
|
140
140
|
return lastTime === null ? null :
|
|
141
141
|
fromIndexTime(lastTime, this._index);
|
|
142
142
|
};
|
|
@@ -293,7 +293,7 @@ var TimelineRepresentationIndex = /** @class */ (function () {
|
|
|
293
293
|
if (timeline.length <= 0) {
|
|
294
294
|
return null;
|
|
295
295
|
}
|
|
296
|
-
return getIndexSegmentEnd(timeline[timeline.length - 1], null, scaledPeriodEnd);
|
|
296
|
+
return Math.min(getIndexSegmentEnd(timeline[timeline.length - 1], null, scaledPeriodEnd), scaledPeriodEnd !== null && scaledPeriodEnd !== void 0 ? scaledPeriodEnd : Infinity);
|
|
297
297
|
};
|
|
298
298
|
/**
|
|
299
299
|
* Allows to generate the "timeline" for this RepresentationIndex.
|
|
@@ -29,7 +29,7 @@ import { normalizeBaseURL } from "../../../../utils/resolve_url";
|
|
|
29
29
|
// eslint-disable-next-line max-len
|
|
30
30
|
import getClockOffset from "./get_clock_offset";
|
|
31
31
|
import getHTTPUTCTimingURL from "./get_http_utc-timing_url";
|
|
32
|
-
import
|
|
32
|
+
import getMinimumAndMaximumPositions from "./get_minimum_and_maximum_positions";
|
|
33
33
|
import parseAvailabilityStartTime from "./parse_availability_start_time";
|
|
34
34
|
import parsePeriods from "./parse_periods";
|
|
35
35
|
import resolveBaseURLs from "./resolve_base_urls";
|
|
@@ -159,56 +159,64 @@ function parseCompleteIntermediateRepresentation(mpdIR, args, warnings, xlinkInf
|
|
|
159
159
|
config.getCurrent().DASH_FALLBACK_LIFETIME_WHEN_MINIMUM_UPDATE_PERIOD_EQUAL_0 :
|
|
160
160
|
rootAttributes.minimumUpdatePeriod;
|
|
161
161
|
}
|
|
162
|
-
var _d =
|
|
162
|
+
var _d = getMinimumAndMaximumPositions(parsedPeriods), minimumSafePosition = _d.minimumSafePosition, maximumSafePosition = _d.maximumSafePosition, maximumUnsafePosition = _d.maximumUnsafePosition;
|
|
163
163
|
var now = performance.now();
|
|
164
164
|
if (!isDynamic) {
|
|
165
|
-
minimumTime =
|
|
165
|
+
minimumTime = minimumSafePosition !== undefined ? minimumSafePosition :
|
|
166
166
|
((_a = parsedPeriods[0]) === null || _a === void 0 ? void 0 : _a.start) !== undefined ? parsedPeriods[0].start :
|
|
167
167
|
0;
|
|
168
|
-
var
|
|
168
|
+
var finalMaximumSafePosition = mediaPresentationDuration !== null && mediaPresentationDuration !== void 0 ? mediaPresentationDuration : Infinity;
|
|
169
169
|
if (parsedPeriods[parsedPeriods.length - 1] !== undefined) {
|
|
170
170
|
var lastPeriod = parsedPeriods[parsedPeriods.length - 1];
|
|
171
171
|
var lastPeriodEnd = (_b = lastPeriod.end) !== null && _b !== void 0 ? _b : (lastPeriod.duration !== undefined ?
|
|
172
172
|
lastPeriod.start + lastPeriod.duration :
|
|
173
173
|
undefined);
|
|
174
|
-
if (lastPeriodEnd !== undefined && lastPeriodEnd <
|
|
175
|
-
|
|
174
|
+
if (lastPeriodEnd !== undefined && lastPeriodEnd < finalMaximumSafePosition) {
|
|
175
|
+
finalMaximumSafePosition = lastPeriodEnd;
|
|
176
176
|
}
|
|
177
177
|
}
|
|
178
|
-
if (
|
|
179
|
-
|
|
178
|
+
if (maximumSafePosition !== undefined &&
|
|
179
|
+
maximumSafePosition < finalMaximumSafePosition) {
|
|
180
|
+
finalMaximumSafePosition = maximumSafePosition;
|
|
180
181
|
}
|
|
181
182
|
maximumTimeData = { isLinear: false,
|
|
182
|
-
|
|
183
|
+
maximumSafePosition: finalMaximumSafePosition,
|
|
184
|
+
livePosition: undefined,
|
|
183
185
|
time: now };
|
|
184
186
|
}
|
|
185
187
|
else {
|
|
186
|
-
minimumTime =
|
|
188
|
+
minimumTime = minimumSafePosition;
|
|
187
189
|
timeshiftDepth = timeShiftBufferDepth !== null && timeShiftBufferDepth !== void 0 ? timeShiftBufferDepth : null;
|
|
188
|
-
var
|
|
189
|
-
|
|
190
|
-
|
|
190
|
+
var finalMaximumSafePosition = void 0;
|
|
191
|
+
var livePosition = void 0;
|
|
192
|
+
if (maximumUnsafePosition !== undefined) {
|
|
193
|
+
livePosition = maximumUnsafePosition;
|
|
194
|
+
}
|
|
195
|
+
if (maximumSafePosition !== undefined) {
|
|
196
|
+
finalMaximumSafePosition = maximumSafePosition;
|
|
191
197
|
}
|
|
192
198
|
else {
|
|
193
199
|
var ast = availabilityStartTime !== null && availabilityStartTime !== void 0 ? availabilityStartTime : 0;
|
|
194
200
|
var externalClockOffset = args.externalClockOffset;
|
|
195
201
|
if (externalClockOffset === undefined) {
|
|
196
202
|
log.warn("DASH Parser: use system clock to define maximum position");
|
|
197
|
-
|
|
203
|
+
finalMaximumSafePosition = (Date.now() / 1000) - ast;
|
|
198
204
|
}
|
|
199
205
|
else {
|
|
200
206
|
var serverTime = performance.now() + externalClockOffset;
|
|
201
|
-
|
|
207
|
+
finalMaximumSafePosition = (serverTime / 1000) - ast;
|
|
202
208
|
}
|
|
203
209
|
}
|
|
210
|
+
if (livePosition === undefined) {
|
|
211
|
+
livePosition = finalMaximumSafePosition;
|
|
212
|
+
}
|
|
204
213
|
maximumTimeData = { isLinear: true,
|
|
205
|
-
|
|
206
|
-
time: now };
|
|
214
|
+
maximumSafePosition: finalMaximumSafePosition, livePosition: livePosition, time: now };
|
|
207
215
|
// if the minimum calculated time is even below the buffer depth, perhaps we
|
|
208
216
|
// can go even lower in terms of depth
|
|
209
217
|
if (timeshiftDepth !== null && minimumTime !== undefined &&
|
|
210
|
-
|
|
211
|
-
timeshiftDepth =
|
|
218
|
+
finalMaximumSafePosition - minimumTime > timeshiftDepth) {
|
|
219
|
+
timeshiftDepth = finalMaximumSafePosition - minimumTime;
|
|
212
220
|
}
|
|
213
221
|
}
|
|
214
222
|
// `isLastPeriodKnown` should be `true` in two cases for DASH contents:
|
|
@@ -232,7 +240,7 @@ function parseCompleteIntermediateRepresentation(mpdIR, args, warnings, xlinkInf
|
|
|
232
240
|
publishTime: rootAttributes.publishTime,
|
|
233
241
|
suggestedPresentationDelay: rootAttributes.suggestedPresentationDelay,
|
|
234
242
|
transportType: "dash",
|
|
235
|
-
timeBounds: {
|
|
243
|
+
timeBounds: { minimumSafePosition: minimumTime, timeshiftDepth: timeshiftDepth, maximumTimeData: maximumTimeData },
|
|
236
244
|
lifetime: lifetime,
|
|
237
245
|
uris: args.url == null ?
|
|
238
246
|
rootChildren.locations : __spreadArray([args.url], rootChildren.locations, true),
|
|
@@ -38,10 +38,11 @@ export default function parseLocalManifest(localManifest) {
|
|
|
38
38
|
isLastPeriodKnown: isFinished,
|
|
39
39
|
isLive: false,
|
|
40
40
|
uris: [],
|
|
41
|
-
timeBounds: {
|
|
41
|
+
timeBounds: { minimumSafePosition: minimumPosition !== null && minimumPosition !== void 0 ? minimumPosition : 0,
|
|
42
42
|
timeshiftDepth: null,
|
|
43
43
|
maximumTimeData: { isLinear: false,
|
|
44
|
-
|
|
44
|
+
maximumSafePosition: maximumPosition,
|
|
45
|
+
livePosition: undefined,
|
|
45
46
|
time: performance.now() } },
|
|
46
47
|
periods: parsedPeriods };
|
|
47
48
|
}
|
|
@@ -230,9 +230,15 @@ function createManifest(mplData, manifests, parserOptions) {
|
|
|
230
230
|
var manifest = { availabilityStartTime: 0, clockOffset: clockOffset, suggestedPresentationDelay: 10, periods: periods, transportType: "metaplaylist",
|
|
231
231
|
isLive: isDynamic, isDynamic: isDynamic, isLastPeriodKnown: isLastPeriodKnown, uris: url == null ? [] :
|
|
232
232
|
[url],
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
233
|
+
// TODO more precize time bounds?
|
|
234
|
+
timeBounds: { minimumSafePosition: minimumTime,
|
|
235
|
+
timeshiftDepth: null,
|
|
236
|
+
maximumTimeData: {
|
|
237
|
+
isLinear: false,
|
|
238
|
+
maximumSafePosition: maximumTime,
|
|
239
|
+
livePosition: undefined,
|
|
240
|
+
time: time,
|
|
241
|
+
} },
|
|
236
242
|
lifetime: mplData.pollInterval };
|
|
237
243
|
return manifest;
|
|
238
244
|
}
|