我正在尝试合并多个视频和音频文件,但我已尝试多次循环视频但没有成功,它会播放所有 3 个视频并在第 3 个视频处停止,直到音频结束。
ffmpeg -y -i "video\0.mp4" -i "video\1.mp4" -i "video\2.mp4" -i audio.m4a -filter_complex "[1:v]xfade=transition=wipeleft:duration=1:offset=9[vfade1];[vfade1][2:v]xfade=transition=wipeleft:duration=1:offset=18[v]" -map "[v]" -map 3:a -c:v libx264 -r 30 -pix_fmt yuv420p -c:a aac -strict experimental ./out_fade1.mp4
请帮我修复代码,使其播放视频 0.mp4 -> 1.mp4 -> 2.mp4。如果音频还在,则返回0.mp4并继续这样,直到音频结束。
这真的非常困难。
获得
concat
的技巧是最初转换为 matroska
。
#!/bin/bash
if [ $# -eq 0 ]; then
>&2 echo -e "\nUsage: $0 file.m4a\n"
exit 1
fi
audio_input="$1"
echo "$audio_input"
# Extract audio's runtime
audio_runtime=$(ffmpeg -hide_banner -i "$audio_input" 2>&1 | grep "Duration"| cut -d ' ' -f 4 | sed s/,//)
echo "$audio_runtime"
# Create and enter the working directory
mkdir -p concatenated_videos_dir/src
cd concatenated_videos_dir/src
# Ensure the source container is matroska
video_input_1=(../../*.mp4)
for src_files in "${video_input_1[@]}"; do
file_name=$(basename "$src_files" .mp4)
echo "$src_files $file_name"
ffmpeg -hide_banner -i "$src_files" -c:v libx264 -pix_fmt yuv420p -an "${file_name}.mkv"
done
video_input_2=(*.mkv)
# Declare array for durations
declare -a video_durations
# Extract durations, and append to the array
for video_file in "${video_input_2[@]}"; do
video_duration=$(ffmpeg -i "$video_file" 2>&1 | grep "Duration" | cut -d ' ' -f 4 | sed s/,//)
video_durations+=("$video_duration")
done
# Calculate the total duration of all video segments
total_video_duration=0
for duration in "${video_durations[@]}"; do
# Extract HH:MM:SS.ms
hours=$(echo "$duration" | awk -F: '{print $1}')
minutes=$(echo "$duration" | awk -F: '{print $2}')
seconds=$(echo "$duration" | awk -F: '{print $3}' | cut -d '.' -f 1) # remove milliseconds
# Convert hours, minutes, and seconds to seconds
duration_in_seconds=$((hours * 3600 + minutes * 60 + seconds))
# Add duration to the total sum
total_video_duration=$((total_video_duration + duration_in_seconds))
done
# Extract audio runtime in HH:MM:SS format
audio_runtime=$(ffmpeg -hide_banner -i ../../"$audio_input" 2>&1 | grep "Duration"| cut -d ' ' -f 4 | sed s/,//)
audio_runtime=$(echo "${audio_runtime/\.*/}")
# Convert audio runtime to seconds
audio_seconds=$(echo "$audio_runtime" | awk -F':' '{print ($1 * 3600) + ($2 * 60) + $3}')
# Calculate the number of loops needed to match audio runtime
num_loops=$(awk "BEGIN {print int(($audio_seconds + $total_video_duration - 1) / $total_video_duration)}")
echo "Total video duration: $total_video_duration"
echo "Audio runtime: $audio_seconds"
echo "Number of loops: $num_loops"
# Loop through each video file
for filename in "${video_input_2[@]}"; do
# Loop through each loop index
for ((i=0; i<num_loops; i++)); do
# Create the prefix for the loop index
prefix=$((i + 1))"_"
# Copy the video file with the prefixed filename
cp "$filename" ../"${prefix}${filename}"
done
done
cd ..
rm -rf src
# Create a list for concatenation
ls --quoting-style=shell-always -1v *.mkv > tmp.txt
sed 's/^/file /' tmp.txt > list.txt && rm tmp.txt
# Concatenate the videos into a single file output to parent directory
ffmpeg -hide_banner -f concat -safe 0 -i list.txt -c:v libx264 -crf 18 -pix_fmt yuv420p -preset ultrafast -avoid_negative_ts make_zero ../output.mkv
# Return to parent directory and cleanup
cd ..
rm -rf concatenated_videos_dir
# Truncate video overlap to audio runtime
ffmpeg -hide_banner -i output.mkv -c:v copy -crf 18 -preset ultrafast -ss -00:00:00.00 -to $(ffmpeg -hide_banner -i "$audio_input" 2>&1 | grep "Duration" | awk -F '[:,]' '{print $2 ":" $3 ":" $4}') video_for_mux.mkv
# Ensure source audio for final mux is PCM .wav
ffmpeg -hide_banner -i "$audio_input" audio.wav
# Final mux
ffmpeg -hide_banner -i video_for_mux.mkv -i audio.wav -c:v libx264 -crf 18 -c:a aac -preset ultrafast -movflags +faststart finished_mux.mkv
# Cleanup and exit
rm video_for_mux.mkv output.mkv audio.wav
exit 0
另存为:
loop_to_audio.sh
chmod +x loop_to_audio.sh
./loop_to_audio.sh your_m4a_file.m4a
将所有要循环的 mp4 放在与此脚本和 .m4a 文件相同的目录中,并按如上所示使用。
已在 Fedora 38 上使用 ffmpeg 版本 6.0.1 进行测试。