@calipsa/video-utils
Version:
Video utilities
77 lines (63 loc) • 1.74 kB
text/typescript
import type {
FfprobeData,
FfmpegCommandOptions,
FfmpegCommand,
} from 'fluent-ffmpeg'
import {
compact,
range,
} from 'lodash'
import getFrameAt from '../getFrameAt'
interface Options {
path: string,
numFrames: number,
videoMetadata: FfprobeData,
ffmpegCommandOptions?: FfmpegCommandOptions,
configureFfmpeg?: (ffmpegCommand: FfmpegCommand) => void,
}
export default async ({
path,
numFrames,
videoMetadata,
ffmpegCommandOptions,
configureFfmpeg,
}: Options) => {
const videoStreamMetaData = videoMetadata.streams.find(item => item.codec_type === 'video')
if (!videoStreamMetaData) {
throw new Error('No video streams found')
}
const {
nb_frames: numInputFramesStr,
start_time: startTime = 0,
duration: durationStr,
} = videoStreamMetaData
const duration = durationStr === undefined ? undefined : +durationStr
if (!duration || !Number.isFinite(duration)) {
throw new TypeError(`ffprobe returned invalid duration: ${durationStr}`)
}
if (numFrames === 1) {
const frame = await getFrameAt({
path,
time: startTime + duration / 2,
ffmpegCommandOptions,
configureFfmpeg,
})
return [frame]
}
const numInputFrames = numInputFramesStr === undefined ? undefined : +numInputFramesStr
const interval = numInputFrames
? duration / (numFrames - 1) * (1 - 1 / numInputFrames)
: duration / numFrames
const promises = range(numFrames).map(async (i) => {
const time = startTime + i * interval
const buffer = await getFrameAt({
path,
time,
ffmpegCommandOptions,
configureFfmpeg,
})
return buffer?.length > 0 && buffer
})
const arr = await Promise.all(promises)
return compact(arr)
}