FFMPEG:合并多个视频和音频,循环第一个视频直到音频结束

问题描述 投票:0回答:1

我正在尝试合并多个视频和音频文件,但我已尝试多次循环视频但没有成功,它会播放所有 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并继续这样,直到音频结束。

ffmpeg
1个回答
0
投票

这真的非常困难。
获得

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 进行测试。

© www.soinside.com 2019 - 2024. All rights reserved.