From a66e4d6d1a182650a6d1187d08151704bc3b2968 Mon Sep 17 00:00:00 2001 From: gnattu Date: Tue, 28 May 2024 01:33:29 +0800 Subject: [PATCH 1/7] Allow VideoStreamCopy for remote source fallback During LiveTV playback, a fallback is usually needed because the first attempt would be try to direct play the remote url of that channel. If that failed we should still allow stream copy because the playback would still success in this case. The server side will enforce the most compatible format (h264+ts) and still do transcoding if that condition is not met. --- src/components/playback/playbackmanager.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/playback/playbackmanager.js b/src/components/playback/playbackmanager.js index c11e176df31..e4d18604607 100644 --- a/src/components/playback/playbackmanager.js +++ b/src/components/playback/playbackmanager.js @@ -3304,10 +3304,10 @@ class PlaybackManager { const startTime = getCurrentTicks(player) || streamInfo.playerStartPositionTicks; changeStream(player, startTime, { - // force transcoding + // force transcoding and only allow remuxing for remote source like liveTV EnableDirectPlay: false, EnableDirectStream: false, - AllowVideoStreamCopy: false, + AllowVideoStreamCopy: streamInfo.item.LocationType === 'Remote' ? true : false, AllowAudioStreamCopy: currentlyPreventsAudioStreamCopy || currentlyPreventsVideoStreamCopy ? false : null }); From 2b59a9f99877d52fe79d39ea00d5dae9c9bfbbbd Mon Sep 17 00:00:00 2001 From: gnattu Date: Tue, 28 May 2024 01:41:56 +0800 Subject: [PATCH 2/7] fix lint --- src/components/playback/playbackmanager.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/playback/playbackmanager.js b/src/components/playback/playbackmanager.js index e4d18604607..819abfee79c 100644 --- a/src/components/playback/playbackmanager.js +++ b/src/components/playback/playbackmanager.js @@ -3307,7 +3307,7 @@ class PlaybackManager { // force transcoding and only allow remuxing for remote source like liveTV EnableDirectPlay: false, EnableDirectStream: false, - AllowVideoStreamCopy: streamInfo.item.LocationType === 'Remote' ? true : false, + AllowVideoStreamCopy: streamInfo.item.LocationType === 'Remote', AllowAudioStreamCopy: currentlyPreventsAudioStreamCopy || currentlyPreventsVideoStreamCopy ? false : null }); From 20e29b81b5f76cf694d52b38bea2d2b06cb9996a Mon Sep 17 00:00:00 2001 From: gnattu Date: Tue, 28 May 2024 05:45:29 +0800 Subject: [PATCH 3/7] Always try transcode as last resort --- src/components/playback/playbackmanager.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/components/playback/playbackmanager.js b/src/components/playback/playbackmanager.js index 819abfee79c..666034e6fde 100644 --- a/src/components/playback/playbackmanager.js +++ b/src/components/playback/playbackmanager.js @@ -3296,18 +3296,21 @@ class PlaybackManager { const streamInfo = error.streamInfo || getPlayerData(player).streamInfo; if (streamInfo?.url) { + const isAlreadyFallbacking = streamInfo.url.toLowerCase().includes('transcodereasons=directplayerror'); const currentlyPreventsVideoStreamCopy = streamInfo.url.toLowerCase().indexOf('allowvideostreamcopy=false') !== -1; const currentlyPreventsAudioStreamCopy = streamInfo.url.toLowerCase().indexOf('allowaudiostreamcopy=false') !== -1; // Auto switch to transcoding if (enablePlaybackRetryWithTranscoding(streamInfo, errorType, currentlyPreventsVideoStreamCopy, currentlyPreventsAudioStreamCopy)) { const startTime = getCurrentTicks(player) || streamInfo.playerStartPositionTicks; + const isRemoteSource = streamInfo.item.LocationType === 'Remote'; + // force transcoding and only allow remuxing for remote source like liveTV, but only for initial trial + const tryVideoStreamCopy = isRemoteSource && !isAlreadyFallbacking; changeStream(player, startTime, { - // force transcoding and only allow remuxing for remote source like liveTV EnableDirectPlay: false, EnableDirectStream: false, - AllowVideoStreamCopy: streamInfo.item.LocationType === 'Remote', + AllowVideoStreamCopy: tryVideoStreamCopy, AllowAudioStreamCopy: currentlyPreventsAudioStreamCopy || currentlyPreventsVideoStreamCopy ? false : null }); From 6feb46fecbe78d9cb23a9252f0b740982690dd6f Mon Sep 17 00:00:00 2001 From: gnattu Date: Tue, 28 May 2024 20:27:11 +0800 Subject: [PATCH 4/7] Don't check specific reason Co-authored-by: Dmitry Lyzo <56478732+dmitrylyzo@users.noreply.github.com> --- src/components/playback/playbackmanager.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/playback/playbackmanager.js b/src/components/playback/playbackmanager.js index 666034e6fde..a8f009ed72d 100644 --- a/src/components/playback/playbackmanager.js +++ b/src/components/playback/playbackmanager.js @@ -3296,7 +3296,7 @@ class PlaybackManager { const streamInfo = error.streamInfo || getPlayerData(player).streamInfo; if (streamInfo?.url) { - const isAlreadyFallbacking = streamInfo.url.toLowerCase().includes('transcodereasons=directplayerror'); + const isAlreadyFallbacking = streamInfo.url.toLowerCase().includes('transcodereasons'); const currentlyPreventsVideoStreamCopy = streamInfo.url.toLowerCase().indexOf('allowvideostreamcopy=false') !== -1; const currentlyPreventsAudioStreamCopy = streamInfo.url.toLowerCase().indexOf('allowaudiostreamcopy=false') !== -1; From adcea4467d05a737d0fad734e34b4e69778409e8 Mon Sep 17 00:00:00 2001 From: gnattu Date: Wed, 29 May 2024 00:20:10 +0800 Subject: [PATCH 5/7] Fix HLS stream check The TranscodingSubProtocol is no longer nullable on the server side and direct playing media will have a value of http. Check container type when TranscodingSubProtocol is not HLS --- src/utils/mediaSource.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/utils/mediaSource.ts b/src/utils/mediaSource.ts index ef196db60f5..2ee56bfc03a 100644 --- a/src/utils/mediaSource.ts +++ b/src/utils/mediaSource.ts @@ -6,6 +6,9 @@ import type { MediaSourceInfo } from '@jellyfin/sdk/lib/generated-client'; * @returns _true_ if the media source is an HLS stream, _false_ otherwise. */ export function isHls(mediaSource: MediaSourceInfo|null|undefined): boolean { - const protocol = mediaSource?.TranscodingSubProtocol || mediaSource?.Container; - return protocol?.toUpperCase() === 'HLS'; + if (mediaSource?.TranscodingSubProtocol?.toUpperCase() === 'HLS') { + return true; + } + + return mediaSource?.Container?.toUpperCase() === 'HLS'; } From a67fd2e5acdc252722283077c4e8d25daa66dfff Mon Sep 17 00:00:00 2001 From: gnattu Date: Thu, 30 May 2024 00:12:00 +0800 Subject: [PATCH 6/7] Try EnableDirectStream when possible Co-authored-by: Dmitry Lyzo <56478732+dmitrylyzo@users.noreply.github.com> --- src/components/playback/playbackmanager.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/playback/playbackmanager.js b/src/components/playback/playbackmanager.js index a8f009ed72d..54541337a18 100644 --- a/src/components/playback/playbackmanager.js +++ b/src/components/playback/playbackmanager.js @@ -3309,7 +3309,7 @@ class PlaybackManager { changeStream(player, startTime, { EnableDirectPlay: false, - EnableDirectStream: false, + EnableDirectStream: tryVideoStreamCopy, AllowVideoStreamCopy: tryVideoStreamCopy, AllowAudioStreamCopy: currentlyPreventsAudioStreamCopy || currentlyPreventsVideoStreamCopy ? false : null }); From 3a0be7d3451f7457f7e264987e660b4601b6331f Mon Sep 17 00:00:00 2001 From: gnattu Date: Thu, 30 May 2024 00:12:16 +0800 Subject: [PATCH 7/7] Simplify syntax Co-authored-by: Dmitry Lyzo <56478732+dmitrylyzo@users.noreply.github.com> --- src/utils/mediaSource.ts | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/utils/mediaSource.ts b/src/utils/mediaSource.ts index 2ee56bfc03a..5b11ee39674 100644 --- a/src/utils/mediaSource.ts +++ b/src/utils/mediaSource.ts @@ -6,9 +6,6 @@ import type { MediaSourceInfo } from '@jellyfin/sdk/lib/generated-client'; * @returns _true_ if the media source is an HLS stream, _false_ otherwise. */ export function isHls(mediaSource: MediaSourceInfo|null|undefined): boolean { - if (mediaSource?.TranscodingSubProtocol?.toUpperCase() === 'HLS') { - return true; - } - - return mediaSource?.Container?.toUpperCase() === 'HLS'; + return mediaSource?.TranscodingSubProtocol?.toUpperCase() === 'HLS' + || mediaSource?.Container?.toUpperCase() === 'HLS'; }