From 4d65757368d5371461ba52987a70d70b37b52c8a Mon Sep 17 00:00:00 2001 From: Benjamin Wallberg Date: Fri, 27 Sep 2024 10:59:28 +0200 Subject: [PATCH] feat: mp4 mode handling --- src/demo/filtered-events.hook.ts | 11 +++++++++-- src/demo/native-events.hook.ts | 1 + src/demo/player.tsx | 2 +- src/media-event-filter.ts | 16 +++++++++++++--- 4 files changed, 24 insertions(+), 6 deletions(-) diff --git a/src/demo/filtered-events.hook.ts b/src/demo/filtered-events.hook.ts index 15fddba..4b71d92 100644 --- a/src/demo/filtered-events.hook.ts +++ b/src/demo/filtered-events.hook.ts @@ -1,7 +1,13 @@ import { useEffect, useState } from "react"; import { FilteredMediaEvent, getMediaEventFilter } from "../media-event-filter"; -export const useFilteredEvents = ({ video }: { video: HTMLVideoElement }) => { +export const useFilteredEvents = ({ + video, + mp4Mode = false, +}: { + video: HTMLVideoElement; + mp4Mode: boolean; +}) => { const [playing, setPlaying] = useState(false); const [seeking, setSeeking] = useState(false); const [buffering, setBuffering] = useState(false); @@ -25,6 +31,7 @@ export const useFilteredEvents = ({ video }: { video: HTMLVideoElement }) => { let seekOrBufferTimestamp = 0; const mef = getMediaEventFilter({ + mp4Mode, mediaElement: video, callback: (evt) => { if (!video) return; @@ -110,7 +117,7 @@ export const useFilteredEvents = ({ video }: { video: HTMLVideoElement }) => { return () => { mef.teardown(); }; - }, [video]); + }, [video, mp4Mode]); return { playing, diff --git a/src/demo/native-events.hook.ts b/src/demo/native-events.hook.ts index 976d5dd..bc9277c 100644 --- a/src/demo/native-events.hook.ts +++ b/src/demo/native-events.hook.ts @@ -17,6 +17,7 @@ export const useNativeEvents = ({ video }: { video: HTMLVideoElement }) => { currentTime: video.currentTime, duration: video.duration, seeking: video.seeking, + playbackRate: video.playbackRate, }; console[evt === MediaEvent.timeupdate ? "debug" : "log"]( diff --git a/src/demo/player.tsx b/src/demo/player.tsx index 99e70d5..ca772b4 100644 --- a/src/demo/player.tsx +++ b/src/demo/player.tsx @@ -96,7 +96,7 @@ export const Player = ({ videoUrl, engine }: PlayerOptions) => { useNativeEvents({ video }); const { playing, seeking, buffering, events, blocked, loading } = - useFilteredEvents({ video }); + useFilteredEvents({ video, mp4Mode: videoUrl?.includes(".mp4") ?? false }); const renderEvents = useRenderEvents(events); diff --git a/src/media-event-filter.ts b/src/media-event-filter.ts index 1889141..10d3a94 100644 --- a/src/media-event-filter.ts +++ b/src/media-event-filter.ts @@ -27,6 +27,9 @@ type TFilteredMediaEventCallback = (event: FilteredMediaEvent) => void; type TMediaEventFilterOptions = { mediaElement: HTMLMediaElement; callback: TFilteredMediaEventCallback; + // Should be set to `true` when playing MP4 files + // as the video element CAN stop buffering when readyState is 3 rather than 4. + mp4Mode: boolean; }; type TCallback = () => void; @@ -103,6 +106,7 @@ export type TMediaEventFilter = { export const getMediaEventFilter = ({ mediaElement, callback, + mp4Mode = false, }: TMediaEventFilterOptions): TMediaEventFilter => { let ratechangeBufferTimeout: number | null = null; @@ -133,8 +137,13 @@ export const getMediaEventFilter = ({ }; const onCanPlay = (): void => { - if (isNotReady()) return; + if (isNotReady()) { + if (mp4Mode) { + onCanPlayThrough(); + } + return; + } // guard for when an engine sets playbackRate to 0 to continue buffering // recover in "ratechange" event if (mediaElement.playbackRate === 0) { @@ -183,8 +192,9 @@ export const getMediaEventFilter = ({ const onCanPlayThrough = (): void => { // guard for when an engine sets playbackRate to 0 to continue buffering - // recover in "ratechange" event - if (mediaElement.playbackRate === 0) { + // recover in "ratechange" event. + // Not used in mp4Mode as the engine doesn't update playbackRate with mp4s + if (!mp4Mode && mediaElement.playbackRate === 0) { state = { ...state, deferCanPlayThroughHandling: true,