Stop asking for HEVC on devices without hardware decode and fall back when frames drop
This commit is contained in:
@@ -105,8 +105,17 @@ function saveDataToStorage(jsonStr) {
|
|||||||
// is the browser's own claim; if a copy still fails to play here, the device
|
// is the browser's own claim; if a copy still fails to play here, the device
|
||||||
// is remembered (NO_HEVC_KEY) and stops asking — it gets H.264 as before.
|
// is remembered (NO_HEVC_KEY) and stops asking — it gets H.264 as before.
|
||||||
const NO_HEVC_KEY = 'ytpNoHevc';
|
const NO_HEVC_KEY = 'ytpNoHevc';
|
||||||
|
// canPlayType only says the browser can decode HEVC — often in software, which
|
||||||
|
// stutters the picture while the audio stays fine. Ask MediaCapabilities whether
|
||||||
|
// it is hardware-accelerated (powerEfficient) and smooth; remember the answer.
|
||||||
|
const HEVC_HW_KEY = 'ytpHevcHw';
|
||||||
|
try {
|
||||||
|
navigator.mediaCapabilities.decodingInfo({ type: 'file', video: { contentType: 'video/mp4; codecs="hvc1.1.6.L93.B0"', width: 1280, height: 720, bitrate: 1500000, framerate: 30 } })
|
||||||
|
.then((i) => { try { localStorage.setItem(HEVC_HW_KEY, i.supported && i.smooth && i.powerEfficient ? '1' : '0'); } catch { /* storage blocked */ } })
|
||||||
|
.catch(() => {});
|
||||||
|
} catch { /* no MediaCapabilities */ }
|
||||||
function hevcCapable() {
|
function hevcCapable() {
|
||||||
try { if (localStorage.getItem(NO_HEVC_KEY) === '1') return false; } catch { /* storage blocked */ }
|
try { if (localStorage.getItem(NO_HEVC_KEY) === '1' || localStorage.getItem(HEVC_HW_KEY) === '0') return false; } catch { /* storage blocked */ }
|
||||||
try {
|
try {
|
||||||
return document.createElement('video').canPlayType('video/mp4; codecs="hvc1.1.6.L93.B0"') !== '';
|
return document.createElement('video').canPlayType('video/mp4; codecs="hvc1.1.6.L93.B0"') !== '';
|
||||||
} catch { return false; }
|
} catch { return false; }
|
||||||
@@ -2013,6 +2022,36 @@ document.addEventListener('play', () => {
|
|||||||
preload(m, { quiet: true });
|
preload(m, { quiet: true });
|
||||||
}, true);
|
}, true);
|
||||||
|
|
||||||
|
// Dropped-frame watchdog: an HEVC server copy that this device decodes in
|
||||||
|
// software drops frames while the audio plays on. Sample the first ~30 s of
|
||||||
|
// each play; if it is clearly struggling, stop asking this device for HEVC and
|
||||||
|
// restart the song on the compatible stream, from where it is.
|
||||||
|
{
|
||||||
|
const dropWatch = { id: '', t: 0, tries: 0 };
|
||||||
|
document.addEventListener('playing', (e) => {
|
||||||
|
const v = e.target;
|
||||||
|
if (!v || v.tagName !== 'VIDEO' || !current || !current.meta || !v.getVideoPlaybackQuality) return;
|
||||||
|
if (!(current.qualities || []).some((q) => q.codec === 'hevc') || !current.serverCached) return;
|
||||||
|
if (dropWatch.id === current.meta.id && dropWatch.tries >= 6) return;
|
||||||
|
if (dropWatch.id !== current.meta.id) { dropWatch.id = current.meta.id; dropWatch.tries = 0; }
|
||||||
|
const id = current.meta.id, at = v.getVideoPlaybackQuality(), t0 = Date.now();
|
||||||
|
const check = setInterval(() => {
|
||||||
|
if (!current || !current.meta || current.meta.id !== id || v.paused || Date.now() - t0 > 30000) { clearInterval(check); return; }
|
||||||
|
dropWatch.tries++;
|
||||||
|
const q = v.getVideoPlaybackQuality();
|
||||||
|
const total = q.totalVideoFrames - at.totalVideoFrames, dropped = q.droppedVideoFrames - at.droppedVideoFrames;
|
||||||
|
if (total >= 60 && dropped / total > 0.2) {
|
||||||
|
clearInterval(check);
|
||||||
|
try { localStorage.setItem(NO_HEVC_KEY, '1'); } catch { /* storage blocked */ }
|
||||||
|
toast('Video was choppy on this device — switching to the compatible format.', { duration: 4000 });
|
||||||
|
const pos = v.currentTime || 0;
|
||||||
|
if (pos > 1 && data.resumePositions && rememberPosEnabled()) data.resumePositions[id] = Math.floor(pos);
|
||||||
|
Player.loadVideo(current.meta, { preferStream: true, nocache: true, resume: true, reveal: false });
|
||||||
|
}
|
||||||
|
}, 3000);
|
||||||
|
}, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// Video editor — cut parts out of a video and save a custom offline copy
|
// Video editor — cut parts out of a video and save a custom offline copy
|
||||||
|
|||||||
Reference in New Issue
Block a user