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

Fix direct play of the AV1 codec #1393

Merged
merged 9 commits into from
Oct 16, 2023
10 changes: 0 additions & 10 deletions locale/en_US/translations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -525,16 +525,6 @@
<translation>Support Direct Play of MPEG-4 content. This may need to be disabled for playback of DIVX encoded video files.</translation>
<extracomment>Settings Menu - Description for option</extracomment>
</message>
<message>
<source>AV1</source>
<translation>AV1</translation>
<extracomment>Name of a setting - should we try to direct play experimental av1 codec</extracomment>
</message>
<message>
<source>** EXPERIMENTAL** Support Direct Play of AV1 content if this Roku device supports it.</source>
<translation>** EXPERIMENTAL** Support Direct Play of AV1 content if this Roku device supports it.</translation>
<extracomment>Description of a setting - should we try to direct play experimental av1 codec</extracomment>
</message>
<message>
<source>Enabled</source>
<translation>Enabled</translation>
Expand Down
7 changes: 0 additions & 7 deletions settings/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -132,13 +132,6 @@
"title": "Video Codec Support",
"description": "Enable or disable Direct Play support for certain codecs.",
"children": [
{
"title": "AV1",
"description": "** EXPERIMENTAL** Support Direct Play of AV1 content if this Roku device supports it.",
cewert marked this conversation as resolved.
Show resolved Hide resolved
"settingName": "playback.av1",
"type": "bool",
"default": "false"
},
{
"title": "MPEG-2",
"description": "Support Direct Play of MPEG-2 content (e.g., Live TV). This will prevent transcoding of MPEG-2 content, but uses significantly more bandwidth.",
Expand Down
87 changes: 56 additions & 31 deletions source/utils/deviceCapabilities.brs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,6 @@ end sub

function getDeviceProfile() as object
playMpeg2 = m.global.session.user.settings["playback.mpeg2"]
playAv1 = m.global.session.user.settings["playback.av1"]
di = CreateObject("roDeviceInfo")

' TRANSCODING
Expand All @@ -78,18 +77,18 @@ function getDeviceProfile() as object
' does the users setup support surround sound?
maxAudioChannels = "2" ' jellyfin expects this as a string
' in order of preference from left to right
audioCodecs = ["mp3", "vorbis", "opus", "flac", "alac", "ac4", "pcm", "wma", "wmapro"]
audioCodecs = ["eac3", "ac3", "dts", "mp3", "vorbis", "opus", "flac", "alac", "ac4", "pcm", "wma", "wmapro"]
surroundSoundCodecs = ["eac3", "ac3", "dts"]
if m.global.session.user.settings["playback.forceDTS"] = true
surroundSoundCodecs = ["dts", "eac3", "ac3"]
end if

surroundSoundCodec = invalid
preferredSurroundSoundCodec = invalid
if di.GetAudioOutputChannel() = "5.1 surround"
maxAudioChannels = "6"
for each codec in surroundSoundCodecs
if di.CanDecodeAudio({ Codec: codec, ChCnt: 6 }).Result
surroundSoundCodec = codec
preferredSurroundSoundCodec = codec
if di.CanDecodeAudio({ Codec: codec, ChCnt: 8 }).Result
maxAudioChannels = "8"
end if
Expand Down Expand Up @@ -214,15 +213,16 @@ function getDeviceProfile() as object
end if

' AV1
addAv1 = di.CanDecodeVideo({ Codec: "av1" }).Result
av1Profiles = ["main", "main 10"]
av1Levels = ["4.1", "5.0", "5.1"]
addAv1 = false
if playAv1

if addAv1
for each container in profileSupport
for each profile in av1Profiles
for each level in av1Levels
if di.CanDecodeVideo({ Codec: "av1", Container: container, Profile: profile, Level: level }).Result
addAv1 = true
' av1 doesn't support checking for container
if di.CanDecodeVideo({ Codec: "av1", Profile: profile, Level: level }).Result
profileSupport[container] = updateProfileArray(profileSupport[container], "av1", profile, level)
if container = "mp4"
' check for codec string before adding it
Expand Down Expand Up @@ -444,37 +444,28 @@ function getDeviceProfile() as object
end if

' surround sound
if surroundSoundCodec <> invalid
if preferredSurroundSoundCodec <> invalid
' add preferred surround sound codec to TranscodingProfile
deviceProfile.TranscodingProfiles.push({
"Container": surroundSoundCodec,
"Container": preferredSurroundSoundCodec,
"Type": "Audio",
"AudioCodec": surroundSoundCodec,
"AudioCodec": preferredSurroundSoundCodec,
"Context": "Streaming",
"Protocol": "http",
"MaxAudioChannels": maxAudioChannels
})
deviceProfile.TranscodingProfiles.push({
"Container": surroundSoundCodec,
"Container": preferredSurroundSoundCodec,
"Type": "Audio",
"AudioCodec": surroundSoundCodec,
"AudioCodec": preferredSurroundSoundCodec,
"Context": "Static",
"Protocol": "http",
"MaxAudioChannels": maxAudioChannels
})

' put codec in front of AudioCodec string
if tsArray.AudioCodec = ""
tsArray.AudioCodec = surroundSoundCodec
else
tsArray.AudioCodec = surroundSoundCodec + "," + tsArray.AudioCodec
end if

if mp4Array.AudioCodec = ""
mp4Array.AudioCodec = surroundSoundCodec
else
mp4Array.AudioCodec = surroundSoundCodec + "," + mp4Array.AudioCodec
end if
' move preferred codec to front of AudioCodec string
tsArray.AudioCodec = setPreferredCodec(tsArray.AudioCodec, preferredSurroundSoundCodec)
mp4Array.AudioCodec = setPreferredCodec(mp4Array.AudioCodec, preferredSurroundSoundCodec)
end if

deviceProfile.TranscodingProfiles.push(tsArray)
Expand Down Expand Up @@ -605,7 +596,7 @@ function getDeviceProfile() as object
if addAv1
av1Mp4LevelSupported = 0.0
av1TsLevelSupported = 0.0
av1AssProfiles = []
av1AssProfiles = {}
av1HighestLevel = 0.0
for each container in profileSupport
for each profile in profileSupport[container]["av1"]
Expand Down Expand Up @@ -833,11 +824,6 @@ function GetDirectPlayProfiles() as object
videoCodecs = ["h264", "mpeg4 avc", "vp8", "vp9", "h263", "mpeg1"]
audioCodecs = ["mp3", "mp2", "pcm", "lpcm", "wav", "ac3", "ac4", "aiff", "wma", "flac", "alac", "aac", "opus", "dts", "wmapro", "vorbis", "eac3", "mpg123"]

' only try to direct play av1 if asked
if m.global.session.user.settings["playback.av1"]
videoCodecs.push("av1")
end if

' check if hevc is disabled
if m.global.session.user.settings["playback.compatibility.disablehevc"] = false
videoCodecs.push("hevc")
Expand Down Expand Up @@ -870,6 +856,15 @@ function GetDirectPlayProfiles() as object
end for
end if

' video codec overrides
' these codecs play fine but are not correctly detected using CanDecodeVideo()
if di.CanDecodeVideo({ Codec: "av1" }).Result
' codec must be checked by itself or the result will always be false
for each container in supportedCodecs
supportedCodecs[container]["video"].push("av1")
end for
end if

' check audio codecs for each container
for each container in supportedCodecs
for each audioCodec in audioCodecs
Expand Down Expand Up @@ -1000,3 +995,33 @@ function removeDecimals(value as string) as string
value = r.ReplaceAll(value, "")
return value
end function

' Takes and returns a comma delimited string of codecs.
' Moves the preferred codec to the front of the string
function setPreferredCodec(codecString as string, preferredCodec as string) as string
if preferredCodec = "" then return ""
if codecString = "" then return preferredCodec

preferredCodecSize = Len(preferredCodec)

' is the codec already in front?
if Left(codecString, preferredCodecSize) = preferredCodec
return codecString
else
' convert string to array
codecArray = codecString.Split(",")
' remove preferred codec from array
newArray = []
for each codec in codecArray
if codec <> preferredCodec
newArray.push(codec)
end if
end for
' convert newArray to string
newCodecString = newArray.Join(",")
' add preferred codec to front of newCodecString
newCodecString = preferredCodec + "," + newCodecString

return newCodecString
end if
end function