利用ffmpeg的xfade转场滤镜把多个视频文件连接到一个文件的bash脚本

时间:2024-03-06 15:33:03

FFmpeg的xfade转场,现在一共有31种效果,2020年02月10日以后的FFmpeg代码中有效;

  1 #!/bin/bash
  2 # Example of concatenating multiple mp4s together with 1-second transitions between them.
  3 
  4 transitions=( \
  5 "fade"        \
  6 "wipeleft"    \
  7 "wiperight"   \
  8 "wipeup"      \
  9 "wipedown"    \
 10 "slideleft"   \
 11 "slideright"  \
 12 "slideup"     \
 13 "slidedown"   \
 14 "circlecrop"  \
 15 "rectcrop"    \
 16 "distance"    \
 17 "fadeblack"   \
 18 "fadewhite"   \
 19 "radial"      \
 20 "smoothleft"  \
 21 "smoothright" \
 22 "smoothup"    \
 23 "smoothdown"  \
 24 "circleopen"  \
 25 "circleclose" \
 26 "vertopen"    \
 27 "vertclose"   \
 28 "horzopen"    \
 29 "horzclose"   \
 30 "dissolve"    \
 31 "pixelize"    \
 32 "diagtl"      \
 33 "diagtr"      \
 34 "diagbl"      \
 35 "diagbr"      \
 36 )
 37 
 38 length=${#transitions[@]}
 39 
 40 interval=1
 41 
 42 x264="-look_ahead 0 -ac 2 -c:v h264_qsv -c:a aac -profile:v high -level 3.1 -preset:v veryfast"
 43 ki="-keyint_min 72 -g 72 -sc_threshold 0"
 44 br="-b:v 3000k -minrate 3000k -maxrate 6000k -bufsize 6000k -b:a 128k -avoid_negative_ts make_zero -fflags +genpts"
 45 
 46 duration=1
 47 function get_duration_video_ffprobe(){
 48   duration=$(ffprobe -v error -count_frames -select_streams v:0 -show_entries stream=duration -of default=nokey=1:noprint_wrappers=1 "$1")
 49   duration=$(echo "scale=3; $duration/1"|bc -l)
 50 }
 51 function get_duration_audio_ffprobe(){
 52   aduration=$(ffprobe -v error -count_frames -select_streams a:0 -show_entries stream=duration -of default=nokey=1:noprint_wrappers=1 "$1")
 53   aduration=$(echo "scale=3; $aduration/1"|bc -l)
 54 }
 55 
 56 MediaInfo="D:\soft\MediaInfo_CLI_19.04_Windows_x64\MediaInfo.exe"
 57 function get_duration_video_MediaInfo(){
 58   # duration=$($MediaInfo --Inform="Video;%Duration/String3%" "$1")
 59   duration=$($MediaInfo --Inform="Video;%Duration%" "$1")
 60   duration=$(echo "scale=3; $duration/1000"|bc -l)
 61 }
 62 function get_duration_audio_MediaInfo(){
 63   # duration=$($MediaInfo --Inform="Video;%Duration/String3%" "$1")
 64   aduration=$($MediaInfo --Inform="Audio;%Duration%" "$1")
 65   aduration=$(echo "scale=3; $aduration/1000"|bc -l)
 66 }
 67 
 68 # ls -u *.mp4       sort by time
 69 # ls *.mp4|sort     sort by name
 70 line=-1
 71 IFS=$(echo -en "\n\b")
 72 for f in `ls *.mp4|sort`; do
 73      line=$((line+1))
 74      get_duration_video_MediaInfo "${f}"
 75      get_duration_audio_MediaInfo "${f}"
 76      ifd=`echo "scale=0; ${aduration}*1000-${duration}*1000"|bc -l -q`
 77      ifd=${ifd/.000/}
 78      echo ${line} ${f} ${duration} - ${aduration} = $ifd
 79      if [[ ${ifd} -le 0 ]]; then
 80        duration=${aduration}
 81      fi
 82      #echo ${line} ${f} ${duration}
 83      duration_array[${line}]=${duration}
 84      filename_array[${line}]=${f}
 85      index_array[${line}]=${line}
 86 done
 87 
 88 vfstr=""
 89 for i in ${index_array[@]}; do
 90      catlen=0$(echo ${duration_array[$i]}-${interval}|bc -l)
 91      if [ ${i} -lt ${line} ]
 92          then
 93              vfstr=${vfstr}"[$i:a]atrim=0:$catlen[a$i];"
 94          else
 95              vfstr=${vfstr}"[$i:a]atrim=0:${duration_array[$i]}[a$i];"
 96      fi
 97      vfstr=${vfstr}"[$i:v]split[v${i}00][v${i}10];"
 98 done
 99 
100 for i in ${index_array[@]}; do
101      catlen=0$(echo ${duration_array[$i]}-${interval}|bc -l)
102      vfstr=${vfstr}"[v${i}00]trim=0:$catlen[v${i}01];"
103      vfstr=${vfstr}"[v${i}10]trim=$catlen:${duration_array[$i]}[v${i}11t];"
104      vfstr=${vfstr}"[v${i}11t]setpts=PTS-STARTPTS[v${i}11];"
105 done
106 
107 for ((i=0; i<$line; ++i)) ; do
108     Index=$[i%(($length))]
109     #Index=$[RANDOM%(($length))]
110     echo ${transitions[$Index]}
111     vfstr=${vfstr}"[v${i}11][v$((i+1))01]xfade=duration=${interval}:transition=${transitions[$Index]}[vt${i}];"
112 done
113 
114 vfstr=${vfstr}"[v001]"
115 for ((i=0; i<$line; ++i)) ; do
116     vfstr=${vfstr}"[vt${i}]"
117 done
118 vfstr=${vfstr}"[v${line}11]concat=n=$((line+2))[outv];"
119 
120 for i in ${index_array[@]}; do
121     vfstr=${vfstr}"[a${i}]"
122 done
123 vfstr=${vfstr}"concat=n=$((line+1)):v=0:a=1[outa]"
124 
125 infile=""
126 for i in ${filename_array[@]}; do
127      infile=${infile}" -i \"$i\""
128 done
129 
130 if [ ! -d "merge" ];then
131   mkdir merge
132 fi
133 
134 echo ${vfstr} > _vfstr_.txt
135 cmd="ffmpeg -hide_banner${infile} \
136 -filter_complex_script \"_vfstr_.txt\" \
137 -map [outv] -map [outa] ${x264} ${ki} ${br} \
138 -y ./merge/ffmpeg-xfade-concat.mp4"
139 echo $cmd >_merge_.cmd
140 #./_merge_.cmd
141 
142 echo ${cmd}
143 bash -c "$cmd"

更详细的参见 https://github.com/qq2225936589/xfade-ffmpeg-script
转场效果参见 https://v.huya.com/play/270325342.html