Skip to content

Commit

Permalink
Merge pull request #1013 from thornbill/4k-on-1080
Browse files Browse the repository at this point in the history
Playback fixes for Fire TVs
  • Loading branch information
nielsvanvelzen committed Jul 13, 2021
2 parents 51f7e54 + dcaef4a commit 91991ee
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 23 deletions.
30 changes: 30 additions & 0 deletions app/src/main/java/org/jellyfin/androidtv/util/DeviceUtils.java
Expand Up @@ -2,9 +2,23 @@

import android.os.Build;

import java.util.Arrays;

public class DeviceUtils {
private static final String FIRE_TV_PREFIX = "AFT";
// Fire TV Stick Models
private static final String FIRE_STICK_MODEL_GEN_1 = "AFTM";
private static final String FIRE_STICK_MODEL_GEN_2 = "AFTT";
private static final String FIRE_STICK_MODEL_GEN_3 = "AFTSSS";
private static final String FIRE_STICK_LITE_MODEL = "AFTSS";
private static final String FIRE_STICK_4K_MODEL = "AFTMM";
// Fire TV Cube Models
private static final String FIRE_CUBE_MODEL_GEN_1 = "AFTA";
private static final String FIRE_CUBE_MODEL_GEN_2 = "AFTR";
// Fire TV (Box) Models
private static final String FIRE_TV_MODEL_GEN_1 = "AFTB";
private static final String FIRE_TV_MODEL_GEN_2 = "AFTS";
private static final String FIRE_TV_MODEL_GEN_3 = "AFTN";

public static boolean isFireTv() {
return Build.MODEL.startsWith(FIRE_TV_PREFIX);
Expand All @@ -14,6 +28,22 @@ public static boolean isFireTvStickGen1() {
return Build.MODEL.equals(FIRE_STICK_MODEL_GEN_1);
}

public static boolean isFireTvStick4k() {
return Build.MODEL.equals(FIRE_STICK_4K_MODEL);
}

public static boolean has4kVideoSupport() {
return !Arrays.asList(
// These devices only support a max video resolution of 1080p
FIRE_STICK_MODEL_GEN_1,
FIRE_STICK_MODEL_GEN_2,
FIRE_STICK_MODEL_GEN_3,
FIRE_STICK_LITE_MODEL,
FIRE_TV_MODEL_GEN_1,
FIRE_TV_MODEL_GEN_2
).contains(Build.MODEL);
}

public static boolean is50() {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP;
}
Expand Down
Expand Up @@ -4,12 +4,11 @@ import org.jellyfin.androidtv.constant.CodecTypes
import org.jellyfin.androidtv.constant.ContainerTypes
import org.jellyfin.androidtv.util.DeviceUtils
import org.jellyfin.androidtv.util.Utils
import org.jellyfin.androidtv.util.profile.ProfileHelper.H264_LEVEL_4_1
import org.jellyfin.androidtv.util.profile.ProfileHelper.H264_LEVEL_5_1
import org.jellyfin.androidtv.util.profile.ProfileHelper.audioDirectPlayProfile
import org.jellyfin.androidtv.util.profile.ProfileHelper.deviceHevcCodecProfile
import org.jellyfin.androidtv.util.profile.ProfileHelper.h264VideoLevelProfileCondition
import org.jellyfin.androidtv.util.profile.ProfileHelper.h264VideoProfileCondition
import org.jellyfin.androidtv.util.profile.ProfileHelper.max1080pProfileConditions
import org.jellyfin.androidtv.util.profile.ProfileHelper.maxAudioChannelsCodecProfile
import org.jellyfin.androidtv.util.profile.ProfileHelper.photoDirectPlayProfile
import org.jellyfin.androidtv.util.profile.ProfileHelper.subtitleProfile
Expand Down Expand Up @@ -101,18 +100,19 @@ class ExoPlayerProfile(
add(photoDirectPlayProfile)
}.toTypedArray()

codecProfiles = arrayOf(
codecProfiles = buildList {
// H264 profile
CodecProfile().apply {
add(CodecProfile().apply {
type = CodecType.Video
codec = CodecTypes.H264
conditions = arrayOf(
h264VideoProfileCondition,
h264VideoLevelProfileCondition
)
},
conditions = buildList {
add(h264VideoProfileCondition)
add(h264VideoLevelProfileCondition)
if (!DeviceUtils.has4kVideoSupport()) addAll(max1080pProfileConditions)
}.toTypedArray()
})
// H264 ref frames profile
CodecProfile().apply {
add(CodecProfile().apply {
type = CodecType.Video
codec = CodecTypes.H264
conditions = arrayOf(
Expand All @@ -129,9 +129,9 @@ class ExoPlayerProfile(
"1200"
)
)
},
})
// H264 ref frames profile
CodecProfile().apply {
add(CodecProfile().apply {
type = CodecType.Video
codec = CodecTypes.H264
conditions = arrayOf(
Expand All @@ -148,12 +148,19 @@ class ExoPlayerProfile(
"1900"
)
)
},
})
// HEVC profile
deviceHevcCodecProfile,
add(deviceHevcCodecProfile)
// Limit video resolution support for older devices
if (!DeviceUtils.has4kVideoSupport()) {
add(CodecProfile().apply {
type = CodecType.Video
conditions = max1080pProfileConditions
})
}
// Audio channel profile
maxAudioChannelsCodecProfile(channels = 6)
)
add(maxAudioChannelsCodecProfile(channels = 6))
}.toTypedArray()

subtitleProfiles = arrayOf(
subtitleProfile("srt", SubtitleDeliveryMethod.External),
Expand Down
Expand Up @@ -2,7 +2,6 @@ package org.jellyfin.androidtv.util.profile

import org.jellyfin.androidtv.constant.CodecTypes
import org.jellyfin.androidtv.constant.ContainerTypes
import org.jellyfin.androidtv.util.DeviceUtils
import org.jellyfin.androidtv.util.Utils
import org.jellyfin.androidtv.util.profile.ProfileHelper.audioDirectPlayProfile
import org.jellyfin.androidtv.util.profile.ProfileHelper.deviceHevcCodecProfile
Expand All @@ -15,9 +14,6 @@ import org.jellyfin.apiclient.model.dlna.CodecProfile
import org.jellyfin.apiclient.model.dlna.CodecType
import org.jellyfin.apiclient.model.dlna.DirectPlayProfile
import org.jellyfin.apiclient.model.dlna.DlnaProfileType
import org.jellyfin.apiclient.model.dlna.ProfileCondition
import org.jellyfin.apiclient.model.dlna.ProfileConditionType
import org.jellyfin.apiclient.model.dlna.ProfileConditionValue
import org.jellyfin.apiclient.model.dlna.SubtitleDeliveryMethod

class LibVlcProfile(
Expand Down
Expand Up @@ -18,8 +18,9 @@ import timber.log.Timber

object ProfileHelper {
// H264 codec levels https://en.wikipedia.org/wiki/Advanced_Video_Coding#Levels
const val H264_LEVEL_4_1 = "41"
const val H264_LEVEL_5_1 = "51"
private const val H264_LEVEL_4_1 = "41"
private const val H264_LEVEL_5_1 = "51"
private const val H264_LEVEL_5_2 = "52"

private val MediaTest by lazy { MediaCodecCapabilitiesTest() }

Expand Down Expand Up @@ -69,7 +70,12 @@ object ProfileHelper {
ProfileCondition(
ProfileConditionType.LessThanEqual,
ProfileConditionValue.VideoLevel,
if (DeviceUtils.isFireTvStickGen1()) H264_LEVEL_4_1 else H264_LEVEL_5_1
when {
// https://developer.amazon.com/docs/fire-tv/device-specifications.html
DeviceUtils.isFireTvStick4k() -> H264_LEVEL_5_2
DeviceUtils.isFireTv() -> H264_LEVEL_4_1
else -> H264_LEVEL_5_1
}
)
}

Expand All @@ -86,6 +92,21 @@ object ProfileHelper {
)
}

val max1080pProfileConditions by lazy {
arrayOf(
ProfileCondition(
ProfileConditionType.LessThanEqual,
ProfileConditionValue.Width,
"1920"
),
ProfileCondition(
ProfileConditionType.LessThanEqual,
ProfileConditionValue.Height,
"1080"
)
)
}

val photoDirectPlayProfile by lazy {
DirectPlayProfile().apply {
type = DlnaProfileType.Photo
Expand Down

0 comments on commit 91991ee

Please sign in to comment.