fix hdr tone mapping
This commit is contained in:
@@ -647,7 +647,7 @@ export function usePlaybackInfo(
|
|||||||
// picks the default; when set, the returned TranscodingUrl muxes
|
// picks the default; when set, the returned TranscodingUrl muxes
|
||||||
// that audio track into the stream.
|
// that audio track into the stream.
|
||||||
AudioStreamIndex: audioStreamIndex,
|
AudioStreamIndex: audioStreamIndex,
|
||||||
DeviceProfile: browserDeviceProfile(audioPassthrough) as any,
|
DeviceProfile: await browserDeviceProfile(audioPassthrough) as any,
|
||||||
AutoOpenLiveStream: true,
|
AutoOpenLiveStream: true,
|
||||||
EnableDirectPlay: true,
|
EnableDirectPlay: true,
|
||||||
EnableDirectStream: true,
|
EnableDirectStream: true,
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ export function usePrebuffer(item: BaseItemDto | null | undefined, armed: boolea
|
|||||||
playbackInfoDto: {
|
playbackInfoDto: {
|
||||||
UserId: jellyfinClient.getAuthState()!.userId,
|
UserId: jellyfinClient.getAuthState()!.userId,
|
||||||
MaxStreamingBitrate: 140_000_000,
|
MaxStreamingBitrate: 140_000_000,
|
||||||
DeviceProfile: browserDeviceProfile() as any,
|
DeviceProfile: await browserDeviceProfile() as any,
|
||||||
AutoOpenLiveStream: true,
|
AutoOpenLiveStream: true,
|
||||||
EnableDirectPlay: true,
|
EnableDirectPlay: true,
|
||||||
EnableDirectStream: true,
|
EnableDirectStream: true,
|
||||||
|
|||||||
+53
-16
@@ -32,6 +32,29 @@ function canPlayInMse(mime: string): boolean {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function canDecodeHdr(contentType: string, transferFunction: 'pq' | 'hlg' = 'pq'): Promise<boolean> {
|
||||||
|
if (!canPlayInMse(contentType)) return false
|
||||||
|
if (typeof navigator.mediaCapabilities?.decodingInfo !== 'function') return false
|
||||||
|
|
||||||
|
try {
|
||||||
|
const info = await navigator.mediaCapabilities.decodingInfo({
|
||||||
|
type: 'media-source',
|
||||||
|
video: {
|
||||||
|
contentType,
|
||||||
|
width: 3840,
|
||||||
|
height: 2160,
|
||||||
|
bitrate: 25_000_000,
|
||||||
|
framerate: 24,
|
||||||
|
colorGamut: 'rec2020',
|
||||||
|
transferFunction,
|
||||||
|
},
|
||||||
|
} as any)
|
||||||
|
return !!info.supported
|
||||||
|
} catch {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function supportedVideoCodecs(): string[] {
|
function supportedVideoCodecs(): string[] {
|
||||||
const codecs: string[] = ['h264'] // Universally supported in MSE
|
const codecs: string[] = ['h264'] // Universally supported in MSE
|
||||||
if (canPlayInMse('video/mp4; codecs="hev1.1.6.L93.B0"') ||
|
if (canPlayInMse('video/mp4; codecs="hev1.1.6.L93.B0"') ||
|
||||||
@@ -82,19 +105,33 @@ function displaySupportsHdr(): boolean {
|
|||||||
* or VP9.2 (`vp09.02.10.10.01.09.16.09.00`)
|
* or VP9.2 (`vp09.02.10.10.01.09.16.09.00`)
|
||||||
* - Dolby Vision: `dvh1.05.06` / `dvhe.05.06`
|
* - Dolby Vision: `dvh1.05.06` / `dvhe.05.06`
|
||||||
*/
|
*/
|
||||||
function supportedVideoRanges(): string {
|
async function supportedVideoRanges(): Promise<string> {
|
||||||
const ranges = ['SDR']
|
const ranges = ['SDR']
|
||||||
const hdrCodec =
|
if (!displaySupportsHdr()) return ranges.join('|')
|
||||||
canPlayInMse('video/mp4; codecs="hvc1.2.4.L153.B0"') ||
|
|
||||||
canPlayInMse('video/mp4; codecs="hev1.2.4.L153.B0"') ||
|
const hdrCodec = (await Promise.all([
|
||||||
canPlayInMse('video/webm; codecs="vp09.02.10.10.01.09.16.09.00"')
|
canDecodeHdr('video/mp4; codecs="hvc1.2.4.L153.B0"'),
|
||||||
if (hdrCodec && displaySupportsHdr()) {
|
canDecodeHdr('video/mp4; codecs="hev1.2.4.L153.B0"'),
|
||||||
ranges.push('HDR10', 'HDR10Plus', 'HLG')
|
canDecodeHdr('video/mp4; codecs="av01.0.08M.10.0.110.09"'),
|
||||||
|
canDecodeHdr('video/webm; codecs="vp09.02.10.10.01.09.16.09.00"'),
|
||||||
|
])).some(Boolean)
|
||||||
|
if (hdrCodec) {
|
||||||
|
ranges.push('HDR10', 'HDR10Plus')
|
||||||
}
|
}
|
||||||
const dvCodec =
|
|
||||||
canPlayInMse('video/mp4; codecs="dvh1.05.06"') ||
|
const hlgCodec = (await Promise.all([
|
||||||
canPlayInMse('video/mp4; codecs="dvhe.05.06"')
|
canDecodeHdr('video/mp4; codecs="hvc1.2.4.L153.B0"', 'hlg'),
|
||||||
if (dvCodec && displaySupportsHdr()) {
|
canDecodeHdr('video/mp4; codecs="hev1.2.4.L153.B0"', 'hlg'),
|
||||||
|
canDecodeHdr('video/mp4; codecs="av01.0.08M.10.0.110.09"', 'hlg'),
|
||||||
|
canDecodeHdr('video/webm; codecs="vp09.02.10.10.01.09.16.09.00"', 'hlg'),
|
||||||
|
])).some(Boolean)
|
||||||
|
if (hlgCodec && !ranges.includes('HLG')) ranges.push('HLG')
|
||||||
|
|
||||||
|
const dvCodec = (await Promise.all([
|
||||||
|
canDecodeHdr('video/mp4; codecs="dvh1.05.06"'),
|
||||||
|
canDecodeHdr('video/mp4; codecs="dvhe.05.06"'),
|
||||||
|
])).some(Boolean)
|
||||||
|
if (dvCodec) {
|
||||||
ranges.push('DOVI', 'DOVIWithHDR10', 'DOVIWithHLG', 'DOVIWithSDR')
|
ranges.push('DOVI', 'DOVIWithHDR10', 'DOVIWithHLG', 'DOVIWithSDR')
|
||||||
}
|
}
|
||||||
return ranges.join('|')
|
return ranges.join('|')
|
||||||
@@ -108,10 +145,10 @@ export function isHdrDisplayActive(): boolean {
|
|||||||
return displaySupportsHdr()
|
return displaySupportsHdr()
|
||||||
}
|
}
|
||||||
|
|
||||||
export function browserDeviceProfile(audioPassthrough = false) {
|
export async function browserDeviceProfile(audioPassthrough = false) {
|
||||||
const videoCodecs = supportedVideoCodecs()
|
const videoCodecs = supportedVideoCodecs()
|
||||||
const videoCodecsCsv = videoCodecs.join(',')
|
const videoCodecsCsv = videoCodecs.join(',')
|
||||||
const videoRanges = supportedVideoRanges()
|
const videoRanges = await supportedVideoRanges()
|
||||||
|
|
||||||
return {
|
return {
|
||||||
Name: 'Jellybloom Browser Client',
|
Name: 'Jellybloom Browser Client',
|
||||||
@@ -215,7 +252,7 @@ export function browserDeviceProfile(audioPassthrough = false) {
|
|||||||
Condition: 'EqualsAny',
|
Condition: 'EqualsAny',
|
||||||
Property: 'VideoRangeType',
|
Property: 'VideoRangeType',
|
||||||
Value: videoRanges,
|
Value: videoRanges,
|
||||||
IsRequired: false,
|
IsRequired: true,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@@ -229,7 +266,7 @@ export function browserDeviceProfile(audioPassthrough = false) {
|
|||||||
Condition: 'EqualsAny',
|
Condition: 'EqualsAny',
|
||||||
Property: 'VideoRangeType',
|
Property: 'VideoRangeType',
|
||||||
Value: videoRanges,
|
Value: videoRanges,
|
||||||
IsRequired: false,
|
IsRequired: true,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@@ -241,7 +278,7 @@ export function browserDeviceProfile(audioPassthrough = false) {
|
|||||||
Condition: 'EqualsAny',
|
Condition: 'EqualsAny',
|
||||||
Property: 'VideoRangeType',
|
Property: 'VideoRangeType',
|
||||||
Value: videoRanges,
|
Value: videoRanges,
|
||||||
IsRequired: false,
|
IsRequired: true,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user