Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Align with 3-5-2 #1457

Merged
merged 9 commits into from
Dec 4, 2023
6 changes: 0 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -463,12 +463,6 @@ This option defaults to `false`.
* Default: `false`
* Use [Decode Timestamp](https://www.w3.org/TR/media-source/#decode-timestamp) instead of [Presentation Timestamp](https://www.w3.org/TR/media-source/#presentation-timestamp) for [timestampOffset](https://www.w3.org/TR/media-source/#dom-sourcebuffer-timestampoffset) calculation. This option was introduced to align with DTS-based browsers. This option affects only transmuxed data (eg: transport stream). For more info please check the following [issue](https://github.com/videojs/http-streaming/issues/1247).

##### calculateTimestampOffsetForEachSegment
* Type: `boolean`,
* Default: `false`
* Calculate timestampOffset for each segment, regardless of its timeline. Sometimes it is helpful when you have corrupted DTS/PTS timestamps during discontinuities.


##### useForcedSubtitles
* Type: `boolean`
* Default: `false`
Expand Down
5 changes: 0 additions & 5 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -144,11 +144,6 @@
<label class="form-check-label" for="dts-offset">Use DTS instead of PTS for Timestamp Offset calculation (reloads player)</label>
</div>

<div class="form-check">
<input id=offset-each-segment type="checkbox" class="form-check-input">
<label class="form-check-label" for="offset-each-segment">Calculate timestampOffset for each segment, regardless of its timeline (reloads player)</label>
</div>

<div class="form-check">
<input id=llhls type="checkbox" class="form-check-input">
<label class="form-check-label" for="llhls">[EXPERIMENTAL] Enables support for ll-hls (reloads player)</label>
Expand Down
3 changes: 0 additions & 3 deletions scripts/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -470,7 +470,6 @@
'pixel-diff-selector',
'network-info',
'dts-offset',
'offset-each-segment',
'override-native',
'preload',
'mirror-source',
Expand Down Expand Up @@ -526,7 +525,6 @@
'pixel-diff-selector',
'network-info',
'dts-offset',
'offset-each-segment',
'exact-manifest-timings',
'forced-subtitles'
].forEach(function(name) {
Expand Down Expand Up @@ -611,7 +609,6 @@
leastPixelDiffSelector: getInputValue(stateEls['pixel-diff-selector']),
useNetworkInformationApi: getInputValue(stateEls['network-info']),
useDtsForTimestampOffset: getInputValue(stateEls['dts-offset']),
calculateTimestampOffsetForEachSegment: getInputValue(stateEls['offset-each-segment']),
useForcedSubtitles: getInputValue(stateEls['forced-subtitles'])
}
}
Expand Down
39 changes: 15 additions & 24 deletions src/playlist-controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,6 @@ export class PlaylistController extends videojs.EventTarget {
vhs: this.vhs_,
parse708captions: options.parse708captions,
useDtsForTimestampOffset: options.useDtsForTimestampOffset,
calculateTimestampOffsetForEachSegment: options.calculateTimestampOffsetForEachSegment,
captionServices,
mediaSource: this.mediaSource,
currentTime: this.tech_.currentTime.bind(this.tech_),
Expand Down Expand Up @@ -961,9 +960,9 @@ export class PlaylistController extends videojs.EventTarget {

/**
* Re-tune playback quality level for the current player
* conditions. This will reset the main segment loader
* and the next segment position to the currentTime.
* This is good for manual quality changes.
* conditions. This method will perform destructive actions like removing
* already buffered content in order to readjust the currently active
* playlist quickly. This is good for manual quality changes
*
* @private
*/
Expand All @@ -972,28 +971,20 @@ export class PlaylistController extends videojs.EventTarget {
this.logger_('skipping fastQualityChange because new media is same as old');
return;
}

this.switchMedia_(media, 'fast-quality');
// Reset main segment loader properties and next segment position information.
// Don't need to reset audio as it is reset when media changes.
// We resetLoaderProperties separately here as we want to fetch init segments if
// necessary and ensure we're not in an ended state when we switch playlists.
this.resetMainLoaderReplaceSegments();
}

/**
* Sets the replaceUntil flag on the main segment soader to the buffered end
* and resets the main segment loaders properties.
*/
resetMainLoaderReplaceSegments() {
const buffered = this.tech_.buffered();
const bufferedEnd = buffered.length ? buffered.end(buffered.length - 1) : 0;

// Set the replace segments flag to the buffered end, this forces fetchAtBuffer
// on the main loader to remain, false after the resetLoader call, until we have
// replaced all content buffered ahead of the currentTime.
this.mainSegmentLoader_.replaceSegmentsUntil = bufferedEnd;
this.mainSegmentLoader_.resetLoaderProperties();
this.mainSegmentLoader_.resetLoader();
// Delete all buffered data to allow an immediate quality switch, then seek to give
// the browser a kick to remove any cached frames from the previous rendtion (.04 seconds
// ahead was roughly the minimum that will accomplish this across a variety of content
// in IE and Edge, but seeking in place is sufficient on all other browsers)
// Edge/IE bug: https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/14600375/
// Chrome bug: https://bugs.chromium.org/p/chromium/issues/detail?id=651904
this.mainSegmentLoader_.resetEverything(() => {
this.tech_.setCurrentTime(this.tech_.currentTime());
});

// don't need to reset audio as it is reset when media changes
}

/**
Expand Down
83 changes: 12 additions & 71 deletions src/segment-loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -179,18 +179,6 @@ export const segmentInfoString = (segmentInfo) => {

const timingInfoPropertyForMedia = (mediaType) => `${mediaType}TimingInfo`;

const getTimestampOffset = (buffered, replaceSegmentsUntil, fallback) => {
if (replaceSegmentsUntil !== null) {
return fallback;
}

if (buffered.length) {
return buffered.end(buffered.length - 1);
}

return fallback;
};

/**
* Returns the timestamp offset to use for the segment.
*
Expand All @@ -202,10 +190,6 @@ const getTimestampOffset = (buffered, replaceSegmentsUntil, fallback) => {
* The estimated segment start
* @param {TimeRange[]} buffered
* The loader's buffer
* @param {boolean} calculateTimestampOffsetForEachSegment
* Feature flag to always calculate timestampOffset
* @param {number|null} replaceSegmentsUntil
* value if we switched quality recently and replacing buffered with a new quality
* @param {boolean} overrideCheck
* If true, no checks are made to see if the timestamp offset value should be set,
* but sets it directly to a value.
Expand All @@ -219,14 +203,8 @@ export const timestampOffsetForSegment = ({
currentTimeline,
startOfSegment,
buffered,
calculateTimestampOffsetForEachSegment,
replaceSegmentsUntil,
overrideCheck
}) => {
if (calculateTimestampOffsetForEachSegment) {
return getTimestampOffset(buffered, replaceSegmentsUntil, startOfSegment);
}

// Check to see if we are crossing a discontinuity to see if we need to set the
// timestamp offset on the transmuxer and source buffer.
//
Expand Down Expand Up @@ -270,7 +248,7 @@ export const timestampOffsetForSegment = ({
// should often be correct, it's better to rely on the buffered end, as the new
// content post discontinuity should line up with the buffered end as if it were
// time 0 for the new content.
return getTimestampOffset(buffered, replaceSegmentsUntil, startOfSegment);
return buffered.length ? buffered.end(buffered.length - 1) : startOfSegment;
};

/**
Expand Down Expand Up @@ -581,7 +559,6 @@ export default class SegmentLoader extends videojs.EventTarget {
this.shouldSaveSegmentTimingInfo_ = true;
this.parse708captions_ = settings.parse708captions;
this.useDtsForTimestampOffset_ = settings.useDtsForTimestampOffset;
this.calculateTimestampOffsetForEachSegment_ = settings.calculateTimestampOffsetForEachSegment;
this.captionServices_ = settings.captionServices;
this.exactManifestTimings = settings.exactManifestTimings;
this.addMetadataToTextTrack = settings.addMetadataToTextTrack;
Expand Down Expand Up @@ -652,8 +629,6 @@ export default class SegmentLoader extends videojs.EventTarget {

// ...for determining the fetch location
this.fetchAtBuffer_ = false;
// For comparing with currentTime when overwriting segments on fastQualityChange_ changes. Use -1 as the inactive flag.
this.replaceSegmentsUntil_ = null;

this.logger_ = logger(`SegmentLoader[${this.loaderType_}]`);

Expand Down Expand Up @@ -1182,26 +1157,18 @@ export default class SegmentLoader extends videojs.EventTarget {
}

/**
* Resets the segment loader ended and init properties.
* Delete all the buffered data and reset the SegmentLoader
*
* @param {Function} [done] an optional callback to be executed when the remove
* operation is complete
*/
resetLoaderProperties() {
resetEverything(done) {
this.ended_ = false;
this.activeInitSegmentId_ = null;
this.appendInitSegment_ = {
audio: true,
video: true
};
}

/**
* Delete all the buffered data and reset the SegmentLoader
*
* @param {Function} [done] an optional callback to be executed when the remove
* operation is complete
*/
resetEverything(done) {
this.replaceSegmentsUntil_ = null;
this.resetLoaderProperties();
this.resetLoader();

// remove from 0, the earliest point, to Infinity, to signify removal of everything.
Expand Down Expand Up @@ -1610,8 +1577,6 @@ export default class SegmentLoader extends videojs.EventTarget {
currentTimeline: this.currentTimeline_,
startOfSegment,
buffered: this.buffered_(),
calculateTimestampOffsetForEachSegment: this.calculateTimestampOffsetForEachSegment_,
replaceSegmentsUntil: this.replaceSegmentsUntil_,
overrideCheck
});

Expand Down Expand Up @@ -2478,7 +2443,7 @@ export default class SegmentLoader extends videojs.EventTarget {
//
// Even though keepOriginalTimestamps is set to true for the transmuxer, timestamp
// offset must be passed to the transmuxer for stream correcting adjustments.
if (this.transmuxer_ && this.shouldUpdateTransmuxerTimestampOffset_(segmentInfo)) {
if (this.shouldUpdateTransmuxerTimestampOffset_(segmentInfo.timestampOffset)) {
this.gopBuffer_.length = 0;
// gopsToAlignWith was set before the GOP buffer was cleared
segmentInfo.gopsToAlignWith = [];
Expand Down Expand Up @@ -2769,26 +2734,21 @@ export default class SegmentLoader extends videojs.EventTarget {
}
}

shouldUpdateTransmuxerTimestampOffset_(segmentInfo) {
if (this.calculateTimestampOffsetForEachSegment_) {
// is discontinuity
return segmentInfo.timeline !== this.currentTimeline_;
}

if (segmentInfo.timestampOffset === null) {
shouldUpdateTransmuxerTimestampOffset_(timestampOffset) {
if (timestampOffset === null) {
return false;
}

// note that we're potentially using the same timestamp offset for both video and
// audio

if (this.loaderType_ === 'main' &&
segmentInfo.timestampOffset !== this.sourceUpdater_.videoTimestampOffset()) {
timestampOffset !== this.sourceUpdater_.videoTimestampOffset()) {
return true;
}

if (!this.audioDisabled_ &&
segmentInfo.timestampOffset !== this.sourceUpdater_.audioTimestampOffset()) {
timestampOffset !== this.sourceUpdater_.audioTimestampOffset()) {
return true;
}

Expand Down Expand Up @@ -3090,14 +3050,7 @@ export default class SegmentLoader extends videojs.EventTarget {
this.logger_(`Appended ${segmentInfoString(segmentInfo)}`);

this.addSegmentMetadataCue_(segmentInfo);
if (this.replaceSegmentsUntil_ !== null && this.currentTime_() >= this.replaceSegmentsUntil_) {
this.replaceSegmentsUntil_ = null;
}

if (this.replaceSegmentsUntil_ === null) {
this.fetchAtBuffer_ = true;
}

this.fetchAtBuffer_ = true;
if (this.currentTimeline_ !== segmentInfo.timeline) {
this.timelineChangeController_.lastTimelineChange({
type: this.loaderType_,
Expand Down Expand Up @@ -3251,16 +3204,4 @@ export default class SegmentLoader extends videojs.EventTarget {

this.segmentMetadataTrack_.addCue(cue);
}

/**
* Public setter for defining the private replaceSegmentsUntil_ property, which
* determines when we can return fetchAtBuffer to true if overwriting the buffer.
*
* @param {number} bufferedEnd the end of the buffered range to replace segments
* until currentTime reaches this time.
*/
set replaceSegmentsUntil(bufferedEnd) {
this.logger_(`Replacing currently buffered segments until ${bufferedEnd}`);
this.replaceSegmentsUntil_ = bufferedEnd;
}
}
7 changes: 1 addition & 6 deletions src/source-updater.js
Original file line number Diff line number Diff line change
Expand Up @@ -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, prettyBuffered} from './util/vjs-compat';
import {createTimeRanges} from './util/vjs-compat';

const bufferTypes = [
'video',
Expand Down Expand Up @@ -297,11 +297,6 @@ const pushQueue = ({type, sourceUpdater, action, doneFn, name}) => {
};

const onUpdateend = (type, sourceUpdater) => (e) => {
const buffered = sourceUpdater[`${type}Buffered`]();
const bufferedAsString = prettyBuffered(buffered);

sourceUpdater.logger_(`${type} source buffer update end. Buffered: \n`, bufferedAsString);

// Although there should, in theory, be a pending action for any updateend receieved,
// there are some actions that may trigger updateend events without set definitions in
// the w3c spec. For instance, setting the duration on the media source may trigger
Expand Down
25 changes: 0 additions & 25 deletions src/util/vjs-compat.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,28 +24,3 @@ export function createTimeRanges(...args) {

return fn.apply(context, args);
}

/**
* Converts any buffered time range to a descriptive string
*
* @param {TimeRanges} buffered - time ranges
* @return {string} - descriptive string
*/
export function prettyBuffered(buffered) {
let result = '';

for (let i = 0; i < buffered.length; i++) {
const start = buffered.start(i);
const end = buffered.end(i);

const duration = end - start;

if (result.length) {
result += '\n';
}

result += `[${duration}](${start} -> ${end})`;
}

return result || 'empty';
}
3 changes: 0 additions & 3 deletions src/videojs-http-streaming.js
Original file line number Diff line number Diff line change
Expand Up @@ -698,7 +698,6 @@ class VhsHandler extends Component {
this.options_.useForcedSubtitles = this.options_.useForcedSubtitles || false;
this.options_.useNetworkInformationApi = this.options_.useNetworkInformationApi || false;
this.options_.useDtsForTimestampOffset = this.options_.useDtsForTimestampOffset || false;
this.options_.calculateTimestampOffsetForEachSegment = this.options_.calculateTimestampOffsetForEachSegment || false;
this.options_.customTagParsers = this.options_.customTagParsers || [];
this.options_.customTagMappers = this.options_.customTagMappers || [];
this.options_.cacheEncryptionKeys = this.options_.cacheEncryptionKeys || false;
Expand Down Expand Up @@ -752,7 +751,6 @@ class VhsHandler extends Component {
'useForcedSubtitles',
'useNetworkInformationApi',
'useDtsForTimestampOffset',
'calculateTimestampOffsetForEachSegment',
'exactManifestTimings',
'leastPixelDiffSelector'
].forEach((option) => {
Expand Down Expand Up @@ -1161,7 +1159,6 @@ class VhsHandler extends Component {
);

// Clear the buffer before switching playlists, since it may already contain unplayable segments
this.playlistController_.mainSegmentLoader_.resetEverything();
this.playlistController_.fastQualityChange_();
}
});
Expand Down
Loading