Skip to content

Commit 6f9b71f

Browse files
committed
Update code docs
1 parent 713aaa4 commit 6f9b71f

7 files changed

Lines changed: 52 additions & 15 deletions

docs/components_ItemGrid_LoadVideoContentTask.bs.html

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,18 +48,19 @@
4848
mediaSourceId = invalid
4949
audio_stream_idx = m.top.selectedAudioStreamIndex
5050
forceTranscoding = false
51+
bypassDoviPreservation = m.top.bypassDoviPreservation
5152

52-
m.top.content = [LoadItems_VideoPlayer(id, mediaSourceId, audio_stream_idx, forceTranscoding)]
53+
m.top.content = [LoadItems_VideoPlayer(id, mediaSourceId, audio_stream_idx, forceTranscoding, bypassDoviPreservation)]
5354
end sub
5455

55-
function LoadItems_VideoPlayer(id as string, mediaSourceId as dynamic, audio_stream_idx = 1 as integer, forceTranscoding = false as boolean) as dynamic
56+
function LoadItems_VideoPlayer(id as string, mediaSourceId as dynamic, audio_stream_idx = 1 as integer, forceTranscoding = false as boolean, bypassDoviPreservation = false as boolean) as dynamic
5657

5758
video = {}
5859
video.id = id
5960
video.content = createObject("RoSGNode", "ContentNode")
6061
video.content.addField("trickplayMetadata", "assocarray", false)
6162

62-
LoadItems_AddVideoContent(video, mediaSourceId, audio_stream_idx, forceTranscoding)
63+
LoadItems_AddVideoContent(video, mediaSourceId, audio_stream_idx, forceTranscoding, bypassDoviPreservation)
6364

6465
if not isValid(video.content)
6566
return invalid
@@ -68,7 +69,7 @@
6869
return video
6970
end function
7071

71-
sub LoadItems_AddVideoContent(video as object, mediaSourceId as dynamic, audio_stream_idx = 1 as integer, forceTranscoding = false as boolean)
72+
sub LoadItems_AddVideoContent(video as object, mediaSourceId as dynamic, audio_stream_idx = 1 as integer, forceTranscoding = false as boolean, bypassDoviPreservation = false as boolean)
7273

7374
meta = ItemMetaData(video.id)
7475
if not isValid(meta)
@@ -220,7 +221,7 @@
220221
if meta.live then mediaSourceId = ""
221222

222223
' Call ItemPostPlaybackInfo ONCE with final subtitle_idx
223-
m.playbackInfo = ItemPostPlaybackInfo(video.id, mediaSourceId, audio_stream_idx, subtitle_idx, playbackPosition, meta)
224+
m.playbackInfo = ItemPostPlaybackInfo(video.id, mediaSourceId, audio_stream_idx, subtitle_idx, playbackPosition, meta, bypassDoviPreservation)
224225
if not isValid(m.playbackInfo)
225226
video.errorMsg = "Error loading playback info"
226227
video.content = invalid
@@ -312,6 +313,16 @@
312313
video.transcodeReasons = getTranscodeReasons(m.playbackInfo.MediaSources[0].TranscodingUrl)
313314
video.content.url = buildURL(m.playbackInfo.MediaSources[0].TranscodingUrl)
314315
video.isTranscoded = true
316+
317+
' If DoVi preservation caused this transcode, flag that direct play is a viable buffer-overflow fallback.
318+
' VideoRangeTypeNotSupported is the reason Jellyfin returns when our DoVi container profile blocks the MKV.
319+
' On a buffer:loop: error the player will retry with bypassDoviPreservation=true, letting the server
320+
' re-evaluate without the DoVi constraint and (usually) grant direct play instead.
321+
if userSettings.playbackPreserveDovi and not bypassDoviPreservation
322+
if arrayHasValue(video.transcodeReasons, "VideoRangeTypeNotSupported")
323+
video.doviDirectPlayFallbackAvailable = true
324+
end if
325+
end if
315326
end if
316327

317328
setCertificateAuthority(video.content)

docs/components_manager_ViewCreator.bs.html

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,8 @@
232232
' Playback state change event handlers
233233
sub onStateChange()
234234
if LCase(m.view.state) = "finished"
235+
' Don't pop the scene mid-retry; the DoVi fallback calls stop which can fire "finished".
236+
if isValid(m.view.isRetrying) and m.view.isRetrying then return
235237
sceneManager = m.global.sceneManager
236238
queueManager = m.global.queueManager
237239

docs/components_video_VideoPlayerView.bs.html

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -514,6 +514,8 @@
514514
m.LoadMetaDataTask.unobserveField("content")
515515
m.LoadMetaDataTask.control = "STOP"
516516

517+
m.top.isRetrying = false
518+
517519
videoContent = m.LoadMetaDataTask.content
518520
m.LoadMetaDataTask.content = []
519521

