ffmpeg Recipes
I use the almighty ffmpeg a lot to convert, edit, and tag my personal media. This is a living document of my most used command line recipes.
Setting Metadata
ffmpeg -i in.mkv -map 0 \
-metadata title="…" -metadata:s:v:0 title="…" \
-metadata:s:a:0 title="English" -metadata:s:a:0 language="en" \
-metadata:s:a:1 title="Deutsch" -metadata:s:a:1 language="de" \
-metadata:s:s:0 title="Deutsch" -metadata:s:s:0 language="de" \
-c copy out.mkv
- Set input file with
-i - Select all streams of input index 0 (the first input) with
-map 0- With streams I refer to video, audio, and subtitles. I haven’t had to deal with data and attachment streams too often.
- Set metadata of video/audio/subtitle stream of index
xwith-metadata:s:[vas]:x <key>="<value>" - Set all codec operations to
copywith-c copy(which is a lot faster than re-encoding) - Write to
out.mkv
Trim/Cut/Clip Video With Timestamps
ffmpeg -i in.mkv \
-ss 00:01:00 -to 00:02:00 \
out.mkv
- Set start time with
-ss- Split seconds can be set with
HH:MM:SS.mmm
- Split seconds can be set with
- Set end time with
-toor duration with-t
Note that using -c copy would again be faster, but then clipping relies on keyframes at the targeted start and end time and might be less accurate. Re-encode for higher accuracy.
Extract Frames as Images
It sometimes happens that galleries or storyboard sketches in video format only play for less than a second because each still image is just one frame. I then prefer extracting these frames as images and store them as a PDF.
Naïve Approach
ffmpeg -i in.mp4 out%04d.png
- Stores each frame as one
pngimage %04dis a format specifier that0-pads an integer to the length of 4
Better Approach
If each still image occupies more than one frame, this approach is superior because it only selects frames that are different from their predecessor.
ffmpeg -i in.mp4 \
-filter_complex "select=gt(scene\,0.01)" \
-fps_mode passthrough \
out%04d.png
- Filter frames by checking whether they have a scene change detection score of least 1 %
- I am setting the score that low because I only expect still images and the smallest change should indicate a new one.
- Ensure 1:1 correspondence between input und output frames with
-fps_mode passthrough
Via Chapters
If still images are marked by chapters, capturing the first frame of their respective start times can be a good approach.
ffprobe -i in.mkv -v error -print_format json -show_chapters | \
jq ".chapters[] | .start_time" | \
xargs -I{} ffmpeg -i in.mkv -v error -ss {} -frames 1 out-{}.png
-v errorinstructsffmpegandffprobeto only report errors for a less verbose outputjqis a JSON parser used to extract the start time of each chapter- These start times are piped into
xargswhich callsffmpegto extract the first frame as an image
Modifying Chapter Data
This is a two-stage process: I extract the metadata into a txt file, change the chapter’s titles, and mux the altered metadata into a new file.
ffmpeg -i in.mkv -f ffmetadata metadata.txt
vim metadata.txt
ffmpeg -i in.mkv -i metadata.txt \
-map_metadata 1 -map_chapters 1 \
-c copy out.mkv