Lazy-load mediabunny on web (#11094)
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,17 +1,8 @@
|
||||
import {type ImagePickerAsset} from 'expo-image-picker'
|
||||
import {
|
||||
ALL_FORMATS,
|
||||
type AudioCodec,
|
||||
BlobSource,
|
||||
BufferTarget,
|
||||
canEncodeAudio,
|
||||
canEncodeVideo,
|
||||
Conversion,
|
||||
Input,
|
||||
Mp4OutputFormat,
|
||||
Output,
|
||||
type Input as MediaBunnyInput,
|
||||
type VideoCodec,
|
||||
WebMOutputFormat,
|
||||
} from 'mediabunny'
|
||||
|
||||
import {VIDEO_MAX_SIZE} from '#/lib/constants'
|
||||
@@ -23,6 +14,7 @@ import {
|
||||
COMPRESSION_MIN_SIZE_BYTES,
|
||||
COMPRESSION_TARGET_BITRATE,
|
||||
} from './constants'
|
||||
import {loadMediaBunny} from './mediabunny'
|
||||
import {type CompressedVideo, type ProbedMetadata} from './types'
|
||||
|
||||
// Codecs to try in order of preference
|
||||
@@ -112,6 +104,7 @@ export async function compressVideo(
|
||||
}
|
||||
|
||||
async function probeWithMediaBunny(blob: Blob): Promise<ProbedMetadata> {
|
||||
const {ALL_FORMATS, BlobSource, Input} = await loadMediaBunny()
|
||||
const input = new Input({source: new BlobSource(blob), formats: ALL_FORMATS})
|
||||
try {
|
||||
const videoTrack = await input.getPrimaryVideoTrack()
|
||||
@@ -153,6 +146,7 @@ async function findEncodableVideoCodec(
|
||||
width: number,
|
||||
height: number,
|
||||
): Promise<{codec: VideoCodec; useWebM: boolean} | null> {
|
||||
const {canEncodeVideo} = await loadMediaBunny()
|
||||
for (const codec of VIDEO_CODECS) {
|
||||
const canEncode = await canEncodeVideo(codec, {
|
||||
width,
|
||||
@@ -179,9 +173,10 @@ const AUDIO_CODECS_MP4: AudioCodec[] = ['aac']
|
||||
const AUDIO_CODECS_WEBM: AudioCodec[] = ['opus', 'vorbis']
|
||||
|
||||
async function findEncodableAudioCodec(
|
||||
audioTrack: Awaited<ReturnType<Input['getPrimaryAudioTrack']>>,
|
||||
audioTrack: Awaited<ReturnType<MediaBunnyInput['getPrimaryAudioTrack']>>,
|
||||
useWebM: boolean,
|
||||
): Promise<{codec: AudioCodec} | null> {
|
||||
const {canEncodeAudio} = await loadMediaBunny()
|
||||
if (!audioTrack) {
|
||||
return null
|
||||
}
|
||||
@@ -228,6 +223,17 @@ async function doCompression(
|
||||
): Promise<CompressedVideo> {
|
||||
const {onProgress, signal} = opts
|
||||
|
||||
const {
|
||||
ALL_FORMATS,
|
||||
BlobSource,
|
||||
BufferTarget,
|
||||
Conversion,
|
||||
Input,
|
||||
Mp4OutputFormat,
|
||||
Output,
|
||||
WebMOutputFormat,
|
||||
} = await loadMediaBunny()
|
||||
|
||||
const input = new Input({
|
||||
source: new BlobSource(blob),
|
||||
formats: ALL_FORMATS,
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
type MediaBunnyModule = typeof import('mediabunny')
|
||||
|
||||
let promise: Promise<MediaBunnyModule> | undefined
|
||||
|
||||
/**
|
||||
* Lazily loads mediabunny into its own webpack chunk and caches the resulting
|
||||
* promise so the module is fetched at most once. If the import fails (e.g. a
|
||||
* transient chunk-load error), the cached promise is reset so a later call can
|
||||
* retry the load.
|
||||
*/
|
||||
export function loadMediaBunny(): Promise<MediaBunnyModule> {
|
||||
promise ??= import(/* webpackChunkName: "mediabunny" */ 'mediabunny').catch(
|
||||
e => {
|
||||
// reset so a later attempt can retry after a transient chunk-load failure
|
||||
promise = undefined
|
||||
throw e
|
||||
},
|
||||
)
|
||||
return promise
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
import {type ImagePickerAsset} from 'expo-image-picker'
|
||||
import {ALL_FORMATS, BlobSource, Input} from 'mediabunny'
|
||||
|
||||
import {loadMediaBunny} from '#/lib/media/video/mediabunny'
|
||||
import {logger} from '#/logger'
|
||||
|
||||
export function hasWebCodecs(): boolean {
|
||||
@@ -55,6 +55,7 @@ async function getMetadataWithWebCodecs(
|
||||
file: File,
|
||||
blobUrl: string,
|
||||
): Promise<ImagePickerAsset> {
|
||||
const {ALL_FORMATS, BlobSource, Input} = await loadMediaBunny()
|
||||
const input = new Input({
|
||||
source: new BlobSource(file),
|
||||
formats: ALL_FORMATS,
|
||||
|
||||
Reference in New Issue
Block a user