@@ -539,6 +541,11 @@
539541
m.chapters = videoContent[0].chapters
540542
m.top.showID = videoContent[0].showID
541543
m.top.cachedPlaybackInfo = videoContent[0].playbackInfo
544+
m.top.doviDirectPlayFallbackAvailable = isValid(videoContent[0].doviDirectPlayFallbackAvailable) and videoContent[0].doviDirectPlayFallbackAvailable
545+
546+
' Reset bypass flag so subsequent reloads (audio/subtitle changes) re-evaluate DoVi naturally.
547+
' It will be set back to true by the error handler if another buffer overflow occurs.
548+
m.LoadMetaDataTask.bypassDoviPreservation = false
542549

543550
if isValidAndNotEmpty(videoContent[0].json)
544551
m.osd.json = formatJson(videoContent[0].json)
@@ -894,7 +901,25 @@
894901

895902
print m.top.errorInfo
896903

897-
if not m.playReported and m.top.transcodeAvailable
904+
' Detect a Roku video buffer overflow (buffer:loop: source) caused by DoVi transcoding.
905+
' When DoVi preservation forced a transcode and the HLS segments overflow the device buffer,
906+
' retry with direct play by bypassing the DoVi container profile injection.
907+
isBufferLoopError = isValid(m.top.errorInfo) and isValid(m.top.errorInfo.source) and m.top.errorInfo.source = "buffer:loop:"
908+
909+
if isBufferLoopError and m.top.doviDirectPlayFallbackAvailable
910+
m.log.warn("Buffer overflow in DoVi transcode; falling back to direct play", m.currentItem.id)
911+
m.top.doviDirectPlayFallbackAvailable = false ' prevent retry loop if direct play also fails
912+
m.global.queueManager.callFunc("setTopStartingPoint", int(m.top.position) * 10000000&)
913+
' Prevents ViewCreator popping the scene when stop causes Roku to fire "finished".
914+
m.top.isRetrying = true
915+
m.top.control = "stop"
916+
m.LoadMetaDataTask.bypassDoviPreservation = true
917+
m.LoadMetaDataTask.selectedSubtitleIndex = m.top.SelectedSubtitle
918+
m.LoadMetaDataTask.selectedAudioStreamIndex = m.top.audioIndex
919+
m.LoadMetaDataTask.itemId = m.currentItem.id
920+
m.LoadMetaDataTask.observeField("content", "onVideoContentLoaded")
921+
m.LoadMetaDataTask.control = "RUN"
922+
else if not m.playReported and m.top.transcodeAvailable
898923
m.log.info("retrying with transcoding", m.currentItem.id, m.top.SelectedSubtitle, m.top.audioIndex)
899924
m.top.retryWithTranscoding = true ' If playback was not reported, retry with transcoding
900925
else

docs/module-Items.html

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

docs/module-LoadVideoContentTask.html

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

docs/source_api_Items.bs.html

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import "pkg:/source/utils/deviceCapabilities.bs"
77
import "pkg:/source/utils/misc.bs"
88

9-
function ItemPostPlaybackInfo(id as string, mediaSourceId = "" as string, audioTrackIndex = -1 as integer, subtitleTrackIndex = SubtitleSelection.none as integer, startTimeTicks = 0& as longinteger, videoMetadata = invalid as dynamic)
9+
function ItemPostPlaybackInfo(id as string, mediaSourceId = "" as string, audioTrackIndex = -1 as integer, subtitleTrackIndex = SubtitleSelection.none as integer, startTimeTicks = 0& as longinteger, videoMetadata = invalid as dynamic, bypassDoviPreservation = false as boolean)
1010
globalUser = m.global.user
1111
postData = {
1212
"UserId": globalUser.id,
@@ -82,8 +82,9 @@
8282
end if
8383

8484
' DOVI not supported using MKV container, so force remux for DOVI content
85-
' Only run DOVI logic if the user setting exists and is enabled
86-
if isValid(mediaStreams) and isValid(globalUser.settings.playbackPreserveDovi) and globalUser.settings.playbackPreserveDovi
85+
' Only run DOVI logic if the user setting exists and is enabled, and caller has not bypassed it
86+
' (bypassDoviPreservation is set when retrying after a buffer overflow to allow direct play)
87+
if not bypassDoviPreservation and isValid(mediaStreams) and isValid(globalUser.settings.playbackPreserveDovi) and globalUser.settings.playbackPreserveDovi
8788
' Check if device supports DOVI before proceeding
8889
deviceSupportsDovi = false
8990
di = CreateObject("roDeviceInfo")

docs/source_utils_deviceCapabilities.bs.html

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -349,10 +349,8 @@
349349
' Video codecs
350350
videoCodecList = "h264"
351351

352-
if container = "mp4"
353-
if di.CanDecodeVideo({ Codec: "hevc", Container: container }).Result
354-
videoCodecList = "hevc,h265," + videoCodecList
355-
end if
352+
if di.CanDecodeVideo({ Codec: "hevc", Container: container }).Result
353+
videoCodecList = "hevc,h265," + videoCodecList
356354
end if
357355

358356
if di.CanDecodeVideo({ Codec: "mpeg4 avc", Container: container }).Result

0 commit comments

Comments
 (0)