Skip to content

Instantly share code, notes, and snippets.

@xandout
Created March 21, 2022 21:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save xandout/2ca52b56e0b537a1c13985ad8ccf2da5 to your computer and use it in GitHub Desktop.
Save xandout/2ca52b56e0b537a1c13985ad8ccf2da5 to your computer and use it in GitHub Desktop.
FFmpeg Utility Scripts

FFmpeg helpers

Requirements: ffmpeg 4.3+ for crossfade. All commands tested on 4.4.1-3ubuntu1+20.04

I think that it is required that all videos(maybe audios) need to be the same resolution, framerate and all that. For my use case this is solved by pixabay

My specific goal here is to be able to use a site such as https://pixabay.com videos and mp3s to make long form videos with multiple songs

Obviously, you don't have to use pixabay. You probably don't have to use mp4s or mp3s, untested but ffmpeg should be able to figure it out, the commands do not use any codec specific flags.

The usage is "documented" above, the rest of this document is just to help the search engines

If you have a set of mp3 and some videos

1 video per audio

# Convert many mp3s to 1 long mp3
crossfade_many_audio song1.mp3  song2.mp3  song3.mp3
# creates song1-song2-song3.wav

# for each song and video, make a video the same length as the song
extend_loop_to_audio loopvid1.mp4 song1.mp3
# creates loopvid1-for-song1-140.643250s.mp4 where the 140.643250s is the duration of song1 and now the new looped video
extend_loop_to_audio loopvid2.mp4 song2.mp3
extend_loop_to_audio loopvid3.mp4 song3.mp3 

# Convert many mp4 to 1 long mp4
merge_videos loopvid1-for-song1-140.643250s.mp4 loopvid2-for-song2-138.579594s.mp4 loopvid3-for-song3-209.606531s.mp4 final.mp4
# creates final.mp4

# Add mp3 to mp4
merge_audio_video song1-song2-song3.wav final.mp4 
# creates song1-song2-song3-final.mp4

1 video for many songs

# Convert many mp3s to 1 long mp3
crossfade_many_audio song1.mp3  song2.mp3  song3.mp3
# creates song1-song2-song3.wav

# make a video the same length as the long song from above
extend_loop_to_audio loopvid1.mp4 song1-song2-song3.wav
# creates loopvid1-for-song1-140.643250s.mp4 where the 140.643250s is the duration of song1 and now the new looped video

# Add mp3 to mp4
merge_audio_video song1-song2-song3.wav loopvid1-for-song1-140.643250s.mp4 
# creates song1-song2-song3-loopvid1-for-song1-140.643250s.mp4

ffmpeg loop video for audio duration ffmpeg merge audio and video ffmpeg get duration ffmpeg crossfade audio -> SOURCE: https://romander.github.io/ffmpeg-script-generator/ ffmpeg concat video ffmpeg concat audio

extend_loop () {
video="${1}"
duration="${2}"
extended_loop_video="${video%.*}-${duration}s.mp4"
ffmpeg -stream_loop -1 -i "${video}" -c copy -t ${duration} "${extended_loop_video}"
}
extend_loop_to_audio () {
video="${1}"
duration=$(getdur "${2}")
extended_loop_video="${video%.*}-for-${2%.*}-${duration}s.mp4"
ffmpeg -stream_loop -1 -i "${video}" -c copy -t "${duration}" "${extended_loop_video}"
}
merge_audio_video () {
audio="${1}"
video="${2}"
duration=getdur "${audio}"
output="${audio%.*}-${video%.*}.mp4"
ffmpeg -i "${video}" -i "${audio}" -c:v copy -map 0:v:0 -map 1:a:0 "${output}"
}
getdur () {
filename="${1}"
ffprobe -i "${filename}" -show_entries format=duration -v quiet -of csv="p=0"
}
crossfade_audio () {
d1=getdur "${1}"
d2=getdur "${2}"
cf_out_file="${1%.*}-${2%.*}.wav"
ffmpeg -vsync 0 \
-i "${1}" \
-i "${2}" \
-filter_complex "[0]atrim=0:${d1}[0:a]; [1]atrim=0:${d2}[1:a]; [0:a][1:a]acrossfade=o=false:d=2:c1=tri:c2=tri[audio]" \
-b:v 10M -map "[audio]" -y "${cf_out_file}"
}
crossfade_many_audio () {
first="${1}"
second="${2}"
crossfade_audio $first $second
set -- "${@:3}" # All other args
for i
do
crossfade_audio "${cf_out_file}" "${i}"
done
}
merge_videos () {
if [ $# = 1 ]; then return; fi
merged_video_output="output.mp4"
echo "$#"
#if no arguments we take all mp4 in current directory as array
if [ $# = 0 ]; then inputfiles=($(ls -1v *.mp4)); fi
if [ $# = 2 ]; then inputfiles=($1 $2); fi
if [ $# -ge 3 ]; then # if >=3, use last as output filename
merged_video_output=${@:$#}
inputfiles=${@:1:$#-1}
fi
ffmpeg -y \
-f concat \
-safe 0 \
-i <(for f in $inputfiles; do echo "file '$PWD/$f'"; done) \
-c copy $merged_video_output
if test -f "$merged_video_output"; then echo "$merged_video_output created"; fi
}
# crossfade_many_audio song1.mp3 song2.mp3 song3.mp3
# extend_loop_to_audio loopvid1.mp4 song1.mp3
# extend_loop_to_audio loopvid2.mp4 song2.mp3
# extend_loop_to_audio loopvid3.mp4 song3.mp3
# merge_videos loopvid1-for-song1-140.643250s.mp4 loopvid2-for-song2-138.579594s.mp4 loopvid3-for-song3-209.606531s.mp4 final.mp4
# merge_audio_video song1-song2-song3.wav final.mp4
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment