如何为序列中所有幻灯片统一应用FFmpeg转场效果?
解决方案:用FFmpeg为未知数量的JPG幻灯片添加统一转场
要实现未知数量JPG的幻灯片转场,核心是将每张图片作为独立输入流,动态生成滤镜链完成转场拼接。以下是完整的Bash脚本:
#!/bin/bash # 配置参数 PLAY_DURATION=10 # 每张图片总显示时长(含转场) TRANSITION_DURATION=1 # 转场持续时间 FRAMERATE=30 # 视频帧率(越高转场越平滑) OUTPUT="./Slideshow.mp4" # 获取目录下所有JPG图片 images=("./slides/"*.jpg) num_images=${#images[@]} if [ $num_images -eq 0 ]; then echo "Error: No JPG files found in ./slides/" exit 1 fi # 构建FFmpeg输入参数:每个图片作为独立循环输入 ffmpeg_input=() for img in "${images[@]}"; do ffmpeg_input+=("-loop" "1" "-t" "$PLAY_DURATION" "-framerate" "$FRAMERATE" "-i" "$img") done # 构建滤镜链:先统一尺寸,再依次添加转场 filter_complex="" # 第一步:为每个输入应用pad滤镜(处理尺寸不一致) for i in $(seq 0 $((num_images-1))); do filter_complex+="[${i}]pad=ceil(iw/2)*2:ceil(ih/2)*2[s${i}]; " done # 第二步:拼接转场 # 第一张与第二张的转场 filter_complex+="[s0][s1]xfade=transition=circleopen:duration=${TRANSITION_DURATION}:offset=$((PLAY_DURATION - TRANSITION_DURATION))[f0]; " # 后续图片的转场循环 for i in $(seq 1 $((num_images-2))); do prev_idx=$((i-1)) current_offset=$(( (i+1)*PLAY_DURATION - TRANSITION_DURATION )) filter_complex+="[f${prev_idx}][s$((i+1))]xfade=transition=circleopen:duration=${TRANSITION_DURATION}:offset=${current_offset}[f${i}]; " done # 指定最终输出流 filter_complex+="[f$((num_images-2))]" # 执行FFmpeg命令 ffmpeg "${ffmpeg_input[@]}" \ -filter_complex "$filter_complex" \ -c:v libx264 -pix_fmt yuv420p \ "$OUTPUT"
关键说明:
- 输入处理:用
-loop 1 -t $PLAY_DURATION让每张图片循环播放指定时长,确保转场有足够的帧数据支撑。 - 尺寸统一:保留你原有的
pad滤镜,解决JPG尺寸不一致的问题。 - 转场逻辑:
xfade滤镜需要两个输入流,通过动态生成滤镜链,依次将前一个转场输出与下一张图片连接。offset参数计算:每张图片播放到PLAY_DURATION - TRANSITION_DURATION秒时开始转场,确保转场完成后刚好切换到下一张。
- 转场类型:可将
circleopen替换为ffmpeg支持的其他转场(如fade、slideleft、dissolve等),用ffmpeg -filters | grep xfade可查看所有可选类型。
为什么原命令无法实现转场?
你原命令用-pattern_type glob将所有JPG作为单个序列流输入,FFmpeg会按顺序播放每张图片,但fade=out仅对整个视频的最后一帧生效,无法实现每张之间的转场。只有将每张图片作为独立输入流,才能用xfade处理流之间的切换效果。
内容的提问来源于stack exchange,提问作者will
相关产品推荐
相关产品推荐

