Using ffmpeg to fade and cross fade audio and video
ffmpeg can be used to fade and cross fade audio and video in a single clip,
or between 2 or more clips which is handy if you dont wont to open a video editor
Combine audio and video files into a new file
Sometimes you need to extract the audio from a video file for example to fix the audio with audacity,
and then recombine the cleaned audio file with the original video track
Extract the audio from a video file as a wav
You can then open the wav file with audacity and clean up the audio with noise removal and adjust the audio levels etc
Audacity also has a macro function that lets you apply multiple audio filters and export the audio with a single click
After exporting the audio file as a wav we need to recombine the new audio with the original video track into a new video file
fade video out, and audio fade audio in and out
fade the audio of a clip in and out and fade the video out to black
note i dont fade the video in from black,
because then youtube will create black a thumbnail from the first video frame
Audio cross fade between 2 clips
Audio Video cross fade between 2 clips
ffmpeg can be used to fade and cross fade audio and video in a single clip,
or between 2 or more clips which is handy if you dont wont to open a video editor
Combine audio and video files into a new file
Sometimes you need to extract the audio from a video file for example to fix the audio with audacity,
and then recombine the cleaned audio file with the original video track
Extract the audio from a video file as a wav
Bash:
ffmpeg -i infile.mp4 -f wav outfile.wav
You can then open the wav file with audacity and clean up the audio with noise removal and adjust the audio levels etc
Audacity also has a macro function that lets you apply multiple audio filters and export the audio with a single click
After exporting the audio file as a wav we need to recombine the new audio with the original video track into a new video file
Bash:
#!/bin/sh
# combine video and audio clip
# script usage
script_usage=$(printf "%s\n%s\n" "$(basename "$0") -v video.(mp4|mov|mkv) -a audio.(wav|m4a)")
# video file destination
videofile="$HOME/Desktop/video-$(date +"%Y-%m-%d-%H-%M-%S").mp4"
# ffmpeg record function
record () {
printf "%s\n" "+ Getting video duration" && \
video_dur=$(ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 "$video" | cut -d\. -f1)
vid_offset=$(printf "%s\n" "${video_dur}-1" | bc -l)
printf "%s\n" "+ Combining video and audio" && \
ffmpeg \
-hide_banner \
-stats -v panic \
-i "$video" \
-i "$audio" \
-filter_complex \
" [1:a] afade=t=in:st=0:d=1,afade=t=out:st='$vid_offset':d=1[fa]; \
[0:v] fade=t=out:st='$vid_offset':d=1[fv]
" \
-c:a aac \
-c:v libx264 -preset fast \
-profile:v high \
-crf 18 -coder 1 \
-pix_fmt yuv420p \
-map "[fv]" -map "[fa]" \
-movflags +faststart \
-f mp4 \
"$videofile"
}
# check arguments
if [[ $# -eq 4 ]]; then
# group commands
{
[ "$1" = '-v' ] && \
[ -f "$2" ] && \
printf "%s\n" "$2" | grep -Eo '.(mov|mp4|mkv)$' 1>/dev/null && \
[ "$3" = '-a' ] && \
[ -f "$4" ] && \
printf "%s\n" "$4" | grep -Eo '.(wav|m4a)$' 1>/dev/null
} || { printf "%s\n" "$script_usage" && exit; }
# run record function to combine video and audio into a video file
# set variables
video="$2"
audio="$4"
record "$video" "$audio"
else
{ printf "%s\n" "$script_usage" && exit; }
fi
fade video out, and audio fade audio in and out
fade the audio of a clip in and out and fade the video out to black
note i dont fade the video in from black,
because then youtube will create black a thumbnail from the first video frame
Bash:
#!/bin/sh
# fade audio in and out, fade video out
# script usage
script_usage=$(printf "%s\n%s\n" "$(basename "$0") -i video.(mp4|mov|mkv)")
# video file destination
videofile="$HOME/Desktop/video-$(date +"%Y-%m-%d-%H-%M-%S").mp4"
# ffmpeg record function
record () {
printf "%s\n" "+ Getting video duration" && \
video_dur=$(ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 "$video" | cut -d\. -f1)
vid_offset=$(printf "%s\n" "${video_dur}-1" | bc -l)
printf "%s\n" "+ Converting video" && \
ffmpeg \
-hide_banner \
-stats -v panic \
-i "$video" \
-filter_complex \
" [0:a] afade=t=in:st=0:d=1,afade=t=out:st='$vid_offset':d=1[fa]; \
[0:v] fade=t=out:st='$vid_offset':d=1[fv]
" \
-c:a aac \
-c:v libx264 -preset fast \
-profile:v high \
-crf 18 -coder 1 \
-pix_fmt yuv420p \
-map "[fv]" -map "[fa]" \
-movflags +faststart \
-f mp4 \
"$videofile"
}
# check arguments
if [[ $# -eq 2 ]]; then
# group commands
{
[ "$1" = '-i' ] && \
[ -f "$2" ] && \
printf "%s\n" "$2" | grep -Eo '.(mov|mp4|mkv)$' 1>/dev/null && \
} || { printf "%s\n" "$script_usage" && exit; }
# run record function to combine video and audio into a video file
# set variables
video="$2"
record "$video"
else
{ printf "%s\n" "$script_usage" && exit; }
fi
Audio cross fade between 2 clips
Bash:
#!/bin/sh
# ffmpeg fadein fadeout clips
# script usage
script_usage=$(printf "%s\n%s\n" "$(basename "$0") -i clip-1.mp4 -i clip-2.mp4")
# video file destination
videofile="$HOME/Desktop/fade-a-$(date +"%Y-%m-%d-%H-%M-%S").mp4"
# check arguments passed to script
if [ $# -eq 4 ]; then
{
[ "$1" = '-i' ] && \
[ -f "$2" ] && \
[ "$3" = '-i' ] && \
[ -f "$4" ]
} || { printf "%s\n" "$script_usage" && exit; }
else
{ printf "%s\n" "$script_usage" && exit; }
fi
# variable names for files passed to script
clip1="$2"
clip2="$4"
# clip durations for fades
clip1_dur=$(ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 "$clip1" | cut -d\. -f1)
clip2_dur=$(ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 "$clip2" | cut -d\. -f1)
# clip1 use the bc command to remove 1 second from length of clip for cross fade
clip1_offset=$(printf "%s\n" "${clip1_dur}-1" | bc -l)
clip2_offset=$(printf "%s\n" "${clip2_dur}-1" | bc -l)
# ffmpeg command
ffmpeg \
-i "$clip1" -i "$clip2" \
-filter_complex \
" [0:v][1:v]concat=n=2[output];
[0:a] afade=t=in:st=0:d=1 [fadein]; \
[1:a] afade=t=out:st='$clip2_offset':d=1 [fadeout]; \
[fadein][fadeout] acrossfade=d=1:o=0 [audio]
" \
-map "[output]" -map "[audio]" "$videofile"
Audio Video cross fade between 2 clips
Bash:
#!/bin/sh
# ffmpeg cross fade clips
# script usage
script_usage=$(printf "%s\n%s\n" "$(basename "$0") -i clip-1.mp4 -i clip-2.mp4")
# video file destination
videofile="$HOME/Desktop/fade-va-$(date +"%Y-%m-%d-%H-%M-%S").mp4"
# check arguments passed to script
if [ $# -eq 4 ]; then
{
[ "$1" = '-i' ] && \
[ -f "$2" ] && \
[ "$3" = '-i' ] && \
[ -f "$4" ]
} || { printf "%s\n" "$script_usage" && exit; }
else
{ printf "%s\n" "$script_usage" && exit; }
fi
# variable names for files passed to script
clip1="$2"
clip2="$4"
# clip durations for fades
clip1_dur=$(ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 "$clip1" | cut -d\. -f1)
clip2_dur=$(ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 "$clip2" | cut -d\. -f1)
# clip1 use the bc command to remove 1 second from length of clip for cross fade
clip1_offset=$(printf "%s\n" "${clip1_dur}-1" | bc -l)
clip2_offset=$(printf "%s\n" "${clip2_dur}-1" | bc -l)
# ffmpeg command
ffmpeg \
-i "$clip1" -i "$clip2" \
-an -filter_complex \
" [0:v]trim=start=0:end='$clip1_offset',setpts=PTS-STARTPTS[firstclip];
[1:v]trim=start=1,setpts=PTS-STARTPTS[secondclip];
[0:v]trim=start='$clip1_offset':end='$clip1_dur',setpts=PTS-STARTPTS[fadeoutsrc];
[1:v]trim=start=0:end=1,setpts=PTS-STARTPTS[fadeinsrc];
[fadeinsrc]format=pix_fmts=yuva420p,
fade=t=in:st=0:d=1:alpha=1[fadein];
[fadeoutsrc]format=pix_fmts=yuva420p,
fade=t=out:st=0:d=1:alpha=1[fadeout];
[fadein]fifo[fadeinfifo];
[fadeout]fifo[fadeoutfifo];
[fadeoutfifo][fadeinfifo]overlay[crossfade];
[firstclip][crossfade][secondclip]concat=n=3[output];
[0:a] afade=t=in:st=0:d=1 [audiofadein]; \
[1:a] afade=t=out:st='$clip2_offset':d=1 [audiofadeout]; \
[audiofadein][audiofadeout] acrossfade=d=1 [audio]
" \
-map "[output]" -map "[audio]" "$videofile"