我一直在尝试弄清楚如何为 ffmpeg 编写一个过滤器来拍摄一组视频并使它们具有相同的时间长度。
例如,我有一个 35 秒的视频和一个 15 秒的视频,但我希望这两个视频都长 30 秒。
我知道我可以使用 setpts 过滤器来加快或减慢视频速度,但说实话我不懂过滤器。我知道 setpts 是“更改输入帧的 PTS(显示时间戳)”。但我不认为这是正确的过滤器,因为我认为它适用于帧的时间长度,与视频的时间长度无关。
答案1
假设你的输入文件是input.mp4
,输出是output.mp4
。你希望output.mp4
输出长度大约为 30 秒。
您可以运行以下命令:
INPUT_FILE=input.mp4 && \
OUTPUT_FILE=output.mp4 && \
OUTPUT_DURATION=30 && \
CURRENT_DURATION=$(ffprobe -v error -show_format -show_streams -i "${INPUT_FILE}" | grep 'duration=' | head -n 1 | sed 's/duration=//') && \
echo "Found current duration ${CURRENT_DURATION} seconds" && \
SPEEDUP=$(( $CURRENT_DURATION / $OUTPUT_DURATION )) && \
echo "Processing conversion with speedup ${SPEEDUP}x" && \
ffmpeg \
-hide_banner \
-v warning \
-i "${INPUT_FILE}" \
-filter:v "setpts=PTS/${SPEEDUP}" \
-filter:a "atempo=${SPEEDUP}" \
"${OUTPUT_FILE}" && \
echo "Done! File written to ${OUTPUT_FILE}"
让我们分解一下。首先,我们使用以下命令查找文件时长:
ffprobe -v error -show_format -show_streams -i "${INPUT_FILE}" | grep 'duration=' | head -n 1 | sed 's/duration=//'
我们使用 获取持续时间,然后使用、和ffprobe
的组合从输出中提取正确的数字。grep
head
sed
接下来,我们将这个数量除以 30:
$(( $CURRENT_DURATION / $OUTPUT_DURATION ))
我们将其插入到 中,-filter:v "setpts=PTS/..."
以获得正确的视频时间缩放,以实现加速或减速。最后,我们使用它-filter:a "atempo=..."
来获得等效的音频缩放。
还请注意,这-hide_banner -v warning
只是为了减少日志信息,但如果您愿意,可以将其删除。
atempo
编辑 1:使用过滤器添加音频时间拉伸
答案2
我在 SPEEDUP 和 macos zsh 上遇到了一些问题,不允许浮点数,所以我改用
SPEEDUP=$(printf "%.2f" $(echo "scale=3; $CURRENT_DURATION / $OUTPUT_DURATION" | bc)) && \
这允许 2 位浮点数根据需要向上或向下舍入。