Improve playback, preroll and TV experience
This commit is contained in:
@@ -297,12 +297,16 @@ func (c *Client) PlaybackInfo(
|
||||
"UserId": {cred.UserID},
|
||||
"IsPlayback": {"true"},
|
||||
}
|
||||
profile := androidTVDeviceProfile(capabilities)
|
||||
if forceTranscode {
|
||||
forceH264TranscodeProfile(profile)
|
||||
}
|
||||
body, err := json.Marshal(map[string]any{
|
||||
"Id": itemID, "UserId": cred.UserID, "IsPlayback": true,
|
||||
"StartTimeTicks": startTicks, "EnableDirectPlay": !forceTranscode,
|
||||
"EnableDirectStream": !forceTranscode, "EnableTranscoding": true,
|
||||
"AllowVideoStreamCopy": true, "AllowAudioStreamCopy": true,
|
||||
"DeviceProfile": androidTVDeviceProfile(capabilities),
|
||||
"AllowVideoStreamCopy": !forceTranscode, "AllowAudioStreamCopy": true,
|
||||
"DeviceProfile": profile,
|
||||
})
|
||||
var requestBody map[string]any
|
||||
if err == nil {
|
||||
@@ -314,10 +318,6 @@ func (c *Client) PlaybackInfo(
|
||||
if currentPlaySessionID != "" {
|
||||
requestBody["CurrentPlaySessionId"] = currentPlaySessionID
|
||||
}
|
||||
if forceTranscode {
|
||||
profile := requestBody["DeviceProfile"].(map[string]any)
|
||||
profile["DirectPlayProfiles"] = []map[string]string{}
|
||||
}
|
||||
if err == nil {
|
||||
body, err = json.Marshal(requestBody)
|
||||
}
|
||||
|
||||
@@ -32,3 +32,23 @@ func TestAndroidTVProfileConstrainsCodecLevelAndResolution(t *testing.T) {
|
||||
t.Fatalf("codec profiles = %#v", codecProfiles)
|
||||
}
|
||||
}
|
||||
|
||||
func TestForcedTranscodeProfileCannotStreamCopyHEVC(t *testing.T) {
|
||||
profile := androidTVDeviceProfile(PlaybackCapabilities{
|
||||
HEVC: true, HEVCMain: true, HEVCMain10: true,
|
||||
})
|
||||
forceH264TranscodeProfile(profile)
|
||||
|
||||
if direct := profile["DirectPlayProfiles"].([]map[string]string); len(direct) != 0 {
|
||||
t.Fatalf("direct profiles = %#v", direct)
|
||||
}
|
||||
transcode := profile["TranscodingProfiles"].([]map[string]string)
|
||||
if len(transcode) != 1 || transcode[0]["VideoCodec"] != "h264" {
|
||||
t.Fatalf("transcoding profiles = %#v", transcode)
|
||||
}
|
||||
for _, codecProfile := range profile["CodecProfiles"].([]map[string]any) {
|
||||
if codecProfile["Codec"] == "hevc" {
|
||||
t.Fatalf("HEVC constraint survived fallback: %#v", codecProfile)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,6 +53,27 @@ func androidTVDeviceProfile(capabilities PlaybackCapabilities) map[string]any {
|
||||
}
|
||||
}
|
||||
|
||||
// forceH264TranscodeProfile turns decoder recovery into an actual codec change. Merely
|
||||
// removing DirectPlayProfiles is insufficient: Emby may otherwise stream-copy HEVC into
|
||||
// the ordinary HLS transcoding profile and hand the failing decoder the same video again.
|
||||
func forceH264TranscodeProfile(profile map[string]any) {
|
||||
profile["DirectPlayProfiles"] = []map[string]string{}
|
||||
profile["TranscodingProfiles"] = []map[string]string{
|
||||
{
|
||||
"Container": "ts", "VideoCodec": "h264", "AudioCodec": "aac",
|
||||
"Protocol": "hls", "Type": "Video", "Context": "Streaming",
|
||||
},
|
||||
}
|
||||
profiles, _ := profile["CodecProfiles"].([]map[string]any)
|
||||
h264Profiles := make([]map[string]any, 0, len(profiles))
|
||||
for _, codecProfile := range profiles {
|
||||
if codec, _ := codecProfile["Codec"].(string); codec == "h264" {
|
||||
h264Profiles = append(h264Profiles, codecProfile)
|
||||
}
|
||||
}
|
||||
profile["CodecProfiles"] = h264Profiles
|
||||
}
|
||||
|
||||
func androidTVSubtitleProfiles() []map[string]string {
|
||||
return []map[string]string{
|
||||
{"Format": "srt", "Method": "External"},
|
||||
|
||||
Reference in New Issue
Block a user