Experimental option to transcode surround sound audio to AC3 (#947)

## Description
Adds an experimental setting to prefer transcoding audio with more than
2 channels to AC3. Stereo audio does not transcode.

This is basically a workaround for HDMI ARC (not eARC) or optical audio
devices because instead of 2 uncompressed PCM channels, 6 AC3 channels
(ie 5.1) is possible.

An downside of enabling this is that embedded subtitles be burned in
causing a video transcode as well.

### Related issues
Fixes #255
Incorporates some code from #1410

### Testing
Just on the emulator so far to observe if the settings trigger the
transcode or not

## Screenshots
N/A

## AI or LLM usage
None

---------

Co-authored-by: darkflame91 <darkflame91@gmail.com>
This commit is contained in:
Damontecres 2026-07-09 13:15:42 -04:00 • committed by GitHub
parent f2287a85e8
commit d481aea85a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 205 additions and 54 deletions

View file

@ -71,6 +71,7 @@ fun createDeviceProfile(
dolbyVisionELDirectPlay: Boolean,
decodeAv1: Boolean,
jellyfinTenEleven: Boolean,
preferAc3ForSurround: Boolean,
) = buildDeviceProfile {
val allowedAudioCodecs =
when {
@ -132,31 +133,61 @@ fun createDeviceProfile(
// / Transcoding profiles
// Video
transcodingProfile {
type = DlnaProfileType.VIDEO
context = EncodingContext.STREAMING
if (preferAc3ForSurround) {
transcodingProfile {
type = DlnaProfileType.VIDEO
context = EncodingContext.STREAMING
container = Codec.Container.TS
protocol = MediaStreamProtocol.HLS
container = Codec.Container.TS
protocol = MediaStreamProtocol.HLS
if (supportsHevc) videoCodec(Codec.Video.HEVC)
videoCodec(Codec.Video.H264)
if (supportsHevc) videoCodec(Codec.Video.HEVC)
videoCodec(Codec.Video.H264)
audioCodec(*allowedAudioCodecs)
audioCodec(Codec.Audio.AC3)
copyTimestamps = false
enableSubtitlesInManifest = true
copyTimestamps = false
enableSubtitlesInManifest = true
}
} else {
transcodingProfile {
type = DlnaProfileType.VIDEO
context = EncodingContext.STREAMING
container = Codec.Container.TS
protocol = MediaStreamProtocol.HLS
if (supportsHevc) videoCodec(Codec.Video.HEVC)
videoCodec(Codec.Video.H264)
audioCodec(*allowedAudioCodecs)
copyTimestamps = false
enableSubtitlesInManifest = true
}
}
// Audio
transcodingProfile {
type = DlnaProfileType.AUDIO
context = EncodingContext.STREAMING
if (preferAc3ForSurround) {
transcodingProfile {
type = DlnaProfileType.AUDIO
context = EncodingContext.STREAMING
container = Codec.Container.TS
protocol = MediaStreamProtocol.HLS
container = Codec.Container.TS
protocol = MediaStreamProtocol.HLS
audioCodec(Codec.Audio.AAC)
audioCodec(Codec.Audio.AC3)
}
} else {
transcodingProfile {
type = DlnaProfileType.AUDIO
context = EncodingContext.STREAMING
container = Codec.Container.TS
protocol = MediaStreamProtocol.HLS
audioCodec(Codec.Audio.AAC)
}
}
// / Direct play profiles
@ -530,6 +561,27 @@ fun createDeviceProfile(
}
}
if (preferAc3ForSurround) {
supportedAudioCodecs
.filterNot { it == Codec.Audio.AC3 }
.forEach { audioCodec ->
codecProfile {
type = CodecType.VIDEO_AUDIO
codec = audioCodec
conditions {
ProfileConditionValue.AUDIO_CHANNELS lowerThanOrEquals 2
}
}
codecProfile {
type = CodecType.AUDIO
codec = audioCodec
conditions {
ProfileConditionValue.AUDIO_CHANNELS lowerThanOrEquals 2
}
}
}
}
// Audio channel profile
codecProfile {
type = CodecType.VIDEO_AUDIO