ffmpeg cheat sheet
This is a skeleton page at the moment.
audio
Convert mp4 audio to wav
$ ffmpeg -i input.mp4 -vn -acodec pcm_s16le -ar 44100 -ac 2 output.wav
Remove audio from video file:
$ ffmpeg -i video.3gp -vcodec copy -an newvideo.3gp
Converting formats
$ ffmpeg -i video.mkv -acodec copy -vcodec copy video.mp4
Turning a mp4 audio file with chapters into individual mp3 files per chapter.
$ ffmpeg -i 'unabridged.mp4' -f ffmetadata 2> /tmp/chapters
$ for i in $( grep 'Chapter #' /tmp/chapters | sed -e 's/.*#//g' -e 's/: .*//g' ); do
start=$( grep "Chapter #$i:" /tmp/chapters | sed -e 's/.*start //g' -e 's/, end.*//g' )
end=$( grep "Chapter #$i:" /tmp/chapters | sed -e 's/.*end //g' )
track=$( echo $i | sed -e 's/.*://g' -e 's/$/ + 1/' | bc )
ffmpeg -i 'unabridged.mp4' -q:a 0 -map a -ss "$start" -to "$end" -y "$track.mp3"
id3v2 -1 -a 'artist' -A 'album' -t "$track" -T "$track" "$track.mp3"
done
Rebuilding mp4 from m3u8
:
$ ffmpeg -i 'index_728_av-p.m3u8' -bsf:a aac_adtstoasc -vcodec copy -c copy -crf 50 file.mp4
video
$ ffmpeg -i source_file.mkv -acodec copy -vcodec copy dest_file.mp4
shrinking
To shrink the video frame size to 1/3 the original size, but simply copy audio:
$ ffmpeg -i source_file.mp4 -vf "scale=iw/3:ih/3" -c:a copy output.mp4
how i made a birthday movie?
The brief was this:
"Can you merge all these videos and pictures into one with some
music for a birthday message?"
Essentially this is a collage of random sized videos, orientations and pictures.
After trying a few programs I decided to settle with ffmpeg. There were videos of different rotations sizes and the same went for photos. The photos needed music and differing amounts of time on screen.
Since much of the video wasn't going to work on first go, I decided to
start as I meant to go on and would compile all this with a Makefile
.
This works well for several reasons, one of those is that the various
elements could be defined through variables at the top in a simple way.
Firstly I needed to specify the resolution, note that a lower proportion is commented:
RESX=1080
#RESX=270
RESY=1920
#RESY=480
RES=$(RESX)x$(RESY)
Firstly, all videos pieces need to be in a fixed sized and orientation, lets make this part of the ffmpeg invocation:
REFORMAT=-vf 'scale=$(RESX):$(RESY):force_original_aspect_ratio=decrease,pad=$(RESX):$(RESY):(ow-iw)/2:(oh-ih)/2,setsar=0'
The above will use the resolution values and set padding so that the videos retain their aspect ratios.
We need to use a common codec, and audio we do this with the following:
CODECS=-s $(RES) -r $(RATE) -acodec aac -vcodec libx264 -ar 48000 -strict experimental
Now we need to make the image collage, we can do that with the following:
ffmpeg -y -f concat -i image_list.txt $(REFORMAT) $(CODECS) slide_show_vid.mp4
If you notice in the above command we use concat
and image_list.txt
.
This tells ffmpeg to use a filter named concat
against the list. I've
reduced the list greatly, but this example shows two different images
and durations in the file:
file plain_picture.jpg
duration 2.5
file complex_text_picture.jpg
duration 10
This then produces a file named slide_show_vid.mp4, without any sound. Lets add some sound by merging slide_show_vid.mp4 and my_sound_file.mp3 with fade out at 45 seconds for five seconds!
ffmpeg -y -i slide_show_vid.mp4 -i my_sound_file.mp3 \
$(REFORMAT) $(CODECS) -af 'afade=out:st=45:d=5' \
-shortest slide_show.mp4
Lets convert the videos to a common video/audio format:
ffmpeg -y -i video_from_some_phone.mp4 $(CODECS) \
video_from_some_phone_encoded1.mp4
We do this for all the videos that were sent, and the compile a list of videos to make the final montage, named video_list.txt:
video_from_some_phone_encoded1.mp4
video_from_some_phone_encoded2.mp4
video_from_some_phone_encoded3.mp4
slide_show.mp4
Lets splice it together:
ffmpeg -y -f concat -i ./video_list.txt $(REFORMAT) $(CODECS) \
output.mp4
There we have it, a nicely built video montage. When someone sends another video or the photo set changes, it is a very trivial task to recreate the montage with minimum hassle.
ok, how do i play a stupid video for conference calls?
Simple. Surprisingly.
while /bin/true; do
ffmpeg -re -i 20200509_quiriano_Have_a_good_weekend_and_watch_for_fresh_cement_NA_mpw3fwxd9sx41.mp4 -map 0:v -f v4l2 /dev/video0
done
But that's only half of it. First you will need the v4l loopback device. We do that with the following:
sudo apt update
sudo apt install v4l2loopback-dkms v4l2loopback-utils
Then we need to ensure that module is loaded
sudo modprobe v4l2loopback
how to do simple stop motion?
Here's how I did a simple stop-motion video. I used gphoto2
to access
a nikon and store the photos in a
new directory. I placed this script in the parent directory:
#!/bin/sh
while IFS= read -r THROW; do
gphoto2 --camera 'Nikon DSC D610' --capture-image-and-download --filename '%Y%m%d-%H%M%S.%3n.%C'
done
Then I called it with ../camera.sh
. This stores the photos with a
date-time stamp, so that the following script pieces them together in
the right order, allowing one second for each image, I called this
movie.sh
and also placed that in the parent.
#!/bin/sh
RESX=1080
#RESX=270
RESY=1920
#RESY=480
RES="${RESX}x${RESY}"
REFORMAT="-vf scale=${RESX}:${RESY}:force_original_aspect_ratio=decrease,pad=${RESX}:${RESY}:(ow-iw)/2:(oh-ih)/2,setsar=0"
AFRESAMPLE="-af aresample=async=1000"
AFRESAMPLE=
RATE=30
CODECS="-s ${RES} -r ${RATE} -acodec aac -vcodec libx264 -ar 48000 -strict experimental"
/bin/rm output.mp4
for i in `/bin/ls *.jpg`; do
echo -ne "file ${i}\nduration 1\n"
done | tee image_list.txt
ffmpeg -y -f concat -i image_list.txt ${REFORMAT} ${AFRESAMPLE} ${CODECS} slide_show_vid.mp4
Storing both scripts in the parent directory makes it easy to build up a
series of scenes that can be joined together using the concat
method
above.
how do i do caption text on a movie?
Suppose you take a movie from a video streaming site such as YouTube and you want to put some captions on the movie, perhaps for a meme of some sort. This is a common task, and perhaps one that is worth pursuing as it has quite an interesting solution.
Setup a boiler place script, similar to this:
#!/bin/sh
FILE='input_video.mp4'
OUTPUT="output_video.mp4"
FONT="fontcolor=white:fontsize=40:shadowx=2:shadowy=2"
TEXTPOS="x=(w-text_w)/2:y=h-th-10"
ffmpeg -y -i "$FILE" \
-vf \
-acodec copy "$OUTPUT"
Watch the video clip that you want and make a note of all the timestamps that you want the text to appear in along with the text. Store these in the following format:
drawtext=enable='between(t,1,3)':text='sample text':${TEXTPOS}:${FONT},
Join all the drawtext
lines together with ,
separators, but not ,
terminator, so don't leave a trailing ,
on the final drawtext
command.
Your final script should look similar to this:
#!/bin/sh
FILE='input_video'
OUTPUT="output_video.mp4"
FONT="fontcolor=white:fontsize=40:shadowx=2:shadowy=2"
TEXTPOS="x=(w-text_w)/2:y=h-th-10"
ffmpeg -y -i "$FILE" \
-vf \
"drawtext=enable='between(t,1,3)':text='sample text':${TEXTPOS}:${FONT},
drawtext=enable='between(t,5,6)':text='ffmpeg is awesome':${TEXTPOS}:${FONT},
drawtext=enable='between(t,8,10)':text='best thing since sliced bread':${TEXTPOS}:${FONT}
" \
-acodec copy "$OUTPUT"
vlc outputVideo.mp4
how do i make caption text move around during the movie?
Things get a little more difficult to organise now. Mostly, how do you group text, time and position information together well?
One way to do this is we can define it something like this
TEXT1='sample1' TEXT2='sample2' TEXT3='sample3'
image stabilisation
ffmpeg -i input.mp4 -vf deshake stable_output.mp4