mirror of
https://github.com/jellyfin/jellyfin-web
synced 2025-03-30 19:56:21 +00:00
Merge pull request #4761 from dmitrylyzo/hls-direct-play
This commit is contained in:
commit
9435e3172d
3 changed files with 34 additions and 7 deletions
|
@ -35,6 +35,7 @@ import { setBackdropTransparency, TRANSPARENCY_LEVEL } from '../../components/ba
|
||||||
import { PluginType } from '../../types/plugin.ts';
|
import { PluginType } from '../../types/plugin.ts';
|
||||||
import Events from '../../utils/events.ts';
|
import Events from '../../utils/events.ts';
|
||||||
import { includesAny } from '../../utils/container.ts';
|
import { includesAny } from '../../utils/container.ts';
|
||||||
|
import { isHls } from '../../utils/mediaSource.ts';
|
||||||
import debounce from 'lodash-es/debounce';
|
import debounce from 'lodash-es/debounce';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -69,12 +70,12 @@ function tryRemoveElement(elem) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function enableNativeTrackSupport(currentSrc, track) {
|
function enableNativeTrackSupport(mediaSource, track) {
|
||||||
if (track?.DeliveryMethod === 'Embed') {
|
if (track?.DeliveryMethod === 'Embed') {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (browser.firefox && (currentSrc || '').toLowerCase().includes('.m3u8')) {
|
if (browser.firefox && isHls(mediaSource)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -341,15 +342,13 @@ export class HtmlVideoPlayer {
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
updateVideoUrl(streamInfo) {
|
updateVideoUrl(streamInfo) {
|
||||||
const isHls = streamInfo.url.toLowerCase().includes('.m3u8');
|
|
||||||
|
|
||||||
const mediaSource = streamInfo.mediaSource;
|
const mediaSource = streamInfo.mediaSource;
|
||||||
const item = streamInfo.item;
|
const item = streamInfo.item;
|
||||||
|
|
||||||
// Huge hack alert. Safari doesn't seem to like if the segments aren't available right away when playback starts
|
// Huge hack alert. Safari doesn't seem to like if the segments aren't available right away when playback starts
|
||||||
// This will start the transcoding process before actually feeding the video url into the player
|
// This will start the transcoding process before actually feeding the video url into the player
|
||||||
// Edit: Also seeing stalls from hls.js
|
// Edit: Also seeing stalls from hls.js
|
||||||
if (mediaSource && item && !mediaSource.RunTimeTicks && isHls && streamInfo.playMethod === 'Transcode' && (browser.iOS || browser.osx)) {
|
if (mediaSource && item && !mediaSource.RunTimeTicks && isHls(mediaSource) && streamInfo.playMethod === 'Transcode' && (browser.iOS || browser.osx)) {
|
||||||
const hlsPlaylistUrl = streamInfo.url.replace('master.m3u8', 'live.m3u8');
|
const hlsPlaylistUrl = streamInfo.url.replace('master.m3u8', 'live.m3u8');
|
||||||
|
|
||||||
loading.show();
|
loading.show();
|
||||||
|
@ -513,7 +512,7 @@ export class HtmlVideoPlayer {
|
||||||
elem.crossOrigin = crossOrigin;
|
elem.crossOrigin = crossOrigin;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (enableHlsJsPlayer(options.mediaSource.RunTimeTicks, 'Video') && val.includes('.m3u8')) {
|
if (enableHlsJsPlayer(options.mediaSource.RunTimeTicks, 'Video') && isHls(options.mediaSource)) {
|
||||||
return this.setSrcWithHlsJs(elem, options, val);
|
return this.setSrcWithHlsJs(elem, options, val);
|
||||||
} else if (options.playMethod !== 'Transcode' && options.mediaSource.Container === 'flv') {
|
} else if (options.playMethod !== 'Transcode' && options.mediaSource.Container === 'flv') {
|
||||||
return this.setSrcWithFlvJs(elem, options, val);
|
return this.setSrcWithFlvJs(elem, options, val);
|
||||||
|
@ -1558,7 +1557,7 @@ export class HtmlVideoPlayer {
|
||||||
})[0];
|
})[0];
|
||||||
|
|
||||||
this.setTrackForDisplay(this.#mediaElement, track, targetTextTrackIndex);
|
this.setTrackForDisplay(this.#mediaElement, track, targetTextTrackIndex);
|
||||||
if (enableNativeTrackSupport(this.#currentSrc, track)) {
|
if (enableNativeTrackSupport(this._currentPlayOptions?.mediaSource, track)) {
|
||||||
if (streamIndex !== -1) {
|
if (streamIndex !== -1) {
|
||||||
this.setCueAppearance();
|
this.setCueAppearance();
|
||||||
}
|
}
|
||||||
|
|
|
@ -718,6 +718,15 @@ export default function (options) {
|
||||||
enableFmp4Hls = false;
|
enableFmp4Hls = false;
|
||||||
}
|
}
|
||||||
if (hlsInFmp4VideoCodecs.length && hlsInFmp4VideoAudioCodecs.length && enableFmp4Hls) {
|
if (hlsInFmp4VideoCodecs.length && hlsInFmp4VideoAudioCodecs.length && enableFmp4Hls) {
|
||||||
|
// HACK: Since there is no filter for TS/MP4 in the API, specify HLS support in general and rely on retry after DirectPlay error
|
||||||
|
// FIXME: Need support for {Container: 'mp4', Protocol: 'hls'} or {Container: 'hls', SubContainer: 'mp4'}
|
||||||
|
profile.DirectPlayProfiles.push({
|
||||||
|
Container: 'hls',
|
||||||
|
Type: 'Video',
|
||||||
|
VideoCodec: hlsInFmp4VideoCodecs.join(','),
|
||||||
|
AudioCodec: hlsInFmp4VideoAudioCodecs.join(',')
|
||||||
|
});
|
||||||
|
|
||||||
profile.TranscodingProfiles.push({
|
profile.TranscodingProfiles.push({
|
||||||
Container: 'mp4',
|
Container: 'mp4',
|
||||||
Type: 'Video',
|
Type: 'Video',
|
||||||
|
@ -732,6 +741,15 @@ export default function (options) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hlsInTsVideoCodecs.length && hlsInTsVideoAudioCodecs.length) {
|
if (hlsInTsVideoCodecs.length && hlsInTsVideoAudioCodecs.length) {
|
||||||
|
// HACK: Since there is no filter for TS/MP4 in the API, specify HLS support in general and rely on retry after DirectPlay error
|
||||||
|
// FIXME: Need support for {Container: 'ts', Protocol: 'hls'} or {Container: 'hls', SubContainer: 'ts'}
|
||||||
|
profile.DirectPlayProfiles.push({
|
||||||
|
Container: 'hls',
|
||||||
|
Type: 'Video',
|
||||||
|
VideoCodec: hlsInTsVideoCodecs.join(','),
|
||||||
|
AudioCodec: hlsInTsVideoAudioCodecs.join(',')
|
||||||
|
});
|
||||||
|
|
||||||
profile.TranscodingProfiles.push({
|
profile.TranscodingProfiles.push({
|
||||||
Container: 'ts',
|
Container: 'ts',
|
||||||
Type: 'Video',
|
Type: 'Video',
|
||||||
|
|
10
src/utils/mediaSource.ts
Normal file
10
src/utils/mediaSource.ts
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
import type { MediaSourceInfo } from '@jellyfin/sdk/lib/generated-client';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the media source is an HLS stream.
|
||||||
|
* @param mediaSource The media source.
|
||||||
|
* @returns _true_ if the media source is an HLS stream, _false_ otherwise.
|
||||||
|
*/
|
||||||
|
export function isHls(mediaSource: MediaSourceInfo|null|undefined): boolean {
|
||||||
|
return (mediaSource?.TranscodingSubProtocol || mediaSource?.Container) === 'hls';
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue