commit
1832dfd0d6
|
@ -134,6 +134,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
|
||||
|
|
|
@ -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" />
|
||||
|
|
|
@ -738,5 +738,83 @@
|
|||
<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>
|
||||
<extracomment>Video profile level</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Bit Rate</source>
|
||||
<translation>Bit Rate</translation>
|
||||
<extracomment>Video streaming bit rate</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Container</source>
|
||||
<translation>Container</translation>
|
||||
<extracomment>Video streaming container</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Size</source>
|
||||
<translation>Size</translation>
|
||||
<extracomment>Video size</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Video range type</source>
|
||||
<translation>Video range type</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Pixel format</source>
|
||||
<translation>Pixel format</translation>
|
||||
<extracomment>Video pixel format</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>WxH</source>
|
||||
<translation>WxH</translation>
|
||||
<extracomment>Video width x height</extracomment>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
||||
|
|
|
@ -385,6 +385,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 selectedItem.Type = "TvChannel" and node.state = "finished"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -170,18 +170,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
|
||||
|
@ -190,17 +190,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
|
||||
|
@ -209,7 +209,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
|
||||
|
||||
|
||||
|
@ -218,8 +218,8 @@ 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"
|
||||
transcodingReasons = getTranscodeReasons(m.playbackInfo.MediaSources[0].TranscodingUrl)
|
||||
if transcodingReasons.Count() = 1 and transcodingReasons[0] = "VideoLevelNotSupported"
|
||||
video.directPlaySupported = true
|
||||
video.transcodeAvailable = true
|
||||
|
@ -227,10 +227,10 @@ sub AddVideoContent(video, mediaSourceId, audio_stream_idx = 1, subtitle_idx = -
|
|||
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
|
||||
|
@ -241,7 +241,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({
|
||||
|
@ -258,15 +258,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
|
||||
|
||||
|
@ -435,3 +435,135 @@ 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 isValid(session.TranscodingInfo) 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 isValid(transcodingReasons) and transcodingReasons.Count() > 0
|
||||
sessionStats.push("** " + tr("Transcoding Information") + " **")
|
||||
for each item in transcodingReasons
|
||||
sessionStats.push(tr("Reason") + ": " + item)
|
||||
end for
|
||||
end if
|
||||
|
||||
if isValid(videoCodec)
|
||||
data = tr("Video Codec") + ": " + videoCodec
|
||||
if session.TranscodingInfo.IsVideoDirect
|
||||
data = data + " (" + tr("direct") + ")"
|
||||
end if
|
||||
sessionStats.push(data)
|
||||
end if
|
||||
|
||||
if isValid(audioCodec)
|
||||
data = tr("Audio Codec") + ": " + audioCodec
|
||||
if session.TranscodingInfo.IsAudioDirect
|
||||
data = data + " (" + tr("direct") + ")"
|
||||
end if
|
||||
sessionStats.push(data)
|
||||
end if
|
||||
|
||||
if isValid(totalBitrate)
|
||||
data = tr("Total Bitrate") + ": " + getDisplayBitrate(totalBitrate)
|
||||
sessionStats.push(data)
|
||||
end if
|
||||
|
||||
if isValid(audioChannels)
|
||||
data = tr("Audio Channels") + ": " + Str(audioChannels)
|
||||
sessionStats.push(data)
|
||||
end if
|
||||
end if
|
||||
|
||||
if havePlaybackInfo()
|
||||
stream = m.playbackInfo.mediaSources[0].MediaStreams[0]
|
||||
sessionStats.push("** " + tr("Stream Information") + " **")
|
||||
if isValid(stream.Container)
|
||||
data = tr("Container") + ": " + stream.Container
|
||||
sessionStats.push(data)
|
||||
end if
|
||||
if isValid(stream.Size)
|
||||
data = tr("Size") + ": " + stream.Size
|
||||
sessionStats.push(data)
|
||||
end if
|
||||
if isValid(stream.BitRate)
|
||||
data = tr("Bit Rate") + ": " + getDisplayBitrate(stream.BitRate)
|
||||
sessionStats.push(data)
|
||||
end if
|
||||
if isValid(stream.Codec)
|
||||
data = tr("Codec") + ": " + stream.Codec
|
||||
sessionStats.push(data)
|
||||
end if
|
||||
if isValid(stream.CodecTag)
|
||||
data = tr("Codec Tag") + ": " + stream.CodecTag
|
||||
sessionStats.push(data)
|
||||
end if
|
||||
if isValid(stream.VideoRangeType)
|
||||
data = tr("Video range type") + ": " + stream.VideoRangeType
|
||||
sessionStats.push(data)
|
||||
end if
|
||||
if isValid(stream.PixelFormat)
|
||||
data = tr("Pixel format") + ": " + stream.PixelFormat
|
||||
sessionStats.push(data)
|
||||
end if
|
||||
if isValid(stream.Width) and isValid(stream.Height)
|
||||
data = tr("WxH") + ": " + Str(stream.Width) + " x " + Str(stream.Height)
|
||||
sessionStats.push(data)
|
||||
end if
|
||||
if isValid(stream.Level)
|
||||
data = tr("Level") + ": " + Str(stream.Level)
|
||||
sessionStats.push(data)
|
||||
end if
|
||||
end if
|
||||
|
||||
return sessionStats
|
||||
end function
|
||||
|
||||
function havePlaybackInfo()
|
||||
if not isValid(m.playbackInfo)
|
||||
return false
|
||||
end if
|
||||
|
||||
if not isValid(m.playbackInfo.mediaSources)
|
||||
return false
|
||||
end if
|
||||
|
||||
if m.playbackInfo.mediaSources.Count() <= 0
|
||||
return false
|
||||
end if
|
||||
|
||||
if not isValid(m.playbackInfo.mediaSources[0].MediaStreams)
|
||||
return false
|
||||
end if
|
||||
|
||||
if m.playbackInfo.mediaSources[0].MediaStreams.Count() <= 0
|
||||
return false
|
||||
end if
|
||||
|
||||
return true
|
||||
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
|
||||
|
|
Loading…
Reference in New Issue
Block a user