diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index 20ac7eb3..74290fc7 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -17,8 +17,15 @@ import RecordingsIcon from "$lib/icons/features/recordings.svg?raw"; const CDN_BASE = "https://3comma.net"; - const HeroLandscapeVideo = `${CDN_BASE}/hero-landscape/hero-landscape.m3u8`; - const HeroPortraitVideo = `${CDN_BASE}/hero-portrait/hero-portrait.m3u8`; + const AV1_FMP4_TYPE = 'video/mp4; codecs="av01.0.08M.08"'; + const HeroLandscapeVideo = { + av1: `${CDN_BASE}/hero-landscape-av1/hero-landscape.m3u8`, + h264: `${CDN_BASE}/hero-landscape/hero-landscape.m3u8`, + }; + const HeroPortraitVideo = { + av1: `${CDN_BASE}/hero-portrait-av1/hero-portrait.m3u8`, + h264: `${CDN_BASE}/hero-portrait/hero-portrait.m3u8`, + }; const ScreenVideo = `${CDN_BASE}/screen-video/screen-video.m3u8`; let videoLandscapeElement; @@ -31,25 +38,76 @@ // Hardcode GitHub star count (similar to contributors on openpilot page) const githubStars = 50000; - function initializeHLS(videoEl, src, onReady) { - if (Hls.isSupported()) { + function mediaSourceSupports(mimeType) { + const MediaSourceConstructor = typeof Hls.getMediaSource === 'function' + ? Hls.getMediaSource() + : typeof window !== 'undefined' + ? window.MediaSource + : null; + + return Boolean(MediaSourceConstructor?.isTypeSupported?.(mimeType)); + } + + function canUseHlsJsForAv1() { + return Boolean( + typeof Hls.isMSESupported === 'function' && + Hls.isMSESupported() && + mediaSourceSupports(AV1_FMP4_TYPE) + ); + } + + function canPlayAv1HLS(videoEl) { + const nativeHlsAv1 = videoEl.canPlayType('application/vnd.apple.mpegurl') && + videoEl.canPlayType(AV1_FMP4_TYPE); + + return canUseHlsJsForAv1() || Boolean(nativeHlsAv1); + } + + function getPreferredVideoSource(videoEl, sources) { + return canPlayAv1HLS(videoEl) ? sources.av1 : sources.h264; + } + + function initializeHLS(videoEl, src, onReady, onFatalError) { + const isAv1HlsSource = src.includes('-av1/'); + + if (Hls.isSupported() || (isAv1HlsSource && canUseHlsJsForAv1())) { const hls = new Hls(); hls.loadSource(src); hls.attachMedia(videoEl); hls.on(Hls.Events.MANIFEST_PARSED, () => { if (onReady) onReady(); }); + hls.on(Hls.Events.ERROR, (_event, data) => { + if (data.fatal && onFatalError) onFatalError(hls); + }); return hls; } else if (videoEl.canPlayType('application/vnd.apple.mpegurl')) { videoEl.src = src; videoEl.addEventListener('loadedmetadata', () => { if (onReady) onReady(); }); + videoEl.addEventListener('error', () => { + if (onFatalError) onFatalError(null); + }, { once: true }); return null; } return null; } + function initializeHeroHLS(videoEl, sources, onReady) { + const preferredSrc = getPreferredVideoSource(videoEl, sources); + + initializeHLS(videoEl, preferredSrc, onReady, (hls) => { + if (preferredSrc !== sources.av1) return; + + if (hls) hls.destroy(); + videoEl.pause(); + videoEl.removeAttribute('src'); + videoEl.load(); + initializeHLS(videoEl, sources.h264, onReady); + }); + } + // TODO: don't load both mobile and desktop videos on initial load onMount(async () => { // const isMobile = typeof window !== 'undefined' && window.innerWidth < 769; @@ -59,7 +117,7 @@ videoLandscapeElement.addEventListener('playing', () => { videoLandscapeReady = true; }); - initializeHLS(videoLandscapeElement, HeroLandscapeVideo, () => { + initializeHeroHLS(videoLandscapeElement, HeroLandscapeVideo, () => { videoLandscapeElement.play(); }); } @@ -69,7 +127,7 @@ videoPortraitElement.addEventListener('playing', () => { videoPortraitReady = true; }); - initializeHLS(videoPortraitElement, HeroPortraitVideo, () => { + initializeHeroHLS(videoPortraitElement, HeroPortraitVideo, () => { videoPortraitElement.play(); }); } diff --git a/static/videos/hero-landscape-av1/hero-landscape.m3u8 b/static/videos/hero-landscape-av1/hero-landscape.m3u8 new file mode 100644 index 00000000..ef6462d8 --- /dev/null +++ b/static/videos/hero-landscape-av1/hero-landscape.m3u8 @@ -0,0 +1,44 @@ +#EXTM3U +#EXT-X-VERSION:7 +#EXT-X-TARGETDURATION:4 +#EXT-X-MEDIA-SEQUENCE:0 +#EXT-X-PLAYLIST-TYPE:VOD +#EXT-X-INDEPENDENT-SEGMENTS +#EXT-X-MAP:URI="init.mp4" +#EXTINF:4.000000, +part_000.m4s +#EXTINF:4.000000, +part_001.m4s +#EXTINF:4.000000, +part_002.m4s +#EXTINF:4.000000, +part_003.m4s +#EXTINF:4.000000, +part_004.m4s +#EXTINF:4.000000, +part_005.m4s +#EXTINF:4.000000, +part_006.m4s +#EXTINF:4.000000, +part_007.m4s +#EXTINF:4.000000, +part_008.m4s +#EXTINF:4.000000, +part_009.m4s +#EXTINF:4.000000, +part_010.m4s +#EXTINF:4.000000, +part_011.m4s +#EXTINF:4.000000, +part_012.m4s +#EXTINF:4.000000, +part_013.m4s +#EXTINF:4.000000, +part_014.m4s +#EXTINF:4.000000, +part_015.m4s +#EXTINF:4.000000, +part_016.m4s +#EXTINF:1.233333, +part_017.m4s +#EXT-X-ENDLIST diff --git a/static/videos/hero-landscape-av1/init.mp4 b/static/videos/hero-landscape-av1/init.mp4 new file mode 100644 index 00000000..730b441d Binary files /dev/null and b/static/videos/hero-landscape-av1/init.mp4 differ diff --git a/static/videos/hero-landscape-av1/part_000.m4s b/static/videos/hero-landscape-av1/part_000.m4s new file mode 100644 index 00000000..42187961 Binary files /dev/null and b/static/videos/hero-landscape-av1/part_000.m4s differ diff --git a/static/videos/hero-landscape-av1/part_001.m4s b/static/videos/hero-landscape-av1/part_001.m4s new file mode 100644 index 00000000..cd4339f6 Binary files /dev/null and b/static/videos/hero-landscape-av1/part_001.m4s differ diff --git a/static/videos/hero-landscape-av1/part_002.m4s b/static/videos/hero-landscape-av1/part_002.m4s new file mode 100644 index 00000000..f80e0bf4 Binary files /dev/null and b/static/videos/hero-landscape-av1/part_002.m4s differ diff --git a/static/videos/hero-landscape-av1/part_003.m4s b/static/videos/hero-landscape-av1/part_003.m4s new file mode 100644 index 00000000..73961045 Binary files /dev/null and b/static/videos/hero-landscape-av1/part_003.m4s differ diff --git a/static/videos/hero-landscape-av1/part_004.m4s b/static/videos/hero-landscape-av1/part_004.m4s new file mode 100644 index 00000000..2dd3a591 Binary files /dev/null and b/static/videos/hero-landscape-av1/part_004.m4s differ diff --git a/static/videos/hero-landscape-av1/part_005.m4s b/static/videos/hero-landscape-av1/part_005.m4s new file mode 100644 index 00000000..77a0be39 Binary files /dev/null and b/static/videos/hero-landscape-av1/part_005.m4s differ diff --git a/static/videos/hero-landscape-av1/part_006.m4s b/static/videos/hero-landscape-av1/part_006.m4s new file mode 100644 index 00000000..9747767d Binary files /dev/null and b/static/videos/hero-landscape-av1/part_006.m4s differ diff --git a/static/videos/hero-landscape-av1/part_007.m4s b/static/videos/hero-landscape-av1/part_007.m4s new file mode 100644 index 00000000..73aedadb Binary files /dev/null and b/static/videos/hero-landscape-av1/part_007.m4s differ diff --git a/static/videos/hero-landscape-av1/part_008.m4s b/static/videos/hero-landscape-av1/part_008.m4s new file mode 100644 index 00000000..ab356428 Binary files /dev/null and b/static/videos/hero-landscape-av1/part_008.m4s differ diff --git a/static/videos/hero-landscape-av1/part_009.m4s b/static/videos/hero-landscape-av1/part_009.m4s new file mode 100644 index 00000000..19d4f663 Binary files /dev/null and b/static/videos/hero-landscape-av1/part_009.m4s differ diff --git a/static/videos/hero-landscape-av1/part_010.m4s b/static/videos/hero-landscape-av1/part_010.m4s new file mode 100644 index 00000000..4e5a6abe Binary files /dev/null and b/static/videos/hero-landscape-av1/part_010.m4s differ diff --git a/static/videos/hero-landscape-av1/part_011.m4s b/static/videos/hero-landscape-av1/part_011.m4s new file mode 100644 index 00000000..ff34e7b8 Binary files /dev/null and b/static/videos/hero-landscape-av1/part_011.m4s differ diff --git a/static/videos/hero-landscape-av1/part_012.m4s b/static/videos/hero-landscape-av1/part_012.m4s new file mode 100644 index 00000000..5022930d Binary files /dev/null and b/static/videos/hero-landscape-av1/part_012.m4s differ diff --git a/static/videos/hero-landscape-av1/part_013.m4s b/static/videos/hero-landscape-av1/part_013.m4s new file mode 100644 index 00000000..ca8f9f5c Binary files /dev/null and b/static/videos/hero-landscape-av1/part_013.m4s differ diff --git a/static/videos/hero-landscape-av1/part_014.m4s b/static/videos/hero-landscape-av1/part_014.m4s new file mode 100644 index 00000000..e3c0157e Binary files /dev/null and b/static/videos/hero-landscape-av1/part_014.m4s differ diff --git a/static/videos/hero-landscape-av1/part_015.m4s b/static/videos/hero-landscape-av1/part_015.m4s new file mode 100644 index 00000000..b1fde0f3 Binary files /dev/null and b/static/videos/hero-landscape-av1/part_015.m4s differ diff --git a/static/videos/hero-landscape-av1/part_016.m4s b/static/videos/hero-landscape-av1/part_016.m4s new file mode 100644 index 00000000..af0eb1f7 Binary files /dev/null and b/static/videos/hero-landscape-av1/part_016.m4s differ diff --git a/static/videos/hero-landscape-av1/part_017.m4s b/static/videos/hero-landscape-av1/part_017.m4s new file mode 100644 index 00000000..77835987 Binary files /dev/null and b/static/videos/hero-landscape-av1/part_017.m4s differ diff --git a/static/videos/hero-portrait-av1/hero-portrait.m3u8 b/static/videos/hero-portrait-av1/hero-portrait.m3u8 new file mode 100644 index 00000000..9258c050 --- /dev/null +++ b/static/videos/hero-portrait-av1/hero-portrait.m3u8 @@ -0,0 +1,44 @@ +#EXTM3U +#EXT-X-VERSION:7 +#EXT-X-TARGETDURATION:4 +#EXT-X-MEDIA-SEQUENCE:0 +#EXT-X-PLAYLIST-TYPE:VOD +#EXT-X-INDEPENDENT-SEGMENTS +#EXT-X-MAP:URI="init.mp4" +#EXTINF:4.000000, +part_000.m4s +#EXTINF:4.000000, +part_001.m4s +#EXTINF:4.000000, +part_002.m4s +#EXTINF:4.000000, +part_003.m4s +#EXTINF:4.000000, +part_004.m4s +#EXTINF:4.000000, +part_005.m4s +#EXTINF:4.000000, +part_006.m4s +#EXTINF:4.000000, +part_007.m4s +#EXTINF:4.000000, +part_008.m4s +#EXTINF:4.000000, +part_009.m4s +#EXTINF:4.000000, +part_010.m4s +#EXTINF:4.000000, +part_011.m4s +#EXTINF:4.000000, +part_012.m4s +#EXTINF:4.000000, +part_013.m4s +#EXTINF:4.000000, +part_014.m4s +#EXTINF:4.000000, +part_015.m4s +#EXTINF:4.000000, +part_016.m4s +#EXTINF:1.100000, +part_017.m4s +#EXT-X-ENDLIST diff --git a/static/videos/hero-portrait-av1/init.mp4 b/static/videos/hero-portrait-av1/init.mp4 new file mode 100644 index 00000000..7e0cd1e8 Binary files /dev/null and b/static/videos/hero-portrait-av1/init.mp4 differ diff --git a/static/videos/hero-portrait-av1/part_000.m4s b/static/videos/hero-portrait-av1/part_000.m4s new file mode 100644 index 00000000..45d30ee1 Binary files /dev/null and b/static/videos/hero-portrait-av1/part_000.m4s differ diff --git a/static/videos/hero-portrait-av1/part_001.m4s b/static/videos/hero-portrait-av1/part_001.m4s new file mode 100644 index 00000000..d503a838 Binary files /dev/null and b/static/videos/hero-portrait-av1/part_001.m4s differ diff --git a/static/videos/hero-portrait-av1/part_002.m4s b/static/videos/hero-portrait-av1/part_002.m4s new file mode 100644 index 00000000..9e825ba3 Binary files /dev/null and b/static/videos/hero-portrait-av1/part_002.m4s differ diff --git a/static/videos/hero-portrait-av1/part_003.m4s b/static/videos/hero-portrait-av1/part_003.m4s new file mode 100644 index 00000000..47b29cdd Binary files /dev/null and b/static/videos/hero-portrait-av1/part_003.m4s differ diff --git a/static/videos/hero-portrait-av1/part_004.m4s b/static/videos/hero-portrait-av1/part_004.m4s new file mode 100644 index 00000000..327c94d5 Binary files /dev/null and b/static/videos/hero-portrait-av1/part_004.m4s differ diff --git a/static/videos/hero-portrait-av1/part_005.m4s b/static/videos/hero-portrait-av1/part_005.m4s new file mode 100644 index 00000000..bd920eaa Binary files /dev/null and b/static/videos/hero-portrait-av1/part_005.m4s differ diff --git a/static/videos/hero-portrait-av1/part_006.m4s b/static/videos/hero-portrait-av1/part_006.m4s new file mode 100644 index 00000000..456debd4 Binary files /dev/null and b/static/videos/hero-portrait-av1/part_006.m4s differ diff --git a/static/videos/hero-portrait-av1/part_007.m4s b/static/videos/hero-portrait-av1/part_007.m4s new file mode 100644 index 00000000..46b8b6d4 Binary files /dev/null and b/static/videos/hero-portrait-av1/part_007.m4s differ diff --git a/static/videos/hero-portrait-av1/part_008.m4s b/static/videos/hero-portrait-av1/part_008.m4s new file mode 100644 index 00000000..c855d0b3 Binary files /dev/null and b/static/videos/hero-portrait-av1/part_008.m4s differ diff --git a/static/videos/hero-portrait-av1/part_009.m4s b/static/videos/hero-portrait-av1/part_009.m4s new file mode 100644 index 00000000..000d8890 Binary files /dev/null and b/static/videos/hero-portrait-av1/part_009.m4s differ diff --git a/static/videos/hero-portrait-av1/part_010.m4s b/static/videos/hero-portrait-av1/part_010.m4s new file mode 100644 index 00000000..0823e97b Binary files /dev/null and b/static/videos/hero-portrait-av1/part_010.m4s differ diff --git a/static/videos/hero-portrait-av1/part_011.m4s b/static/videos/hero-portrait-av1/part_011.m4s new file mode 100644 index 00000000..17f85d6a Binary files /dev/null and b/static/videos/hero-portrait-av1/part_011.m4s differ diff --git a/static/videos/hero-portrait-av1/part_012.m4s b/static/videos/hero-portrait-av1/part_012.m4s new file mode 100644 index 00000000..5012181b Binary files /dev/null and b/static/videos/hero-portrait-av1/part_012.m4s differ diff --git a/static/videos/hero-portrait-av1/part_013.m4s b/static/videos/hero-portrait-av1/part_013.m4s new file mode 100644 index 00000000..92aea6d2 Binary files /dev/null and b/static/videos/hero-portrait-av1/part_013.m4s differ diff --git a/static/videos/hero-portrait-av1/part_014.m4s b/static/videos/hero-portrait-av1/part_014.m4s new file mode 100644 index 00000000..1219a90c Binary files /dev/null and b/static/videos/hero-portrait-av1/part_014.m4s differ diff --git a/static/videos/hero-portrait-av1/part_015.m4s b/static/videos/hero-portrait-av1/part_015.m4s new file mode 100644 index 00000000..8f2c4ddb Binary files /dev/null and b/static/videos/hero-portrait-av1/part_015.m4s differ diff --git a/static/videos/hero-portrait-av1/part_016.m4s b/static/videos/hero-portrait-av1/part_016.m4s new file mode 100644 index 00000000..f7e873f3 Binary files /dev/null and b/static/videos/hero-portrait-av1/part_016.m4s differ diff --git a/static/videos/hero-portrait-av1/part_017.m4s b/static/videos/hero-portrait-av1/part_017.m4s new file mode 100644 index 00000000..dbefd9b5 Binary files /dev/null and b/static/videos/hero-portrait-av1/part_017.m4s differ