Skip to content

Commit

Permalink
Merge branch 'main' into fix/audio-and-video-only-drm
Browse files Browse the repository at this point in the history
  • Loading branch information
gkatsev authored Apr 5, 2021
2 parents d81db89 + 99480d5 commit 0e0928d
Show file tree
Hide file tree
Showing 12 changed files with 1,687 additions and 1,666 deletions.
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@
"mux.js": "5.11.0",
"video.js": "^6 || ^7"
},
"peerDependencies": {
"video.js": "^6 || ^7"
},
"devDependencies": {
"@rollup/plugin-replace": "^2.3.4",
"@videojs/generator-helpers": "~2.0.1",
Expand Down
13 changes: 13 additions & 0 deletions src/manifest.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,19 @@ export const parseManifest = ({
});
}
}
if (!manifest.targetDuration) {
let targetDuration = 10;

if (manifest.segments && manifest.segments.length) {
targetDuration = manifest
.segments.reduce((acc, s) => Math.max(acc, s.duration), 0);
}

if (onwarn) {
onwarn(`manifest has no targetDuration defaulting to ${targetDuration}`);
}
manifest.targetDuration = targetDuration;
}

return manifest;
};
Expand Down
38 changes: 29 additions & 9 deletions src/master-playlist-controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -301,10 +301,22 @@ export class MasterPlaylistController extends videojs.EventTarget {
const nextPlaylist = this.selectPlaylist();

if (this.shouldSwitchToMedia_(nextPlaylist)) {
this.masterPlaylistLoader_.media(nextPlaylist);
this.switchMedia_(nextPlaylist, 'abr');
}
}

switchMedia_(playlist, cause, delay) {
const oldMedia = this.media();
const oldId = oldMedia && (oldMedia.id || oldMedia.uri);
const newId = playlist.id || playlist.uri;

if (oldId && oldId !== newId) {
this.logger_(`switch media ${oldId} -> ${newId} from ${cause}`);
this.tech_.trigger({type: 'usage', name: `vhs-rendition-change-${cause}`});
}
this.masterPlaylistLoader_.media(playlist, delay);
}

