.dotfiles/zsh/ffmpeg

250 lines
9.4 KiB
Plaintext
Raw Permalink Normal View History

2022-02-10 20:11:56 +01:00
#--------------------------------
# filename: /zsh/ffmpeg
#--------------------------------
2024-07-05 10:58:37 +02:00
# "Repackge" video file into MP4 container
2023-03-06 21:09:36 +01:00
# Original script: https://yohanes.gultom.me/2016/05/21/bash-script-to-batch-convert-mkv-to-mp4-linux/
# Rewritten with ChatGPT 🙈
function ff-mp4 () {
2023-12-18 22:30:42 +01:00
local findpath="${1:-.}"
local file_list=()
local temp_file=$(mktemp)
# Find all video files and write them to a temporary file
find "$findpath" \( -iname '*.mkv' -o -iname '*.flv' -o -iname '*.mov' -o -iname '*.mp4' \) -print0 > "$temp_file"
# Read the file contents into the file_list array
while IFS= read -r -d $'\0' file; do
file_list+=("$file")
done < "$temp_file"
rm "$temp_file" # Delete the temporary file
# Process each file in the file_list array
local num_files=${#file_list[@]}
local counter=1
for file in "${file_list[@]}"; do
local dir=$(dirname "$file")
local file_name=$(basename "$file")
local name="${file_name%.*}"
local ext="${file_name##*.}"
2023-03-06 21:09:36 +01:00
2023-03-07 17:56:00 +01:00
echo "Processing file [$counter/$num_files]: $file_name"
counter=$((counter+1))
2023-02-11 01:30:25 +01:00
2023-12-18 22:30:42 +01:00
# Re-container the video file to mp4 using ffmpeg
ffmpeg -hide_banner -loglevel error -i "$file" -map 0 -c copy -pix_fmt yuv420p -movflags faststart "$dir/temp_$name.mp4"
2023-02-11 01:30:25 +01:00
2023-12-18 22:30:42 +01:00
# Rename the original file and move the new mp4 file to its place
mv -n "$file" "$dir/_$file_name"
2024-02-08 13:26:48 +01:00
mv -n "$dir/temp_$name.mp4" "$dir/$file_name.mp4"
done
2022-02-10 20:11:56 +01:00
}
2024-07-05 10:58:37 +02:00
#
# Video scaling/reencoding
#
# Recompress input MP4 to 720p x264 MP4 (copy audio)
ff-x264-scale720p() {
2023-12-18 22:30:42 +01:00
for input in *.mp4; do
if [[ -f "$input" ]]; then
tempfile="temp_${input%.mp4}"
2024-07-05 11:38:18 +02:00
ffmpeg -hide_banner -loglevel info -i "$input" -c:v libx264 -crf 18 -vf scale=1280:-2 -preset slow -tune film -x264-params "ref=5:bframes=5:crf-max=25:qpmax=34:level=3.1:b-adapt=2:direct=auto:deblock=-1,-1:analyse=all:me=umh:subme=9:trellis=2:psy-rd=1,0.15:vbv-bufsize=17500:vbv-maxrate=17500:rc-lookahead=60" -c:a copy -c:s copy -movflags faststart "$tempfile.mp4"
2023-12-18 22:30:42 +01:00
if [[ $? -eq 0 ]]; then
mv "$input" "_$input"
mv "$tempfile.mp4" "$input"
echo "Conversion successful: $input"
else
echo "Conversion failed for: $input"
fi
fi
2024-02-08 13:27:13 +01:00
done
}
2024-07-05 10:58:37 +02:00
# Recompress input MP4 to 540p x264 MP4 (copy audio)
ff-x264-scale540p() {
2024-02-08 13:27:13 +01:00
for input in *.mp4; do
if [[ -f "$input" ]]; then
tempfile="temp_${input%.mp4}"
2024-07-05 11:38:18 +02:00
ffmpeg -hide_banner -loglevel info -i "$input" -c:v libx264 -crf 18 -vf scale=960:-2 -preset slow -tune film -x264-params "ref=5:bframes=5:crf-max=25:qpmax=34:level=3.1:b-adapt=2:direct=auto:deblock=-1,-1:analyse=all:me=umh:subme=9:trellis=2:psy-rd=1,0.15:vbv-bufsize=17500:vbv-maxrate=17500:rc-lookahead=60" -c:a copy -c:s copy -movflags faststart "$tempfile.mp4"
2024-02-08 13:27:13 +01:00
if [[ $? -eq 0 ]]; then
mv "$input" "_$input"
mv "$tempfile.mp4" "$input"
echo "Conversion successful: $input"
else
echo "Conversion failed for: $input"
fi
fi
done
2023-10-20 16:37:29 +02:00
}
2024-08-25 02:07:19 +02:00
# Recompress input MP4 to 720p x265 MP4 (copy audio)
ff-x265-scale720p() {
local crf=${1-20}
for input in *.mp4; do
if [[ -f "$input" ]]; then
tempfile="temp_${input%.mp4}"
ffmpeg -hide_banner -loglevel info -i "$input" -map 0 -c:v libx265 -x265-params strong-intra-smoothing=0:rect=0:aq-mode=1:rd=4:psy-rd=0.75:psy-rdoq=4.0:rdoq-level=1:rskip=2 -vf scale=1280:-2 -crf "$crf" -tag:v hvc1 -c:s copy -c:a copy -movflags faststart "$tempfile.mp4"
if [[ $? -eq 0 ]]; then
mv "$input" "_$input"
mv "$tempfile.mp4" "$input"
echo "Conversion successful: $input"
else
echo "Conversion failed for: $input"
fi
fi
done
pushover "FFmpeg done ✔"
}
2024-08-25 02:05:13 +02:00
# Recompress input MP4 to 720p x265 MP4 (copy audio)
ff-x265-scale720p() {
local crf=${1-20}
for input in *.mp4; do
if [[ -f "$input" ]]; then
tempfile="temp_${input%.mp4}"
ffmpeg -hide_banner -loglevel info -i "$input" -map 0 -c:v libx265 -x265-params strong-intra-smoothing=0:rect=0:aq-mode=1:rd=4:psy-rd=0.75:psy-rdoq=4.0:rdoq-level=1:rskip=2 -vf scale=1280:-2 -crf "$crf" -tag:v hvc1 -c:s copy -c:a copy -movflags faststart "$tempfile.mp4"
if [[ $? -eq 0 ]]; then
mv "$input" "_$input"
mv "$tempfile.mp4" "$input"
echo "Conversion successful: $input"
else
echo "Conversion failed for: $input"
fi
fi
done
pushover "FFmpeg done ✔"
}
2024-07-05 10:58:37 +02:00
# Recompress input MP4 to 720p AV1 MP4 (copy audio)
ff-av1-scale720p() {
2024-08-10 00:28:47 +02:00
local crf=${1-23}
2024-07-05 10:58:37 +02:00
for input in *.mp4; do
if [[ -f "$input" ]]; then
tempfile="temp_${input%.mp4}"
2024-08-10 00:28:47 +02:00
ffmpeg -hide_banner -loglevel info -i "$input" -vf format=yuv420p10le,scale=1280:-2 -c:v libsvtav1 -preset 6 -crf "$crf" -g 30 -svtav1-params tune=0 -c:a copy -c:s copy "$tempfile.mp4"
2024-07-05 10:58:37 +02:00
if [[ $? -eq 0 ]]; then
mv "$input" "_$input"
mv "$tempfile.mp4" "$input"
echo "Conversion successful: $input"
else
echo "Conversion failed for: $input"
fi
fi
done
pushover "FFmpeg done ✔"
2023-02-10 19:25:48 +01:00
}
2024-08-06 08:31:24 +02:00
# Recompress input MP4 to 540p AV1 MP4 (copy audio)
ff-av1-scale540p() {
2024-08-10 00:28:47 +02:00
local crf=${1-23}
2024-08-05 11:57:19 +02:00
for input in *.mp4; do
if [[ -f "$input" ]]; then
tempfile="temp_${input%.mp4}"
2024-08-10 00:28:47 +02:00
ffmpeg -hide_banner -loglevel info -i "$input" -vf format=yuv420p10le,scale=960:-2 -c:v libsvtav1 -preset 6 -crf "$crf" -g 30 -svtav1-params tune=0 -c:a copy -c:s copy "$tempfile.mp4"
2024-08-05 11:57:19 +02:00
if [[ $? -eq 0 ]]; then
mv "$input" "_$input"
mv "$tempfile.mp4" "$input"
echo "Conversion successful: $input"
else
echo "Conversion failed for: $input"
fi
fi
done
pushover "FFmpeg done ✔"
2024-08-05 11:57:19 +02:00
}
2024-07-05 10:58:37 +02:00
#
# Video helper
#
2023-02-10 19:25:48 +01:00
2024-07-05 10:58:37 +02:00
# ffmpeg function to find borders for cropping
function ff-crop() {
2024-07-06 17:18:47 +02:00
ffmpeg -hide_banner -loglevel info -i "$1" -vf cropdetect,metadata=mode=print -f null - 2>&1 | awk '/crop=/ { print $NF }'
2023-02-12 19:54:49 +01:00
}
2022-02-10 20:11:56 +01:00
# ffmpeg fix Non-monotonous DTS
function ff-dts() {
2024-02-08 13:26:27 +01:00
ffmpeg -hide_banner -loglevel error -fflags +igndts -i "$1" -c copy -pix_fmt yuv420p -movflags faststart "temp_$1"
2023-02-11 01:30:25 +01:00
mv "$1" "_$1" && mv "temp_$1" "$1"
2022-02-10 20:11:56 +01:00
}
2024-07-05 10:58:37 +02:00
#
# Convert audio
#
# ffmpeg audio-to-ac3
function ff-audio-to-ac3() {
ffmpeg -hide_banner -loglevel error -i "$1" -movflags faststart -map 0 -c:v copy -c:s copy -c:a ac3 -b:a 448k "temp_$1"
2024-08-05 11:57:19 +02:00
mv "$1" "_$1" && mv "temp_$1" "$1"
2024-07-05 10:58:37 +02:00
}
2022-02-10 20:11:56 +01:00
## ffmpeg wma-to-m4a
2024-07-05 10:58:37 +02:00
function ff-wma-to-m4a() {
2022-02-10 20:11:56 +01:00
findpath=$1
2022-11-13 19:19:00 +01:00
: "${findpath:="."}"
find "$findpath" -name '*.wma' | while read -r f ; do
2023-02-11 01:30:25 +01:00
dir=$(dirname "$f");
file=$(basename "$f");
name="${file%.*}";
ext="${file##*.}";
ffmpeg -hide_banner -loglevel error -i "$f" -map 0 -vn -b:a 192k -c:a libfdk_aac "$dir/temp_$name.mp4";
mv "$f" "$dir/_$file";
mv "$dir/temp_$name.mp4" "$dir/$file";
2022-02-10 20:11:56 +01:00
done
}
2024-07-05 10:58:37 +02:00
#
# Cut parts of the file
#
## ffmpeg cut X seconds from start
function ff-cutstart {
local time="${2:-00:00:08.590}"
mv "$1" "_$1"
2024-02-08 13:26:27 +01:00
ffmpeg -hide_banner -loglevel error -ss $time -i "_$1" -map 0 -c copy -movflags faststart "$1"
}
## ffmpeg cut X seconds from start
function ff-cutend {
local time="${2:-24.250}"
duration=`ffprobe -v error -show_entries format=duration -of csv=p=0 "$1"`
duration=`bc --expression=$duration-$time`
mv "$1" "_$1"
2024-02-08 13:26:27 +01:00
ffmpeg -hide_banner -loglevel error -ss 00:00:00 -to $duration -i "_$1" -map 0 -c copy -movflags faststart "$1"
2024-02-05 12:47:55 +01:00
}
2024-07-05 10:58:37 +02:00
#
# Correct/fix aspect ratio
#
# ffmpeg fix 16:9 AR
2024-08-05 11:57:19 +02:00
function ff-ar16-9() {
2024-07-05 10:58:37 +02:00
ffmpeg -hide_banner -loglevel error -i "$1" -c copy -map 0 -bsf:v "h264_metadata=sample_aspect_ratio=4/3" -aspect 16:9 -pix_fmt yuv420p -movflags faststart "temp_$1"
mv "$1" "_$1" && mv "temp_$1" "$1"
}
# ffmpeg fix 5:4 AR
function ff-ar5-4() {
ffmpeg -hide_banner -loglevel error -i "$1" -c copy -map 0 -bsf:v "h264_metadata=sample_aspect_ratio=1/1" -aspect 5:4 -pix_fmt yuv420p -movflags faststart "temp_$1"
mv "$1" "_$1" && mv "temp_$1" "$1"
}
# ffmpeg fix 4:3 AR
function ff-ar4-3() {
ffmpeg -hide_banner -loglevel error -i "$1" -c copy -map 0 -bsf:v "h264_metadata=sample_aspect_ratio=1/1" -aspect 4:3 -pix_fmt yuv420p -movflags faststart "temp_$1"
mv "$1" "_$1" && mv "temp_$1" "$1"
}
2024-08-05 11:57:19 +02:00
# ffmpeg fix AR ($1 = file, $2 1/1, $4:3)
2024-07-05 10:58:37 +02:00
function ff-ar-custom() {
if [ $# -lt 3 ]; then
>&2 echo "Not enough arguments (\$1 = 'file', \$2 '1/1', \$3 '4:3')"
return 0
else
ffmpeg -hide_banner -loglevel error -i "$1" -c copy -map 0 -bsf:v "h264_metadata=sample_aspect_ratio=$2" -aspect $3 -pix_fmt yuv420p -movflags faststart "_$1"
fi
2024-07-05 21:12:39 +02:00
}