From 516c924690760de23aea1514683592eef0a5aead Mon Sep 17 00:00:00 2001 From: Jonny Burger Date: Wed, 22 Jan 2025 10:17:47 +0100 Subject: [PATCH] `@remotion/media-parser`: Break event loop from time to time --- packages/convert/app/lib/use-thumbnail.ts | 7 ++++++- packages/media-parser/src/parse-media.ts | 2 ++ .../src/state/last-eventloop-break.ts | 18 ++++++++++++++++++ .../media-parser/src/state/parser-state.ts | 2 ++ 4 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 packages/media-parser/src/state/last-eventloop-break.ts diff --git a/packages/convert/app/lib/use-thumbnail.ts b/packages/convert/app/lib/use-thumbnail.ts index 362bcef3b30..342d7a057b6 100644 --- a/packages/convert/app/lib/use-thumbnail.ts +++ b/packages/convert/app/lib/use-thumbnail.ts @@ -31,6 +31,11 @@ export const useThumbnailAndWaveform = ({ const execute = useCallback(() => { const abortController = new AbortController(); + + const hasEnoughData = () => { + onDone(); + }; + parseMedia({ signal: abortController.signal, reader: src.type === 'file' ? webFileReader : fetchReader, @@ -114,7 +119,7 @@ export const useThumbnailAndWaveform = ({ if (frames >= framesToGet) { abortController.abort(); frame.close(); - onDone(); + hasEnoughData(); return; } diff --git a/packages/media-parser/src/parse-media.ts b/packages/media-parser/src/parse-media.ts index adc78e9731f..8c026f2ac11 100644 --- a/packages/media-parser/src/parse-media.ts +++ b/packages/media-parser/src/parse-media.ts @@ -187,6 +187,8 @@ const internalParseMedia: InternalParseMedia = async function < } } + await state.eventLoop.eventLoopBreakIfNeeded(); + const hasBigBuffer = iterator.bytesRemaining() > 100_000; if (iterationWithThisOffset > 0 || !hasBigBuffer) { diff --git a/packages/media-parser/src/state/last-eventloop-break.ts b/packages/media-parser/src/state/last-eventloop-break.ts new file mode 100644 index 00000000000..ba5806c9578 --- /dev/null +++ b/packages/media-parser/src/state/last-eventloop-break.ts @@ -0,0 +1,18 @@ +import type {LogLevel} from '../log'; +import {Log} from '../log'; + +export const eventLoopState = (logLevel: LogLevel) => { + let lastEventLoopBreak = Date.now(); + + const eventLoopBreakIfNeeded = async () => { + if (Date.now() - lastEventLoopBreak > 2_000) { + await new Promise((resolve) => { + setTimeout(() => resolve(), 10); + }); + Log.verbose(logLevel, '10ms event loop break'); + lastEventLoopBreak = Date.now(); + } + }; + + return {eventLoopBreakIfNeeded}; +}; diff --git a/packages/media-parser/src/state/parser-state.ts b/packages/media-parser/src/state/parser-state.ts index 17aba81e65a..3de682c7dda 100644 --- a/packages/media-parser/src/state/parser-state.ts +++ b/packages/media-parser/src/state/parser-state.ts @@ -9,6 +9,7 @@ import {flacState} from './flac-state'; import {imagesState} from './images'; import {isoBaseMediaState} from './iso-base-media/iso-state'; import {keyframesState} from './keyframes'; +import {eventLoopState} from './last-eventloop-break'; import {makeMp3State} from './mp3'; import {riffSpecificState} from './riff'; import {sampleCallback} from './sample-callbacks'; @@ -101,6 +102,7 @@ export const makeParserState = ({ videoSection: videoSectionState(), logLevel, iterator, + eventLoop: eventLoopState(logLevel), }; };