MCPcopy
hub / github.com/simstudioai/sim / concat

Function concat

apps/sim/lib/media/ffmpeg.ts:351–429  ·  view source on GitHub ↗
(dir: string, inputPaths: string[])

Source from the content-addressed store, hash-verified

349}
350
351async function concat(dir: string, inputPaths: string[]): Promise<FfmpegResult> {
352 if (inputPaths.length < 2) throw new Error('concat requires at least 2 clips')
353 const probes = await Promise.all(inputPaths.map(probeFile))
354 probes.forEach((p, i) => {
355 if (!p.hasVideo) {
356 throw new Error(
357 `concat input ${i} has no video stream; concat joins video clips (use mix_audio/overlay_audio for audio-only files).`
358 )
359 }
360 })
361 const width = probes[0].width || 1280
362 const height = probes[0].height || 720
363 const fps = 30
364
365 // Normalize every clip to identical codec/size/fps/pixfmt, and SYNTHESIZE silent
366 // audio for clips that have no audio stream. Clips generated without native audio
367 // (generateAudio:false) otherwise break the concat filtergraph (it referenced a
368 // non-existent [i:a]), which is the "Error binding filtergraph inputs/outputs" failure.
369 const normalized: string[] = []
370 for (let i = 0; i < inputPaths.length; i++) {
371 const out = path.join(dir, `norm-${i}.mp4`)
372 const cmd = ffmpeg().input(inputPaths[i])
373 const maps: string[] = ['-map', '0:v:0']
374 const extra: string[] = []
375 if (probes[i].hasAudio) {
376 maps.push('-map', '0:a:0')
377 } else {
378 cmd
379 .input('anullsrc=channel_layout=stereo:sample_rate=48000')
380 .inputOptions(['-f', 'lavfi', '-t', String(probes[i].durationSeconds || 1)])
381 maps.push('-map', '1:a:0')
382 extra.push('-shortest')
383 }
384 cmd
385 .videoFilters(
386 `scale=${width}:${height}:force_original_aspect_ratio=decrease,pad=${width}:${height}:(ow-iw)/2:(oh-ih)/2,setsar=1,fps=${fps},format=yuv420p`
387 )
388 .outputOptions([
389 ...maps,
390 '-c:v',
391 'libx264',
392 '-preset',
393 'medium',
394 '-crf',
395 '18',
396 '-pix_fmt',
397 'yuv420p',
398 '-r',
399 String(fps),
400 '-video_track_timescale',
401 '90000',
402 '-c:a',
403 'aac',
404 '-b:a',
405 '192k',
406 '-ar',
407 '48000',
408 '-ac',

Callers 1

runFfmpegOperationFunction · 0.85

Calls 6

readOutFunction · 0.85
joinMethod · 0.80
runCommandFunction · 0.70
writeFileMethod · 0.65
replaceMethod · 0.65
pushMethod · 0.45

Tested by

no test coverage detected