| 기준 | API | 저사양 조건 | 결합 |
|---|---|---|---|
| CPU 코어 | navigator.hardwareConcurrency | ≤ 4코어 | OR |
| 메모리 | navigator.deviceMemory | ≤ 4 GB | |
| GPU | WEBGL_debug_renderer_info | Mali-T830 / T720 / 400 |
| 기준 | 조건 | 판정 |
|---|---|---|
| 물리 코어 ≤ 2 | hardwareConcurrency ≤ 2 | 즉시 저사양 |
| 논리 코어 ≤ 3 | hardwareConcurrency ≤ 3 | 저사양 |
| iPad 5세대 | 코어=4 + iOS ≤ 16 + 해상도 2048×1536 | 저사양 |
| 복합 (코어=4) | JS 벤치마크 < 60 FPS 또는 (iOS ≤ 16 + 구형 해상도) | 저사양 |
리소스 캐싱 전 initLowPerformanceDevice() await 호출
결과는 모듈 레벨 캐시에 저장 — 이후 동기 호출은 캐시 반환
MediaCapabilities.decodingInfo() 로 MP4 H.264 720p 디코딩 실측
type: "file" · contentType: "video/mp4; codecs=avc1.42E01E" · 1280×720 · 30fps · 1Mbps
!result.smooth && !result.powerEfficient → 저사양
powerEfficient=true(하드웨어 가속 중)이면 smooth=false여도 고사양으로 판정
| smooth | powerEfficient | 판정 | 근거 |
|---|---|---|---|
| true | true | 고사양 | 하드웨어 가속 + 부드러운 재생 |
| false | true | 고사양 | 하드웨어 가속 중 — Chrome 첫 쿼리 보수적 판정 |
| false | false | 저사양 | 소프트웨어 디코딩 + 끊김 예상 |
| 기기 | 저사양 판정 | 비디오 리소스 | 조건 |
|---|---|---|---|
| Android / iOS (저사양) | true | 480p | s3KeyProcessed480p 존재 시 |
| Android / iOS (고사양) | false | 720p | s3KeyProcessed 또는 원본 |
| 노트북/데스크탑 (저사양) | true | 480p | smooth=false AND powerEfficient=false |
| 노트북/데스크탑 (고사양) | false | 720p | smooth=true OR powerEfficient=true |
// apps/web/lib/utils.ts async function _checkDesktopDecodingCapability(): Promise<boolean> { if (!("mediaCapabilities" in navigator)) return false; try { const result = await navigator.mediaCapabilities.decodingInfo({ type: "file", video: { contentType: "video/mp4; codecs=avc1.42E01E", width: 1280, height: 720, bitrate: 1_000_000, framerate: 30 }, }); console.log("[LowPerf] decodingInfo:", { supported: result.supported, smooth: result.smooth, powerEfficient: result.powerEfficient, }); // powerEfficient=true(하드웨어 가속)이면 고사양으로 판정 return !result.smooth && !result.powerEfficient; } catch { return false; } } export async function initLowPerformanceDevice(): Promise<boolean> { if (_lowPerfCache !== null) return _lowPerfCache; if (!_lowPerfPromise) { _lowPerfPromise = (async () => { const syncResult = _computeSyncLowPerf(); // Android/iOS const isDesktop = !/Android|iPad|iPhone|iPod/i.test(navigator.userAgent) && !(navigator.platform === "MacIntel" && navigator.maxTouchPoints > 1); const result = syncResult || (isDesktop && await _checkDesktopDecodingCapability()); _lowPerfCache = result; console.log("[LowPerf] result:", { isLowPerformanceDevice: result, ua: navigator.userAgent, platform: navigator.platform, hardwareConcurrency: navigator.hardwareConcurrency, deviceMemory: (navigator as any).deviceMemory ?? "unknown" }); return result; })(); } return _lowPerfPromise; }