package emby import "testing" func TestDirectPlayVideoCodecsIncludeHEVCOnlyForCapableClient(t *testing.T) { if got := directPlayVideoCodecs(false); got != "h264" { t.Fatalf("baseline codecs = %q", got) } if got := directPlayVideoCodecs(true); got != "h264,hevc" { t.Fatalf("HEVC codecs = %q", got) } } func TestAndroidTVProfileConstrainsCodecLevelAndResolution(t *testing.T) { profile := androidTVDeviceProfile(PlaybackCapabilities{ H264Profiles: []string{"baseline", "main", "high"}, H264Level: 52, H264MaxWidth: 3840, H264MaxHeight: 2160, HEVC: true, HEVCMain: true, HEVCMain10: true, HEVCMainLevel: 153, HEVCMain10Level: 153, HEVCMaxWidth: 3840, HEVCMaxHeight: 2160, }) direct := profile["DirectPlayProfiles"].([]map[string]string) if direct[0]["VideoCodec"] != "h264,hevc" { t.Fatalf("direct video codecs = %q", direct[0]["VideoCodec"]) } transcode := profile["TranscodingProfiles"].([]map[string]string) if transcode[0]["VideoCodec"] != "h264,hevc" { t.Fatalf("stream-copy codecs = %q", transcode[0]["VideoCodec"]) } codecProfiles := profile["CodecProfiles"].([]map[string]any) if len(codecProfiles) < 6 { 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) } } } func TestAudioProfileAdvertisesDecodeAndPassthroughWithoutReencodingVideo(t *testing.T) { profile := androidTVDeviceProfile(PlaybackCapabilities{ HEVC: true, AudioProfileV1: true, AudioMaxChannels: 8, AudioPassthrough: map[string]bool{"ac3": true, "eac3": true}, AudioDecode: map[string]bool{ "ac3": true, "eac3": true, "atmos": true, "dts": true, "dts_hd": true, "truehd": true, }, }) direct := profile["DirectPlayProfiles"].([]map[string]string)[0] for _, codec := range []string{"flac", "opus", "ac3", "eac3", "dts", "dtshd", "truehd"} { if !containsCommaValue(direct["AudioCodec"], codec) { t.Fatalf("direct audio codecs %q missing %q", direct["AudioCodec"], codec) } } transcode := profile["TranscodingProfiles"].([]map[string]string)[0] if transcode["VideoCodec"] != "h264,hevc" || transcode["AudioCodec"] != "eac3,ac3,aac,mp3" { t.Fatalf("audio conversion profile = %#v", transcode) } profiles := profile["CodecProfiles"].([]map[string]any) audio := profiles[len(profiles)-1] conditions := audio["Conditions"].([]map[string]any) if audio["Type"] != "VideoAudio" || conditions[0]["Value"] != "8" { t.Fatalf("audio constraints = %#v", audio) } } func containsCommaValue(values, wanted string) bool { start := 0 for i := 0; i <= len(values); i++ { if i == len(values) || values[i] == ',' { if values[start:i] == wanted { return true } start = i + 1 } } return false }