2020-05-31 10:57:41 +00:00
|
|
|
'Device Capabilities for Roku.
|
2020-07-11 07:52:52 +00:00
|
|
|
'This will likely need further tweaking
|
2020-05-31 10:57:41 +00:00
|
|
|
|
|
|
|
function getDeviceCapabilities() as object
|
|
|
|
|
|
|
|
return {
|
2021-07-09 20:08:32 +00:00
|
|
|
"PlayableMediaTypes": [
|
|
|
|
"Audio",
|
|
|
|
"Video"
|
|
|
|
],
|
|
|
|
"SupportedCommands": [],
|
|
|
|
"SupportsPersistentIdentifier": false,
|
|
|
|
"SupportsMediaControl": false,
|
|
|
|
"DeviceProfile": getDeviceProfile()
|
|
|
|
}
|
2020-05-31 10:57:41 +00:00
|
|
|
end function
|
|
|
|
|
|
|
|
|
|
|
|
function getDeviceProfile() as object
|
2022-05-01 10:53:39 +00:00
|
|
|
playMpeg2 = get_user_setting("playback.mpeg2") = "true"
|
2020-05-31 10:57:41 +00:00
|
|
|
|
|
|
|
'Check if 5.1 Audio Output connected
|
|
|
|
maxAudioChannels = 2
|
|
|
|
di = CreateObject("roDeviceInfo")
|
2021-06-26 13:52:16 +00:00
|
|
|
if di.GetAudioOutputChannel() = "5.1 surround"
|
2021-07-09 20:08:32 +00:00
|
|
|
maxAudioChannels = 6
|
2020-05-31 10:57:41 +00:00
|
|
|
end if
|
|
|
|
|
2021-08-24 01:21:15 +00:00
|
|
|
if playMpeg2 and di.CanDecodeVideo({ Codec: "mpeg2" }).Result = true
|
2022-03-29 01:21:02 +00:00
|
|
|
tsVideoCodecs = "h264,mpeg2video"
|
2021-08-24 01:21:15 +00:00
|
|
|
else
|
2022-03-29 01:21:02 +00:00
|
|
|
tsVideoCodecs = "h264"
|
|
|
|
end if
|
|
|
|
|
|
|
|
if di.CanDecodeVideo({ Codec: "hevc" }).Result = true
|
|
|
|
tsVideoCodecs = tsVideoCodecs + ",h265,hevc"
|
2022-07-07 19:58:01 +00:00
|
|
|
if di.CanDecodeVideo({ Codec: "hevc", Profile: "main 10" }).Result
|
|
|
|
MAIN10 = ",main 10"
|
|
|
|
else
|
|
|
|
MAIN10 = ""
|
|
|
|
end if
|
2021-08-24 01:21:15 +00:00
|
|
|
end if
|
|
|
|
|
|
|
|
if di.CanDecodeAudio({ Codec: "ac3" }).result
|
|
|
|
tsAudioCodecs = "aac,ac3"
|
|
|
|
else
|
|
|
|
tsAudioCodecs = "aac"
|
|
|
|
end if
|
2022-07-07 19:58:01 +00:00
|
|
|
|
|
|
|
addAv1Profile = false
|
|
|
|
if di.CanDecodeVideo({ Codec: "av1" }).result
|
|
|
|
tsVideoCodecs = tsVideoCodecs + ",av1"
|
|
|
|
addAv1Profile = true
|
|
|
|
end if
|
|
|
|
|
|
|
|
addVp9Profile = false
|
|
|
|
if di.CanDecodeVideo({ Codec: "vp9" }).result
|
|
|
|
tsVideoCodecs = tsVideoCodecs + ",vp9"
|
|
|
|
addVp9Profile = true
|
|
|
|
end if
|
2021-08-24 01:21:15 +00:00
|
|
|
|
2022-07-07 19:58:01 +00:00
|
|
|
tsVideoCodecs = tsVideoCodecs + ",h265,hevc"
|
|
|
|
|
|
|
|
hevcVideoRangeTypes = "SDR"
|
|
|
|
vp9VideoRangeTypes = "SDR"
|
|
|
|
av1VideoRangeTypes = "SDR"
|
|
|
|
|
|
|
|
dp = di.GetDisplayProperties()
|
|
|
|
if dp.Hdr10 ' or dp.Hdr10Plus?
|
|
|
|
hevcVideoRangeTypes = hevcVideoRangeTypes + ",HDR10"
|
|
|
|
vp9VideoRangeTypes = vp9VideoRangeTypes + ",HDR10"
|
|
|
|
av1VideoRangeTypes = av1VideoRangeTypes + ",HDR10"
|
|
|
|
end if
|
|
|
|
if dp.HLG
|
|
|
|
hevcVideoRangeTypes = hevcVideoRangeTypes + ",HLG"
|
|
|
|
vp9VideoRangeTypes = vp9VideoRangeTypes + ",HLG"
|
|
|
|
av1VideoRangeTypes = av1VideoRangeTypes + ",HLG"
|
|
|
|
end if
|
|
|
|
if dp.DolbyVision
|
|
|
|
hevcVideoRangeTypes = hevcVideoRangeTypes + ",DOVI"
|
|
|
|
'vp9VideoRangeTypes = vp9VideoRangeTypes + ",DOVI" no evidence that vp9 can hold DOVI
|
|
|
|
av1VideoRangeTypes = av1VideoRangeTypes + ",DOVI"
|
|
|
|
end if
|
|
|
|
|
|
|
|
|
2021-10-12 07:13:25 +00:00
|
|
|
DirectPlayProfile = GetDirectPlayProfiles()
|
2021-08-24 01:21:15 +00:00
|
|
|
|
2022-07-07 19:58:01 +00:00
|
|
|
deviceProfile = {
|
2020-05-31 10:57:41 +00:00
|
|
|
"MaxStreamingBitrate": 120000000,
|
|
|
|
"MaxStaticBitrate": 100000000,
|
|
|
|
"MusicStreamingTranscodingBitrate": 192000,
|
2021-10-12 07:13:25 +00:00
|
|
|
"DirectPlayProfiles": DirectPlayProfile,
|
2020-05-31 10:57:41 +00:00
|
|
|
"TranscodingProfiles": [
|
|
|
|
{
|
|
|
|
"Container": "aac",
|
|
|
|
"Type": "Audio",
|
|
|
|
"AudioCodec": "aac",
|
|
|
|
"Context": "Streaming",
|
|
|
|
"Protocol": "http",
|
2021-07-09 20:08:32 +00:00
|
|
|
"MaxAudioChannels": StrI(maxAudioChannels) ' Currently Jellyfin server expects this as a string
|
2020-05-31 10:57:41 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
"Container": "mp3",
|
|
|
|
"Type": "Audio",
|
|
|
|
"AudioCodec": "mp3",
|
|
|
|
"Context": "Streaming",
|
|
|
|
"Protocol": "http",
|
2020-09-22 14:33:53 +00:00
|
|
|
"MaxAudioChannels": "2"
|
2020-05-31 10:57:41 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
"Container": "mp3",
|
|
|
|
"Type": "Audio",
|
|
|
|
"AudioCodec": "mp3",
|
|
|
|
"Context": "Static",
|
|
|
|
"Protocol": "http",
|
2020-09-22 14:33:53 +00:00
|
|
|
"MaxAudioChannels": "2"
|
2020-05-31 10:57:41 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
"Container": "aac",
|
|
|
|
"Type": "Audio",
|
|
|
|
"AudioCodec": "aac",
|
|
|
|
"Context": "Static",
|
|
|
|
"Protocol": "http",
|
2021-07-09 20:08:32 +00:00
|
|
|
"MaxAudioChannels": StrI(maxAudioChannels) ' Currently Jellyfin server expects this as a string
|
2020-05-31 10:57:41 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
"Container": "ts",
|
|
|
|
"Type": "Video",
|
2021-08-24 01:21:15 +00:00
|
|
|
"AudioCodec": tsAudioCodecs,
|
|
|
|
"VideoCodec": tsVideoCodecs,
|
2020-05-31 10:57:41 +00:00
|
|
|
"Context": "Streaming",
|
|
|
|
"Protocol": "hls",
|
2022-05-30 12:59:24 +00:00
|
|
|
"MaxAudioChannels": StrI(maxAudioChannels), ' Currently Jellyfin server expects this as a string
|
2020-05-31 10:57:41 +00:00
|
|
|
"MinSegments": "1",
|
|
|
|
"BreakOnNonKeyFrames": true
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"Container": "mp4",
|
|
|
|
"Type": "Video",
|
|
|
|
"AudioCodec": "aac,opus,flac,vorbis",
|
|
|
|
"VideoCodec": "h264",
|
|
|
|
"Context": "Static",
|
|
|
|
"Protocol": "http"
|
|
|
|
}
|
|
|
|
],
|
|
|
|
"ContainerProfiles": [],
|
|
|
|
"CodecProfiles": [
|
2021-10-12 07:13:25 +00:00
|
|
|
{
|
|
|
|
"Type": "VideoAudio",
|
2021-10-12 07:21:31 +00:00
|
|
|
"Codec": DirectPlayProfile[1].AudioCodec, ' Use supported MKV Audio list
|
2021-10-12 07:13:25 +00:00
|
|
|
"Conditions": [
|
|
|
|
{
|
|
|
|
"Condition": "LessThanEqual",
|
|
|
|
"Property": "AudioChannels",
|
2022-05-30 12:59:24 +00:00
|
|
|
"Value": StrI(maxAudioChannels), ' Currently Jellyfin server expects this as a string
|
2021-10-12 07:13:25 +00:00
|
|
|
"IsRequired": false
|
|
|
|
}
|
|
|
|
]
|
|
|
|
},
|
2020-05-31 10:57:41 +00:00
|
|
|
{
|
|
|
|
"Type": "Video",
|
|
|
|
"Codec": "h264",
|
|
|
|
"Conditions": [
|
|
|
|
{
|
|
|
|
"Condition": "EqualsAny",
|
|
|
|
"Property": "VideoProfile",
|
|
|
|
"Value": "high|main|baseline|constrained baseline",
|
|
|
|
"IsRequired": false
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"Condition": "LessThanEqual",
|
|
|
|
"Property": "VideoLevel",
|
|
|
|
"Value": "51",
|
|
|
|
"IsRequired": false
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
],
|
|
|
|
"SubtitleProfiles": [
|
|
|
|
{
|
|
|
|
"Format": "vtt",
|
|
|
|
"Method": "External"
|
|
|
|
},
|
|
|
|
{
|
2020-07-11 07:52:52 +00:00
|
|
|
"Format": "srt",
|
2020-05-31 10:57:41 +00:00
|
|
|
"Method": "External"
|
|
|
|
},
|
|
|
|
{
|
2020-07-11 07:52:52 +00:00
|
|
|
"Format": "ttml",
|
2020-05-31 10:57:41 +00:00
|
|
|
"Method": "External"
|
2022-03-29 19:54:46 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
"Format": "sub",
|
|
|
|
"Method": "External"
|
2020-05-31 10:57:41 +00:00
|
|
|
}
|
2020-07-11 07:52:52 +00:00
|
|
|
]
|
|
|
|
}
|
2022-07-07 19:58:01 +00:00
|
|
|
if addAv1Profile
|
|
|
|
deviceProfile.CodecProfiles.push({
|
|
|
|
"Type": "Video",
|
|
|
|
"Codec": "av1",
|
|
|
|
"Conditions": [
|
|
|
|
{
|
|
|
|
"Condition": "EqualsAny",
|
|
|
|
"Property": "VideoRangeType",
|
|
|
|
"Value": av1VideoRangeTypes,
|
|
|
|
"IsRequired": false
|
|
|
|
}
|
|
|
|
]
|
|
|
|
})
|
|
|
|
end if
|
|
|
|
if addVp9Profile
|
|
|
|
deviceProfile.CodecProfiles.push({
|
|
|
|
"Type": "Video",
|
|
|
|
"Codec": "vp9",
|
|
|
|
"Conditions": [
|
|
|
|
{
|
|
|
|
"Condition": "EqualsAny",
|
|
|
|
"Property": "VideoRangeType",
|
|
|
|
"Value": vp9VideoRangeTypes,
|
|
|
|
"IsRequired": false
|
|
|
|
}
|
|
|
|
]
|
|
|
|
})
|
|
|
|
end if
|
|
|
|
|
|
|
|
return deviceProfile
|
2020-07-11 07:52:52 +00:00
|
|
|
end function
|
|
|
|
|
|
|
|
|
|
|
|
function GetDirectPlayProfiles() as object
|
|
|
|
|
|
|
|
mp4Video = "h264"
|
|
|
|
mp4Audio = "mp3,pcm,lpcm,wav"
|
|
|
|
mkvVideo = "h264,vp8"
|
|
|
|
mkvAudio = "mp3,pcm,lpcm,wav"
|
|
|
|
audio = "mp3,pcm,lpcm,wav"
|
|
|
|
|
2022-05-01 10:53:39 +00:00
|
|
|
playMpeg2 = get_user_setting("playback.mpeg2") = "true"
|
2021-08-24 01:21:15 +00:00
|
|
|
|
2020-07-11 07:52:52 +00:00
|
|
|
di = CreateObject("roDeviceInfo")
|
|
|
|
|
|
|
|
'Check for Supported Video Codecs
|
2021-07-09 20:08:32 +00:00
|
|
|
if di.CanDecodeVideo({ Codec: "hevc" }).Result = true
|
2021-08-01 10:45:32 +00:00
|
|
|
mp4Video = mp4Video + ",h265,hevc"
|
|
|
|
mkvVideo = mkvVideo + ",h265,hevc"
|
2020-07-11 07:52:52 +00:00
|
|
|
end if
|
|
|
|
|
2021-07-09 20:08:32 +00:00
|
|
|
if di.CanDecodeVideo({ Codec: "vp9" }).Result = true
|
|
|
|
mkvVideo = mkvVideo + ",vp9"
|
2020-07-11 07:52:52 +00:00
|
|
|
end if
|
|
|
|
|
2021-08-24 01:21:15 +00:00
|
|
|
if playMpeg2 and di.CanDecodeVideo({ Codec: "mpeg2" }).Result = true
|
|
|
|
mp4Video = mp4Video + ",mpeg2video"
|
|
|
|
mkvVideo = mkvVideo + ",mpeg2video"
|
|
|
|
end if
|
|
|
|
|
2020-07-11 07:52:52 +00:00
|
|
|
' Check for supported Audio
|
2021-07-09 20:08:32 +00:00
|
|
|
if di.CanDecodeAudio({ Codec: "ac3" }).result
|
2020-07-11 07:52:52 +00:00
|
|
|
mkvAudio = mkvAudio + ",ac3"
|
|
|
|
mp4Audio = mp4Audio + ",ac3"
|
|
|
|
audio = audio + ",ac3"
|
|
|
|
end if
|
|
|
|
|
2021-07-09 20:08:32 +00:00
|
|
|
if di.CanDecodeAudio({ Codec: "wma" }).result
|
2020-07-11 07:52:52 +00:00
|
|
|
audio = audio + ",wma"
|
|
|
|
end if
|
|
|
|
|
2021-07-09 20:08:32 +00:00
|
|
|
if di.CanDecodeAudio({ Codec: "flac" }).result
|
2020-07-11 07:52:52 +00:00
|
|
|
mkvAudio = mkvAudio + ",flac"
|
|
|
|
audio = audio + ",flac"
|
|
|
|
end if
|
|
|
|
|
2021-07-09 20:08:32 +00:00
|
|
|
if di.CanDecodeAudio({ Codec: "alac" }).result
|
2020-07-11 07:52:52 +00:00
|
|
|
mkvAudio = mkvAudio + ",alac"
|
|
|
|
mp4Audio = mp4Audio + ",alac"
|
|
|
|
audio = audio + ",alac"
|
|
|
|
end if
|
|
|
|
|
2021-07-09 20:08:32 +00:00
|
|
|
if di.CanDecodeAudio({ Codec: "aac" }).result
|
2020-07-11 07:52:52 +00:00
|
|
|
mkvAudio = mkvAudio + ",aac"
|
|
|
|
mp4Audio = mp4Audio + ",aac"
|
|
|
|
audio = audio + ",aac"
|
|
|
|
end if
|
|
|
|
|
2021-07-09 20:08:32 +00:00
|
|
|
if di.CanDecodeAudio({ Codec: "opus" }).result
|
2020-07-11 07:52:52 +00:00
|
|
|
mkvAudio = mkvAudio + ",opus"
|
|
|
|
end if
|
|
|
|
|
2021-07-09 20:08:32 +00:00
|
|
|
if di.CanDecodeAudio({ Codec: "dts" }).result
|
2020-07-22 19:30:13 +00:00
|
|
|
mkvAudio = mkvAudio + ",dts"
|
|
|
|
audio = audio + ",dts"
|
2020-07-11 07:52:52 +00:00
|
|
|
end if
|
|
|
|
|
2021-07-09 20:08:32 +00:00
|
|
|
if di.CanDecodeAudio({ Codec: "wmapro" }).result
|
2020-07-11 07:52:52 +00:00
|
|
|
audio = audio + ",wmapro"
|
|
|
|
end if
|
|
|
|
|
2021-07-09 20:08:32 +00:00
|
|
|
if di.CanDecodeAudio({ Codec: "vorbis" }).result
|
2020-07-11 07:52:52 +00:00
|
|
|
mkvAudio = mkvAudio + ",vorbis"
|
|
|
|
end if
|
|
|
|
|
2021-07-09 20:08:32 +00:00
|
|
|
if di.CanDecodeAudio({ Codec: "eac3" }).result
|
2020-07-11 07:52:52 +00:00
|
|
|
mkvAudio = mkvAudio + ",eac3"
|
2021-08-01 11:33:07 +00:00
|
|
|
mp4Audio = mp4Audio + ",eac3"
|
|
|
|
audio = audio + ",eac3"
|
2020-07-11 07:52:52 +00:00
|
|
|
end if
|
|
|
|
|
|
|
|
return [
|
2021-07-09 20:08:32 +00:00
|
|
|
{
|
|
|
|
"Container": "mp4,m4v,mov",
|
|
|
|
"Type": "Video",
|
|
|
|
"VideoCodec": mp4Video,
|
|
|
|
"AudioCodec": mp4Audio
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"Container": "mkv,webm",
|
|
|
|
"Type": "Video",
|
|
|
|
"VideoCodec": mkvVideo,
|
|
|
|
"AudioCodec": mkvAudio
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"Container": audio,
|
2022-05-30 13:00:14 +00:00
|
|
|
"Type": "Audio"
|
2021-07-09 20:08:32 +00:00
|
|
|
}
|
2020-07-11 07:52:52 +00:00
|
|
|
]
|
|
|
|
|
2022-03-28 19:40:34 +00:00
|
|
|
end function
|