(
inputPath: string,
metadata: VideoMetadata,
options: VideoProcessingOptions = {},
onProgress?: ProgressCallback,
abortSignal?: AbortSignal,
resilientFlags?: ResilientInputFlags,
)
| 1272 | } |
| 1273 | |
| 1274 | export async function processVideo( |
| 1275 | inputPath: string, |
| 1276 | metadata: VideoMetadata, |
| 1277 | options: VideoProcessingOptions = {}, |
| 1278 | onProgress?: ProgressCallback, |
| 1279 | abortSignal?: AbortSignal, |
| 1280 | resilientFlags?: ResilientInputFlags, |
| 1281 | ): Promise<TempFileHandle> { |
| 1282 | const definedOptions = Object.fromEntries( |
| 1283 | Object.entries(options).filter(([, value]) => value !== undefined), |
| 1284 | ) as VideoProcessingOptions; |
| 1285 | const opts = { ...DEFAULT_OPTIONS, ...definedOptions }; |
| 1286 | const outputTempFile = await createTempFile(".mp4"); |
| 1287 | |
| 1288 | const remuxOnly = opts.remuxOnly; |
| 1289 | const sourceH264Level = |
| 1290 | !remuxOnly && metadata.videoCodec === "h264" |
| 1291 | ? await probeH264Level(inputPath, abortSignal) |
| 1292 | : null; |
| 1293 | const targetH264Level = pickMobileSafeH264Level(metadata, opts); |
| 1294 | const videoTranscode = remuxOnly |
| 1295 | ? false |
| 1296 | : needsVideoTranscode(metadata, opts, sourceH264Level); |
| 1297 | const audioTranscode = remuxOnly ? false : needsAudioTranscode(metadata); |
| 1298 | const extraInputArgs = resilientFlags |
| 1299 | ? buildExtraInputFlags(resilientFlags) |
| 1300 | : []; |
| 1301 | const extraOutputArgs = resilientFlags |
| 1302 | ? buildExtraOutputFlags(resilientFlags) |
| 1303 | : []; |
| 1304 | const processTimeoutMs = getProcessTimeoutMs( |
| 1305 | metadata.duration, |
| 1306 | opts.timeoutMs, |
| 1307 | ); |
| 1308 | const ffmpegArgs: string[] = [ |
| 1309 | "ffmpeg", |
| 1310 | "-threads", |
| 1311 | "2", |
| 1312 | ...extraInputArgs, |
| 1313 | "-i", |
| 1314 | inputPath, |
| 1315 | ]; |
| 1316 | |
| 1317 | if (videoTranscode) { |
| 1318 | ffmpegArgs.push( |
| 1319 | "-c:v", |
| 1320 | "libx264", |
| 1321 | "-preset", |
| 1322 | opts.preset, |
| 1323 | "-crf", |
| 1324 | opts.crf.toString(), |
| 1325 | "-vf", |
| 1326 | `scale='min(${opts.maxWidth},iw)':'min(${opts.maxHeight},ih)':force_original_aspect_ratio=decrease,scale=trunc(iw/2)*2:trunc(ih/2)*2`, |
| 1327 | "-pix_fmt", |
| 1328 | "yuv420p", |
| 1329 | "-level:v", |
| 1330 | targetH264Level.ffmpegValue, |
| 1331 | ); |
no test coverage detected