Port two changes to ExoPlayer device profile from the official app (#1263)

## Description
Ports two changes in the official jellyfin android TV app here:
- https://github.com/jellyfin/jellyfin-androidtv/pull/5240
- https://github.com/jellyfin/jellyfin-androidtv/pull/5186

The code changes are copied under GPL-2.0 from the above pull requests.

### Related issues
Closes #1260

### Testing
Emulator mostly

## Screenshots
N/A

## AI or LLM usage
None

---------

Co-authored-by: Niels van Velzen <git@ndat.nl>
Co-authored-by: clams4shoes <prestidgeandrew@gmail.com>
This commit is contained in:
Ray 2026-04-19 15:20:46 -04:00 committed by GitHub
parent 27310d71b4
commit 61afe6ba86
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 60 additions and 29 deletions

View file

@ -153,9 +153,10 @@ fun createDeviceProfile(
type = DlnaProfileType.AUDIO type = DlnaProfileType.AUDIO
context = EncodingContext.STREAMING context = EncodingContext.STREAMING
container = Codec.Container.MP3 container = Codec.Container.TS
protocol = MediaStreamProtocol.HLS
audioCodec(Codec.Audio.MP3) audioCodec(Codec.Audio.AAC)
} }
// / Direct play profiles // / Direct play profiles

View file

@ -1,6 +1,6 @@
package com.github.damontecres.wholphin.util.profile package com.github.damontecres.wholphin.util.profile
// Copied from https://github.com/jellyfin/jellyfin-androidtv/blob/v0.19.4/app/src/main/java/org/jellyfin/androidtv/util/profile/MediaCodecCapabilitiesTest.kt // Copied from https://github.com/jellyfin/jellyfin-androidtv/blob/v0.19.7/app/src/main/java/org/jellyfin/androidtv/util/profile/MediaCodecCapabilitiesTest.kt
import android.content.Context import android.content.Context
import android.media.MediaCodecInfo.CodecProfileLevel import android.media.MediaCodecInfo.CodecProfileLevel
@ -41,11 +41,46 @@ class MediaCodecCapabilitiesTest(
-1 -1
} }
} }
val Profile10: Int by lazy { }
// Some devices (e.g., Fire OS) may support AV1 below the official API level
// Use the platform constant if the API level is met; otherwise fall back to the literal value
// Reference:
// https://cs.android.com/android/platform/superproject/main/+/main:frameworks/base/media/java/android/media/MediaCodecInfo.java
private object AV1ProfileLevel {
val ProfileMain10: Int by lazy {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
CodecProfileLevel.AV1ProfileMain10
} else {
0x2
}
}
val ProfileMain10HDR10: Int by lazy {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
CodecProfileLevel.AV1ProfileMain10HDR10
} else {
0x1000
}
}
val ProfileMain10HDR10Plus: Int by lazy {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
CodecProfileLevel.AV1ProfileMain10HDR10Plus
} else {
0x2000
}
}
val DolbyVisionProfile10: Int by lazy {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
CodecProfileLevel.DolbyVisionProfileDvav110 CodecProfileLevel.DolbyVisionProfileDvav110
} else { } else {
-1 0x400
}
}
val Level5: Int by lazy {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
CodecProfileLevel.AV1Level5
} else {
0x1000
} }
} }
} }
@ -90,40 +125,35 @@ class MediaCodecCapabilitiesTest(
CodecProfileLevel.HEVCMainTierLevel62 to 186, CodecProfileLevel.HEVCMainTierLevel62 to 186,
) )
fun supportsAV1(): Boolean = fun supportsAV1(): Boolean = hasCodecForMime(MimeTypes.VIDEO_AV1)
Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q &&
hasCodecForMime(MediaFormat.MIMETYPE_VIDEO_AV1)
fun supportsAV1Main10(): Boolean = fun supportsAV1Main10(): Boolean =
Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q &&
hasDecoder( hasDecoder(
MediaFormat.MIMETYPE_VIDEO_AV1, MimeTypes.VIDEO_AV1,
CodecProfileLevel.AV1ProfileMain10, AV1ProfileLevel.ProfileMain10,
CodecProfileLevel.AV1Level5, AV1ProfileLevel.Level5,
) )
fun supportsAV1DolbyVision(): Boolean = fun supportsAV1DolbyVision(): Boolean =
Build.VERSION.SDK_INT >= Build.VERSION_CODES.R && Build.VERSION.SDK_INT >= Build.VERSION_CODES.N &&
hasDecoder( hasDecoder(
MediaFormat.MIMETYPE_VIDEO_DOLBY_VISION, MimeTypes.VIDEO_DOLBY_VISION,
DolbyVisionProfiles.Profile10, AV1ProfileLevel.DolbyVisionProfile10,
CodecProfileLevel.DolbyVisionLevelHd24, CodecProfileLevel.DolbyVisionLevelHd24,
) )
fun supportsAV1HDR10(): Boolean = fun supportsAV1HDR10(): Boolean =
Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q &&
hasDecoder( hasDecoder(
MediaFormat.MIMETYPE_VIDEO_AV1, MimeTypes.VIDEO_AV1,
CodecProfileLevel.AV1ProfileMain10HDR10, AV1ProfileLevel.ProfileMain10HDR10,
CodecProfileLevel.AV1Level5, AV1ProfileLevel.Level5,
) )
fun supportsAV1HDR10Plus(): Boolean = fun supportsAV1HDR10Plus(): Boolean =
Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q &&
hasDecoder( hasDecoder(
MediaFormat.MIMETYPE_VIDEO_AV1, MimeTypes.VIDEO_AV1,
CodecProfileLevel.AV1ProfileMain10HDR10Plus, AV1ProfileLevel.ProfileMain10HDR10Plus,
CodecProfileLevel.AV1Level5, AV1ProfileLevel.Level5,
) )
fun supportsAVC(): Boolean = hasCodecForMime(MediaFormat.MIMETYPE_VIDEO_AVC) fun supportsAVC(): Boolean = hasCodecForMime(MediaFormat.MIMETYPE_VIDEO_AVC)