/**
* Start a timer that periodically calls checkABR_
*
Expand Down Expand Up @@ -416,7 +428,7 @@ export class MasterPlaylistController extends videojs.EventTarget {

this.initialMedia_ = selectedMedia;

this.masterPlaylistLoader_.media(this.initialMedia_);
this.switchMedia_(this.initialMedia_, 'initial');

// Under the standard case where a source URL is provided, loadedplaylist will
// fire again since the playlist will be requested. In the case of vhs-json
Expand Down Expand Up @@ -617,7 +629,7 @@ export class MasterPlaylistController extends videojs.EventTarget {
const nextPlaylist = this.selectPlaylist();

if (this.shouldSwitchToMedia_(nextPlaylist)) {
this.masterPlaylistLoader_.media(nextPlaylist);
this.switchMedia_(nextPlaylist, 'bandwidthupdate');
}

this.tech_.trigger('bandwidthupdate');
Expand Down Expand Up @@ -743,7 +755,7 @@ export class MasterPlaylistController extends videojs.EventTarget {
return;
}

this.masterPlaylistLoader_.media(media);
this.switchMedia_(media, 'smooth-quality');

this.mainSegmentLoader_.resetLoader();
// don't need to reset audio as it is reset when media changes
Expand All @@ -763,7 +775,7 @@ export class MasterPlaylistController extends videojs.EventTarget {
return;
}

this.masterPlaylistLoader_.media(media);
this.switchMedia_(media, 'fast-quality');

// 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
Expand Down Expand Up @@ -1118,7 +1130,7 @@ export class MasterPlaylistController extends videojs.EventTarget {
(Date.now() - nextPlaylist.lastRequest) <= delayDuration;

// delay if it's a final rendition or if the last refresh is sooner than half targetDuration
return this.masterPlaylistLoader_.media(nextPlaylist, isFinalRendition || shouldDelay);
return this.switchMedia_(nextPlaylist, 'exclude', isFinalRendition || shouldDelay);
}

/**
Expand Down Expand Up @@ -1299,8 +1311,12 @@ export class MasterPlaylistController extends videojs.EventTarget {
return;
}

const suggestedPresentationDelay = this.masterPlaylistLoader_.master.suggestedPresentationDelay;
const mainSeekable = Vhs.Playlist.seekable(media, expired, suggestedPresentationDelay);
const master = this.masterPlaylistLoader_.master;
const mainSeekable = Vhs.Playlist.seekable(
media,
expired,
Vhs.Playlist.liveEdgeDelay(master, media)
);

if (mainSeekable.length === 0) {
return;
Expand All @@ -1314,7 +1330,11 @@ export class MasterPlaylistController extends videojs.EventTarget {
return;
}

audioSeekable = Vhs.Playlist.seekable(media, expired, suggestedPresentationDelay);
audioSeekable = Vhs.Playlist.seekable(
media,
expired,
Vhs.Playlist.liveEdgeDelay(master, media)
);

if (audioSeekable.length === 0) {
return;
Expand Down
51 changes: 33 additions & 18 deletions src/playlist-loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ export const updateSegments = (original, update, offset) => {
};

export const resolveSegmentUris = (segment, baseUri) => {
// preloadSegments will not have a uri at all
// preloadSegment will not have a uri at all
// as the segment isn't actually in the manifest yet, only parts
if (!segment.resolvedUri && segment.uri) {
segment.resolvedUri = resolveUrl(baseUri, segment.uri);
Expand Down Expand Up @@ -113,6 +113,19 @@ export const resolveSegmentUris = (segment, baseUri) => {
}
};

const getAllSegments = function(media) {
const segments = media.segments || [];

// a preloadSegment with only preloadHints is not currently
// a usable segment, only include a preloadSegment that has
// parts.
if (media.preloadSegment && media.preloadSegment.parts) {
segments.push(media.preloadSegment);
}

return segments;
};

// consider the playlist unchanged if the playlist object is the same or
// the number of segments is equal, the media sequence number is unchanged,
// and this playlist hasn't become the end of the playlist
Expand Down Expand Up @@ -147,6 +160,8 @@ export const updateMaster = (master, media, unchangedCheck = isPlaylistUnchanged

const mergedPlaylist = mergeOptions(playlist, media);

media.segments = getAllSegments(media);

// if the update could overlap existing segment information, merge the two segment lists
if (playlist.segments) {
mergedPlaylist.segments = updateSegments(
Expand Down Expand Up @@ -188,16 +203,16 @@ export const updateMaster = (master, media, unchangedCheck = isPlaylistUnchanged
*/
export const refreshDelay = (media, update) => {
const lastSegment = media.segments[media.segments.length - 1];
let delay;

if (update && lastSegment && lastSegment.duration) {
delay = lastSegment.duration * 1000;
} else {
// if the playlist is unchanged since the last reload or last segment duration
// cannot be determined, try again after half the target duration
delay = (media.targetDuration || 10) * 500;
const lastPart = lastSegment && lastSegment.parts && lastSegment.parts[lastSegment.parts.length - 1];
const lastDuration = lastPart && lastPart.duration || lastSegment && lastSegment.duration;

if (update && lastDuration) {
return lastDuration * 1000;
}
return delay;

// if the playlist is unchanged since the last reload or last segment duration
// cannot be determined, try again after half the target duration
return (media.partTargetDuration || media.targetDuration || 10) * 500;
};

/**
Expand Down Expand Up @@ -326,7 +341,7 @@ export default class PlaylistLoader extends EventTarget {
// merge this playlist into the master
const update = updateMaster(this.master, playlist);

this.targetDuration = playlist.targetDuration;
this.targetDuration = playlist.partTargetDuration || playlist.targetDuration;

if (update) {
this.master = update;
Expand Down Expand Up @@ -405,7 +420,7 @@ export default class PlaylistLoader extends EventTarget {
window.clearTimeout(this.finalRenditionTimeout);

if (shouldDelay) {
const delay = (playlist.targetDuration / 2) * 1000 || 5 * 1000;
const delay = ((playlist.partTargetDuration || playlist.targetDuration) / 2) * 1000 || 5 * 1000;

this.finalRenditionTimeout =
window.setTimeout(this.media.bind(this, playlist, false), delay);
Expand Down Expand Up @@ -538,7 +553,7 @@ export default class PlaylistLoader extends EventTarget {
const media = this.media();

if (shouldDelay) {
const delay = media ? (media.targetDuration / 2) * 1000 : 5 * 1000;
const delay = media ? ((media.partTargetDuration || media.targetDuration) / 2) * 1000 : 5 * 1000;

this.mediaUpdateTimeout = window.setTimeout(() => this.load(), delay);
return;
Expand Down Expand Up @@ -660,11 +675,11 @@ export default class PlaylistLoader extends EventTarget {
// then resolve URIs in advance, as they are usually done after a playlist request,
// which may not happen if the playlist is resolved.
manifest.playlists.forEach((playlist) => {
if (playlist.segments) {
playlist.segments.forEach((segment) => {
resolveSegmentUris(segment, playlist.resolvedUri);
});
}
playlist.segments = getAllSegments(playlist);

playlist.segments.forEach((segment) => {
resolveSegmentUris(segment, playlist.resolvedUri);
});
});
this.trigger('loadedplaylist');
if (!this.request) {
Expand Down
Loading

0 comments on commit 0e0928d

Please sign in to comment.