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

Jf video stats #781

Merged
merged 15 commits into from
Sep 23, 2022
3 changes: 3 additions & 0 deletions components/JFVideo.brs
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,9 @@ function onKeyEvent(key as string, press as boolean) as boolean
if m.top.Subtitles.count() and key = "down"
m.top.selectSubtitlePressed = true
return true
else if key = "up"
m.top.selectPlaybackInfoPressed = true
return true
end if

return false
Expand Down
1 change: 1 addition & 0 deletions components/JFVideo.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
<interface>
<field id="backPressed" type="boolean" alwaysNotify="true" />
<field id="selectSubtitlePressed" type="boolean" alwaysNotify="true" />
<field id="selectPlaybackInfoPressed" type="boolean" alwaysNotify="true" />
<field id="PlaySessionId" type="string" />
<field id="Subtitles" type="array" />
<field id="SelectedSubtitle" type="integer" />
Expand Down
49 changes: 49 additions & 0 deletions locale/en_US/translations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -734,5 +734,54 @@
<translation>Set the maximum amount of days a show should stay in the 'Next Up' list without watching it.</translation>
<extracomment>Settings Menu - Description for option</extracomment>
</message>
<message>
<source>Playback Information</source>
<translation>Playback Information</translation>
</message>
<message>
<source>Transcoding Information</source>
<translation>Transcoding Information</translation>
</message>
<message>
<source>Reason</source>
<translation>Reason</translation>
</message>
<message>
<source>Video Codec</source>
<translation>Video Codec</translation>
</message>
<message>
<source>Audio Codec</source>
<translation>Audio Codec</translation>
</message>
<message>
<source>direct</source>
<translation>direct</translation>
</message>
<message>
<source>Total Bitrate</source>
<translation>Total Bitrate</translation>
</message>
<message>
<source>Audio Channels</source>
<translation>Audio Channels</translation>
</message>
<message>
<source>Stream Information</source>
<translation>Stream Information</translation>
</message>
<message>
<source>Codec</source>
<translation>Codec</translation>
</message>
<message>
<source>Codec Tag</source>
<translation>Codec Tag</translation>
</message>
<message>
<source>Level</source>
<translation>Level</translation>
jimdogx marked this conversation as resolved.
Show resolved Hide resolved
<extracomment>Video profile level</extracomment>
</message>
</context>
</TS>
6 changes: 6 additions & 0 deletions source/Main.brs
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,12 @@ sub Main (args as dynamic) as void
changeSubtitleDuringPlayback(trackSelected)
end if
end if
else if isNodeEvent(msg, "selectPlaybackInfoPressed")
node = m.scene.focusedChild
if node.focusedChild <> invalid and node.focusedChild.isSubType("JFVideo")
info = GetPlaybackInfo()
show_dialog(tr("Playback Information"), info)
end if
else if isNodeEvent(msg, "state")
node = msg.getRoSGNode()
if node.state = "finished"
Expand Down
1 change: 1 addition & 0 deletions source/ShowScenes.brs
Original file line number Diff line number Diff line change
Expand Up @@ -467,6 +467,7 @@ function CreateVideoPlayerGroup(video_id, mediaSourceId = invalid, audio_stream_
if video = invalid then return invalid
if video.errorMsg = "introaborted" then return video
video.observeField("selectSubtitlePressed", m.port)
video.observeField("selectPlaybackInfoPressed", m.port)
video.observeField("state", m.port)

return video
Expand Down
120 changes: 103 additions & 17 deletions source/VideoPlayer.brs
Original file line number Diff line number Diff line change
Expand Up @@ -175,18 +175,18 @@ sub AddVideoContent(video, mediaSourceId, audio_stream_idx = 1, subtitle_idx = -
end if
if meta.live then mediaSourceId = "" ' Don't send mediaSourceId for Live media

playbackInfo = ItemPostPlaybackInfo(video.id, mediaSourceId, audio_stream_idx, subtitle_idx, playbackPosition)
m.playbackInfo = ItemPostPlaybackInfo(video.id, mediaSourceId, audio_stream_idx, subtitle_idx, playbackPosition)
video.videoId = video.id
video.mediaSourceId = mediaSourceId
video.audioIndex = audio_stream_idx

if playbackInfo = invalid
if m.playbackInfo = invalid
video.content = invalid
return
end if

params = {}
video.PlaySessionId = playbackInfo.PlaySessionId
video.PlaySessionId = m.playbackInfo.PlaySessionId

if meta.live
video.content.live = true
Expand All @@ -195,17 +195,17 @@ sub AddVideoContent(video, mediaSourceId, audio_stream_idx = 1, subtitle_idx = -

video.container = getContainerType(meta)

if playbackInfo.MediaSources[0] = invalid
playbackInfo = meta.json
if m.playbackInfo.MediaSources[0] = invalid
m.playbackInfo = meta.json
end if

subtitles = sortSubtitles(meta.id, playbackInfo.MediaSources[0].MediaStreams)
subtitles = sortSubtitles(meta.id, m.playbackInfo.MediaSources[0].MediaStreams)
video.Subtitles = subtitles["all"]

if meta.live
video.transcodeParams = {
"MediaSourceId": playbackInfo.MediaSources[0].Id,
"LiveStreamId": playbackInfo.MediaSources[0].LiveStreamId,
"MediaSourceId": m.playbackInfo.MediaSources[0].Id,
"LiveStreamId": m.playbackInfo.MediaSources[0].LiveStreamId,
"PlaySessionId": video.PlaySessionId
}
end if
Expand All @@ -214,7 +214,7 @@ sub AddVideoContent(video, mediaSourceId, audio_stream_idx = 1, subtitle_idx = -

' 'TODO: allow user selection of subtitle track before playback initiated, for now set to no subtitles

video.directPlaySupported = playbackInfo.MediaSources[0].SupportsDirectPlay
video.directPlaySupported = m.playbackInfo.MediaSources[0].SupportsDirectPlay
fully_external = false


Expand All @@ -223,19 +223,19 @@ sub AddVideoContent(video, mediaSourceId, audio_stream_idx = 1, subtitle_idx = -
' artifacts. If the user preference is set, and the only reason the server says we need to
' transcode is that the Envoding Level is not supported, then try to direct play but silently
' fall back to the transcode if that fails.
if meta.live = false and get_user_setting("playback.tryDirect.h264ProfileLevel") = "true" and playbackInfo.MediaSources[0].TranscodingUrl <> invalid and forceTranscoding = false and playbackInfo.MediaSources[0].MediaStreams[0].codec = "h264"
transcodingReasons = getTranscodeReasons(playbackInfo.MediaSources[0].TranscodingUrl)
if meta.live = false and get_user_setting("playback.tryDirect.h264ProfileLevel") = "true" and m.playbackInfo.MediaSources[0].TranscodingUrl <> invalid and forceTranscoding = false and m.playbackInfo.MediaSources[0].MediaStreams[0].codec = "h264"
jimdogx marked this conversation as resolved.
Show resolved Hide resolved
transcodingReasons = getTranscodeReasons(m.playbackInfo.MediaSources[0].TranscodingUrl)
if transcodingReasons.Count() = 1 and transcodingReasons[0] = "VideoLevelNotSupported"
video.directPlaySupported = true
video.transcodeAvailable = true
end if
end if

if video.directPlaySupported
protocol = LCase(playbackInfo.MediaSources[0].Protocol)
protocol = LCase(m.playbackInfo.MediaSources[0].Protocol)
if protocol <> "file"
uriRegex = CreateObject("roRegex", "^(.*:)//([A-Za-z0-9\-\.]+)(:[0-9]+)?(.*)$", "")
uri = uriRegex.Match(playbackInfo.MediaSources[0].Path)
uri = uriRegex.Match(m.playbackInfo.MediaSources[0].Path)
' proto $1, host $2, port $3, the-rest $4
localhost = CreateObject("roRegex", "^localhost$|^127(?:\.[0-9]+){0,2}\.[0-9]+$|^(?:0*\:)*?:?0*1$", "i")
' https://stackoverflow.com/questions/8426171/what-regex-will-match-all-loopback-addresses
Expand All @@ -246,7 +246,7 @@ sub AddVideoContent(video, mediaSourceId, audio_stream_idx = 1, subtitle_idx = -
video.content.url = buildURL(uri[4])
else
fully_external = true
video.content.url = playbackInfo.MediaSources[0].Path
video.content.url = m.playbackInfo.MediaSources[0].Path
end if
else:
params.append({
Expand All @@ -263,15 +263,15 @@ sub AddVideoContent(video, mediaSourceId, audio_stream_idx = 1, subtitle_idx = -
end if
video.isTranscoded = false
else
if playbackInfo.MediaSources[0].TranscodingUrl = invalid
if m.playbackInfo.MediaSources[0].TranscodingUrl = invalid
' If server does not provide a transcode URL, display a message to the user
m.global.sceneManager.callFunc("userMessage", tr("Error Getting Playback Information"), tr("An error was encountered while playing this item. Server did not provide required transcoding data."))
video.content = invalid
return
end if
' Get transcoding reason
video.transcodeReasons = getTranscodeReasons(playbackInfo.MediaSources[0].TranscodingUrl)
video.content.url = buildURL(playbackInfo.MediaSources[0].TranscodingUrl)
video.transcodeReasons = getTranscodeReasons(m.playbackInfo.MediaSources[0].TranscodingUrl)
video.content.url = buildURL(m.playbackInfo.MediaSources[0].TranscodingUrl)
video.isTranscoded = true
end if

Expand Down Expand Up @@ -444,3 +444,89 @@ sub autoPlayNextEpisode(videoID as string, showID as string)
m.global.sceneManager.callFunc("popScene")
end if
end sub

' Returns an array of playback info to be displayed during playback.
' In the future, with a custom playback info view, we can return an associated array.
function GetPlaybackInfo()
sessions = api_API().sessions.get()
if sessions <> invalid and sessions.Count() > 0
return GetTranscodingStats(sessions[0])
end if

errMsg = tr("Unable to get playback information")
return [errMsg]
end function

function GetTranscodingStats(session)
sessionStats = []

if session.TranscodingInfo <> invalid and session.TranscodingInfo.Count() > 0
transcodingReasons = session.TranscodingInfo.TranscodeReasons
videoCodec = session.TranscodingInfo.VideoCodec
audioCodec = session.TranscodingInfo.AudioCodec
totalBitrate = session.TranscodingInfo.Bitrate
audioChannels = session.TranscodingInfo.AudioChannels

if transcodingReasons <> invalid and transcodingReasons.Count() > 0
sessionStats.push("** " + tr("Transcoding Information") + " **")
for each item in transcodingReasons
sessionStats.push(tr("Reason") + ": " + item)
end for
end if

if videoCodec <> invalid
data = tr("Video Codec") + ": " + videoCodec
if session.TranscodingInfo.IsVideoDirect
data = data + " (" + tr("direct") + ")"
end if
sessionStats.push(data)
end if

if audioCodec <> invalid
data = tr("Audio Codec") + ": " + audioCodec
if session.TranscodingInfo.IsAudioDirect
data = data + " (" + tr("direct") + ")"
end if
sessionStats.push(data)
end if

if totalBitrate <> invalid
data = tr("Total Bitrate") + ": " + getDisplayBitrate(totalBitrate)
sessionStats.push(data)
end if

if audioChannels <> invalid
data = tr("Audio Channels") + ": " + Str(audioChannels)
sessionStats.push(data)
end if
end if

if m.playbackInfo <> invalid and m.playbackInfo.mediaSources <> invalid and m.playbackInfo.mediaSources.Count() > 0
if m.playbackInfo.mediaSources[0].MediaStreams <> invalid and m.playbackInfo.mediaSources[0].MediaStreams.Count() > 0
jimdogx marked this conversation as resolved.
Show resolved Hide resolved
stream = m.playbackInfo.mediaSources[0].MediaStreams[0]
sessionStats.push("** " + tr("Stream Information") + " **")
if stream.Codec <> invalid
jimdogx marked this conversation as resolved.
Show resolved Hide resolved
data = tr("Codec") + ": " + stream.Codec
sessionStats.push(data)
end if
if stream.CodecTag <> invalid
jimdogx marked this conversation as resolved.
Show resolved Hide resolved
data = tr("Codec Tag") + ": " + stream.CodecTag
sessionStats.push(data)
end if
if stream.Level <> invalid
jimdogx marked this conversation as resolved.
Show resolved Hide resolved
data = tr("Level") + ": " + Str(stream.Level)
sessionStats.push(data)
end if
end if
end if

return sessionStats
end function

function getDisplayBitrate(bitrate)
if bitrate > 1000000
return Str(Fix(bitrate / 1000000)) + " Mbps"
else
return Str(Fix(bitrate / 1000)) + " Kbps"
end if
end function