A collection of frequently used ffmpeg commands.
Video to Video
Convert .flv to .mp4 without re-encode (fast)
ffmpeg -i input.flv -c copy -copyts output.mp4
Convert unplayable .mp4 to Samsung supported .mp4
ffmpeg -n -nostdin -i input.mp4 -c:v h264_nvenc -preset slow -crf 23 -c:a aac -b:a 192k -vf format=yuv420p -movflags +faststart output.mp4
- Document: H.264 Video Encoding Guide
batch version
#!/bin/env bash
# My Video Converter
# Convert unplayable mp4 to playable mp4
# File with spaces. Ref: https://unix.stackexchange.com/a/9499
find . -maxdepth 1 -type f \( -iname "*.mp4" ! -iname "*.new.mp4" \) -print0 | while IFS= read -r -d '' file; do
ext="${file##*.}"
filename="${file%.*}"
new_file="${filename}.new.${ext}"
echo $new_file
ffmpeg -n -nostdin -i "$file" -c:v h264_nvenc -preset slow \
-crf 23 -c:a aac -b:a 192k -vf format=yuv420p \
-movflags +faststart "$new_file"
done
Video Concat
Concat w/o re-encode (fast)
- Create the
list.txt
file manually
$ cat list.txt
file A.mp4
file B.mp4
file C.mp4
$ ffmpeg -safe 0 -f concat -i list.txt -c copy output.mp3
- Create a file list using the
find
command (not compatible with PowerShell)
ffmpeg -safe 0 -f concat -i <(find . -type f -name '*.mp4' -printf "file '$PWD/%p'\n" | sort) -c copy output.mp4
Concat w/ re-encode (slow)
- remove
-c:v h264_nvenc
if there is no GPU driver
ffmpeg -i A.mp4 -i B.mp4 -filter_complex "concat=n=2:v=1:a=1" -c:v h264_nvenc output.mp4
if error when different SAR
[Parsed_concat_4 @ 0x55c55ae4d400] Input link in0:v0 parameters (size 1280x720, SAR 1:1) do not match the corresponding output link in0:v0 parameters (1280x720, SAR 8001:8000)
[Parsed_concat_4 @ 0x55c55ae4d400] Failed to configure output pad on Parsed_concat_4
Error reinitializing filters!
Correct the aspect of one of videos first by: ffmpeg -i wrong_A.mp4 -aspect 16:9 -c copy A.mp4
Reduce video file size
-crf N
: N: 0-51, where 0 is lossless, 23 is the default, and 51 is worst quality possible-b 800k
: limit the bitrate (optional)
ffmpeg -i input.flv -c:v h264_nvenc -crf 30 -c:a aac -b:a 192k -vf format=yuv420p -movflags +faststart output.mp4
Combine video and audio
ffmpeg -i video.mp4 -i audio.m4a -c copy -map 0:v:0 -map 1:a:0 output.mp4
Video to .gif
scale
andmax_colors
impact the output gif’s size
ffmpeg -y -i input.flv -filter_complex "fps=4,scale=1920:-1:flags=lanczos,split[s0][s1];[s0]palettegen=max_colors=256[p];[s1][p]paletteuse=dither=bayer" output.gif
Convert .jpeg to .webp
ffmpeg -i input.jpg -c:v libwebp output.webp
Convert .webp to .jpeg
ffmpeg -i input.webp output.jpg
Batch version with find
- keep original input file
find . -iname '*.webp' -exec bash -c 'ffmpeg -y -hide_banner -loglevel error -i "$1" -q:v 1 -qmin 1 -qmax 1 "${1%.*}.jpg"; printf "$1\n"' _ {} \;
- remove original input file
find . -iname '*.webp' -exec bash -c 'ffmpeg -y -hide_banner -loglevel error -i "$1" -q:v 1 -qmin 1 -qmax 1 "${1%.*}.jpg"; printf "$1\n" && rm "$1"' _ {} \;
PIL offers a significantly faster performance when processing images in batches
- tested in Windows PowerShell with python 3.12.5
python script
# -*- coding: utf8 -*-
# pip install Pillow tqdm
# python -X utf8 .\webp2jpg.py --dir ../
from pathlib import Path
from multiprocessing import Pool, cpu_count
import argparse
import os, sys
from tqdm import tqdm
from PIL import Image
def process(file):
ori_dir = str(str(file.parent.resolve()).encode("utf8"), encoding="utf8")
new_dir = ori_dir + "_jpg"
os.makedirs(new_dir, exist_ok=True)
ori_file = str(file.resolve())
new_file = ori_file.replace(file.suffix, ".jpg").replace(ori_dir, new_dir)
ori_file = str(bytes(ori_file, encoding="utf8"), encoding="utf8")
new_file = str(bytes(new_file, encoding="utf8"), encoding="utf8")
if not os.path.isfile(new_file):
im = Image.open(ori_file).convert("RGB")
im.save(new_file, "jpeg", subsampling=0, quality=95)
def main():
parser = argparse.ArgumentParser()
parser.add_argument("--dir", type=str, required=True)
parser.add_argument("--count", action="store_true")
args = parser.parse_args()
pwd = Path(rf"{args.dir}")
files = [Path(file) for file in pwd.glob("**/*.webp")]
if args.count:
print(f"total: {len(files)}")
sys.exit(0)
with Pool(cpu_count()) as p:
with tqdm(total=len(files), ascii=True, ncols=60) as pbar:
for _ in p.imap_unordered(process, files):
pbar.update()
print(f"total: {len(files)}")
if __name__ == "__main__":
main()