Use toolbox video compressor (#11246)

This commit is contained in:
Spence Pope
2026-08-06 08:16:18 -04:00
committed by GitHub
parent 1ac5a71d61
commit 5cf6d8fa21
7 changed files with 45 additions and 29 deletions
+2 -2
View File
@@ -1388,7 +1388,7 @@ export type Events = {
// === Video upload funnel (Frontend Spec section D) ===
// Every event carries uploadId (client-generated UUID, ties one upload
// session end-to-end) + engine (compression engine id, e.g.
// native:react-native-compressor@1.13.0). jobId is added once the server
// native:@bsky.app/video-compressor@0.2.0). jobId is added once the server
// returns it. Sizes / codecs / dimensions / timings only - never content.
'video:upload:picked': {
uploadId: string
@@ -1407,7 +1407,7 @@ export type Events = {
// Native-only. Raw container metadata returned by the new module's probe()
// (bitrate, codec, HDR, frame rate, rotation, etc.). Fires once per upload
// between compressStarted and the compressSkipped/compressCompleted decision.
// The web (mediabunny) and legacy rn-compressor engines do not surface this.
// The web mediabunny engine also emits this from its own probe.
'video:upload:probed': {
uploadId: string
engine: string
+21 -23
View File
@@ -1,11 +1,13 @@
import {getVideoMetaData, Video} from 'react-native-compressor'
import {type ImagePickerAsset} from 'expo-image-picker'
import {compress, probe, type VideoMetadata} from '@bsky.app/video-compressor'
import {SUPPORTED_MIME_TYPES, type SupportedMimeTypes} from '#/lib/constants'
import {logger} from '#/logger'
import {probe} from '../../../../modules/expo-bluesky-video-compress'
import {
COMPRESSION_MAX_DIMENSION,
COMPRESSION_TARGET_BITRATE,
} from './constants'
import {type CompressedVideo, type ProbedMetadata} from './types'
import {extToMime} from './util'
const MIN_SIZE_FOR_COMPRESSION_BYTES = 25 * 1024 * 1024 // 25mb
@@ -23,7 +25,7 @@ export async function compressVideo(
// future smart-skip thresholds. Failures must not block the upload.
if (onProbe && file.mimeType !== 'image/gif') {
try {
onProbe(await probe(file.uri))
onProbe(toProbedMetadata(await probe(file.uri)))
} catch (e) {
logger.debug('video probe failed', {safeMessage: e})
}
@@ -60,31 +62,27 @@ export async function compressVideo(
}
}
const compressed = await Video.compress(
return compress(
file.uri,
{
compressionMethod: 'manual',
bitrate: 3_000_000, // 3mbps
maxSize: 1920,
targetBitrate: COMPRESSION_TARGET_BITRATE,
maxSize: COMPRESSION_MAX_DIMENSION,
codec: 'auto',
frameRateCap: 30,
mimeType: file.mimeType,
fileSize: file.fileSize,
// Force a transcode for unacceptable-format files regardless of size.
// rnc's default minimumFileSizeForCompress would otherwise pass small
// The compressor's default threshold would otherwise pass small
// unacceptable-format files through unchanged and the server would
// reject them. Acceptable formats are already short-circuited above so
// they never reach this call.
// WARNING: this ONE SPECIFIC ARG is in MB -sfn
minimumFileSizeForCompress: 0,
getCancellationId: id => {
if (signal) {
signal.addEventListener('abort', () => {
Video.cancelCompression(id)
})
}
},
passthroughBelowBytes: 0,
passthroughGif: false,
},
onProgress,
{onProgress, signal},
)
const info = await getVideoMetaData(compressed)
return {uri: compressed, size: info.size, mimeType: extToMime(info.extension)}
}
function toProbedMetadata(metadata: VideoMetadata): ProbedMetadata {
return metadata
}
+2 -2
View File
@@ -5,6 +5,6 @@
export const COMPRESSION_TARGET_BITRATE = 3_000_000 // 3 Mbps
// Output dimension cap when compressing, and skip threshold for source files.
export const COMPRESSION_MAX_DIMENSION = 1920
// Web only: files under this size skip compression entirely. Native applies
// its own threshold logic inside react-native-compressor.
// Web only: files under this size skip compression entirely. Native uses a
// 25 MiB threshold in compress.ts for compatibility with the previous engine.
export const COMPRESSION_MIN_SIZE_BYTES = 25_000_000
+1 -1
View File
@@ -18,7 +18,7 @@ type MetricFn = <E extends keyof Metrics>(event: E, payload: Metrics[E]) => void
const COMPRESS_ENGINE =
Platform.OS === 'web'
? 'web:mediabunny@1.25.3'
: 'native:react-native-compressor@1.13.0'
: 'native:@bsky.app/video-compressor@0.2.0'
type Phase = 'compress' | 'upload' | 'processing'
+1 -1
View File
@@ -22,7 +22,7 @@ export type CompressedVideo = {
}
// Source container metadata read off the input before any encoding decision.
// Same shape across native (expo-bluesky-video-compress probe) and web
// Same shape across native (@bsky.app/video-compressor probe) and web
// (mediabunny Input + track inspection). Numbers are raw - no bucketing.
export type ProbedMetadata = {
mimeType: string