Skip to content

Commit

Permalink
fix: set max resolution for common video codecs
Browse files Browse the repository at this point in the history
Instead of relying on the max resolution for the H264 codec decoder as a
global setting when computing device capabilities, set the max supported
resolution for the most common video codecs by querying the decoder.

Video codecs that support this are: AVC (H264), HEVC (H265), AV1.

This change avoids unnecessary transcodings because, on some devices,
the AVC decoder might support a lower maximum resolution compared to
other decoders that the device supports. For example, if the AVC decoder
supports up to 2K resolution decoding, and the HEVC supports up to 4K
resolution decoding, Jellyfin would have transcoded a 4K HEVC media
stream.
  • Loading branch information
ferrarimarco committed Feb 20, 2025
1 parent 5160482 commit c47166a
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,8 @@ class MediaCodecCapabilitiesTest {
}
}

Timber.d("Computed max resolution for %s: %dx%d", mime, maxWidth, maxHeight)

return Size(maxWidth, maxHeight)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import org.jellyfin.sdk.model.api.ProfileConditionValue
import org.jellyfin.sdk.model.api.SubtitleDeliveryMethod
import org.jellyfin.sdk.model.deviceprofile.DeviceProfileBuilder
import org.jellyfin.sdk.model.deviceprofile.buildDeviceProfile
import timber.log.Timber

private val downmixSupportedAudioCodecs = arrayOf(
Codec.Audio.AAC,
Expand Down Expand Up @@ -62,7 +63,6 @@ fun createDeviceProfile(
val avcHigh10Level = mediaTest.getAVCHigh10Level()
val supportsAV1 = mediaTest.supportsAV1()
val supportsAV1Main10 = mediaTest.supportsAV1Main10()
val maxResolution = mediaTest.getMaxResolution(MediaFormat.MIMETYPE_VIDEO_AVC)

name = "AndroidTV-Default"

Expand Down Expand Up @@ -280,13 +280,49 @@ fun createDeviceProfile(
}
}

// Limit video resolution support for older devices
codecProfile {
type = CodecType.VIDEO
// Get max resolutions for common codecs
// AVC
if(supportsAVC){
val maxResolutionAVC = mediaTest.getMaxResolution(MediaFormat.MIMETYPE_VIDEO_AVC)
Timber.d("The device supports %s decoding. Max supported resolution: %s", MediaFormat.MIMETYPE_VIDEO_AVC, maxResolutionAVC.toString())
codecProfile {
type = CodecType.VIDEO
codec = Codec.Video.H264

conditions {
ProfileConditionValue.WIDTH lowerThanOrEquals maxResolution.width
ProfileConditionValue.HEIGHT lowerThanOrEquals maxResolution.height
conditions {
ProfileConditionValue.WIDTH lowerThanOrEquals maxResolutionAVC.width
ProfileConditionValue.HEIGHT lowerThanOrEquals maxResolutionAVC.height
}
}
}

// HEVC
if(supportsHevc){
val maxResolutionHevc = mediaTest.getMaxResolution(MediaFormat.MIMETYPE_VIDEO_HEVC)
Timber.d("The device supports %s decoding. Max supported resolution: %s", MediaFormat.MIMETYPE_VIDEO_HEVC, maxResolutionHevc.toString())
codecProfile {
type = CodecType.VIDEO
codec = Codec.Video.HEVC

conditions {
ProfileConditionValue.WIDTH lowerThanOrEquals maxResolutionHevc.width
ProfileConditionValue.HEIGHT lowerThanOrEquals maxResolutionHevc.height
}
}
}

// AV1
if(supportsAV1){
val maxResolutionAV1 = mediaTest.getMaxResolution(MediaFormat.MIMETYPE_VIDEO_AV1)
Timber.d("The device supports %s decoding. Max supported resolution: %s", MediaFormat.MIMETYPE_VIDEO_AV1, maxResolutionAV1.toString())
codecProfile {
type = CodecType.VIDEO
codec = Codec.Video.AV1

conditions {
ProfileConditionValue.WIDTH lowerThanOrEquals maxResolutionAV1.width
ProfileConditionValue.HEIGHT lowerThanOrEquals maxResolutionAV1.height
}
}
}

Expand Down

0 comments on commit c47166a

Please sign in to comment.