Skip to content

Instantly share code, notes, and snippets.

@meoso
Last active February 20, 2024 21:37
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save meoso/5d0b48172b503737eb0d222ca9f0bcf7 to your computer and use it in GitHub Desktop.
Save meoso/5d0b48172b503737eb0d222ca9f0bcf7 to your computer and use it in GitHub Desktop.
ffmpeg re-encoding scripts to reduce filesize and remain "visually" lossless

I've accumulated too many quadcopter (drone) footage files (.mp4, .MOV, etc).

I researched how to ffmpeg re-encode with "practical" losslessness (i.e. not lessless, but human eye acceptable).

These are my resultant scripts. The filenames say "reduce" but should actually be "re-encode".

In the case of GoPro, these scripts should retain the Gyro data.

I recommend footage filenames and folder-names to not include spaces. I rename all existing files in a folder with the command rename "s/[[:space:]]/_/g" * to make certain i have no spaces in filenames. You could rename all files in subfolders as well: e.g. find ~/SYNC/YT-Archive/ -type f -name "*[[:space:]]*" -exec rename "s/[[:space:]]/_/g" "{}" \;. The same goes for folders themselves if you use -type d. To rename both, exclude the -type specification altogether.

I have a base reduce-crf-only.sh that will re-encode the input file with a specified crf value. 18-23 is "visually" lossless. 18 if you want top quality; 23 if you want minimal filesize. i typically go 18 for my best work, and 20 or 21 for all others. I've re-watched all the output files and never noticed any reduction of quality or color. However, i have not recorded in "LOG" type formats for post-production color-grading, so this is intended for hobby-grade videos.

Further notes: This script uses N-2 cpu cores for re-encoding and uses the preset slow along with libx264. You could easily change these in the script. libx265(h265) are generally smaller, so one could decrease the crf value for additional quality. The scripts have hard-coded script source locations. These are expected to be located in ~/scripts/. A conversions.log will be stored for reference.

The output will be the filename plus the text "_crfXX .mp4" where XX is the 18-23 you specified. e.g. input.MOV --> input.MOV_crf21.mp4

reduce-crf-only.sh will either: 1) Delete the re-encoded file if it was not smaller than the source, or 2) "Trash" the source if it was larger than the re-encoded output. Note that the log will contain the hostname when trashing files. this helps if files are synced across multiple machine and one needs to know which trash-bin to view.

reduce-all-crf.sh will run reduce-crf-only.sh against all MOV, MP4, & AVI files. this uses BASH's built in case-insensitivity option. it will filter out any files with _crf in the filename.

reduce-wildcard-crf.sh will run reduce-crf-only.sh against a specified wildcard string. HOWEVER, you must specify such in quotes. e.g. reduce-wildcard-crf.sh "*.webm" 20.

In some rare cases, i may want to change the resolution of a file while re-encoding. to do so i use the reduce-resolution-crf.sh script in the form reduce-resolution-crf.sh INPUT.mp4 1080 18. It calculates the width-value to remain symmetric, so you only have to enter 720, 1080, or 1440, etc.

I've also included a script split-video.sh to cut (clip) files given the start-time and end-time. This personal need has also led to a more complex, all inclusive split-and-reduce-crf.sh which can both cut and re-encode footage, while also retaining GoPro gyro data.

Finally, I have discovered a pretty cool find command to iterate sub-folders and re-encode a specified wildcard (excluding already re-encoded _crf filenames): find ~/SYNC/YT-Archive/ -type f \( -name "201*.mp4" ! -iname "*crf*" \) -exec bash -c 'cd "$(dirname {})"; pwd ; ~/scripts/reduce-crf-only.sh "$(basename {})" 20' \;

Edit 2024: So i copied all my files here again, there have been multiple edits since this project was first uploaded. That said this is certainly spaghetti code and in many cases much duplication. At one time i duplicated the files to a h265 version, but have not necessarily kept them in sync with the original h264 versions. There are some -1080.sh files which downscale larger than 1080p files to 1080p.

#!/bin/bash
for f in ./*.ts; do
ffmpeg -y -i "${f}" -filter:v "crop=960:714:160:0, fps=30" "${f}.mp4"
done;
#!/bin/bash
if [ $# -lt 1 ] || ! [ $1 -ge 0 ] 2>/dev/null; then
echo "Re-encode ./*.{mov,mp4,avi} (except existing *_crf*)"
echo "Usage: ${0##*/} <crf> [trash|delete|keep] , where if nothing specified, will trash as default."
echo " Ex: ${0##*/} 18"
echo " Ex: ${0##*/} 21 notrash"
else
shopt -s nocaseglob nullglob #case insensitive & null empties
for infile in *.{MOV,mp4,avi,lrv,webm,mkv} ; do
#if [[ "${infile}" != *"_crf"* ]];then
if [ $# -eq 2 ] ; then
source ~/scripts/reduce-crf-only-1080.sh "${infile}" "${1}" $2 ;
else
source ~/scripts/reduce-crf-only-1080.sh "${infile}" "${1}" ;
fi ;
#fi
done ;
fi ;
#!/bin/bash
if [ $# -lt 1 ] || ! [ $1 -ge 0 ] 2>/dev/null; then
echo "Re-encode ./*.{mov,mp4,avi} (except existing *_crf*)"
echo "Usage: ${0##*/} <crf> [trash|delete|keep] , where if nothing specified, will trash as default."
echo " Ex: ${0##*/} 18"
echo " Ex: ${0##*/} 21 notrash"
else
shopt -s nocaseglob nullglob #case insensitive & null empties
for infile in *.{MOV,mp4,avi,lrv,webm} ; do
if [[ "${infile}" != *"_crf"* ]];then
if [ $# -eq 2 ] ; then
source ~/scripts/reduce-crf-only-265.sh "${infile}" "${1}" $2
else
source ~/scripts/reduce-crf-only-265.sh "${infile}" "${1}"
fi
fi
done
fi
#!/bin/bash
if [ $# -lt 1 ] || ! [ $1 -ge 0 ] 2>/dev/null; then
echo "Re-encode ./*.{mov,mp4,avi} (except existing *_crf*)"
echo "Usage: ${0##*/} <crf> [trash|delete|keep] , where if nothing specified, will trash as default."
echo " Ex: ${0##*/} 18"
echo " Ex: ${0##*/} 21 keep"
else
shopt -s nocaseglob nullglob #case insensitive & null empties
for infile in *.{MOV,mp4,avi,lrv,webm} ; do
if [[ "${infile}" != *"_crf"* ]];then
if [ $# -eq 2 ] ; then
source ~/scripts/reduce-crf-only.sh "${infile}" "${1}" $2
else
source ~/scripts/reduce-crf-only.sh "${infile}" "${1}"
fi
fi
done
fi
#!/bin/bash
if !( which trash );
then
echo "please install trash-cli (sudo apt install trash-cli)";
exit;
else
echo "trash command exists"
fi;
if [ $# -lt 2 ]
then
echo "Usage: ${0##*/} <filename> <crf> [trash|delete|keep] , where if nothing specified, will trash as default."
echo " Ex: ${0##*/} INPUT.mp4 18"
echo " Ex: ${0##*/} INPUT.mp4 18 delete"
echo " Ex: ${0##*/} INPUT.mp4 20 trash"
echo " Ex: ${0##*/} INPUT.mp4 22 keep"
else
hostname=$(hostname)
#threads=$(( $(nproc) - 2 ))
threads=$(echo $(nproc) |awk '{printf "%.0f",$0*0.80}')
logfile="conversions.log"
infile="${1}"
outfile="${1}_crf${2}.mp4"
echo "$(date +"%Y%m%d_%H%M%S") Processing: ${infile} with crf=${2}" | tee -a ${logfile}
gopro=false
gpregex1='^G.*\.MP4$' #### GOPR1153.MP4 / GP011153.MP4
resolution=$(ffprobe -v error -of flat=s=_ -select_streams v:0 -show_entries stream=height "${infile}" | awk -F= {'print $2'})
if [[ $infile =~ $gpregex1 ]] ; then gopro=true ; fi ;
if $gopro ; then
echo "gopro"
if [[ "$resolution" -gt 1080 ]]
then
echo "$resolution >1080"
nice -n 19 ffmpeg -y -hide_banner -loglevel panic -i "${infile}" -movflags use_metadata_tags -map 0:v -map 0:a -map 0:3 -tag:2 gpmd -threads ${threads} -stats -framerate 60000/1001 -c:v libx264 -c:a copy -crf "$2" -vf scale=1920:1080 -preset slow "${outfile}" -r 60000/1001 -async 1 -vsync 1
# -vf scale=1920:1080 # -1:1080
else
echo "<=1080 : SKIPPING" ; exit ; #do not delete/trash
## nice -n 19 ffmpeg -y -hide_banner -loglevel panic -i "${infile}" -movflags use_metadata_tags -map 0:v -map 0:a -map 0:3 -tag:2 gpmd -threads ${threads} -stats -framerate 60000/1001 -c:v libx264 -c:a copy -crf "$2" -preset slow "${outfile}" -r 60000/1001 -async 1 -vsync 1
fi
else
echo "non gopro"
if [[ "$resolution" -gt 1080 ]]
then
echo "$resolution >1080"
nice -n 19 ffmpeg -y -hide_banner -loglevel panic -i "${infile}" -threads ${threads} -stats -framerate 60000/1001 -c:v libx264 -c:a copy -crf "$2" -vf scale=1920:1080 -preset slow "${outfile}" -r 60000/1001 -async 1 -vsync 1
else
echo "<=1080 : SKIPPING" ; exit ; #do not delete/trash
## nice -n 19 ffmpeg -y -hide_banner -loglevel panic -i "${infile}" -threads ${threads} -stats -framerate 60000/1001 -c:v libx264 -c:a copy -crf "$2" -preset slow "${outfile}" -r 60000/1001 -async 1 -vsync 1
fi
fi
failed=($?)
sleep 1
if [ ${failed} -eq 0 ] ; then
echo "$(date +"%Y%m%d_%H%M%S") Re-Encoding succeeded." | tee -a ${logfile}
touch "${outfile}" -r "${infile}"
insize=$(stat -c%s "$infile")
outsize=$(stat -c%s "$outfile")
if [ ${insize}>${outsize} ] && [ -n ${outsize} ] ; then # bigger and non-zero
#keep, trash(default), or delete
if [ $# -lt 3 ] ; then
discard="trash"
else
discard=$3
fi
echo "$(date +"%Y%m%d_%H%M%S") Source was bigger (${insize}>${outsize}), (${hostname}) will ${discard} source: ${infile}" | tee -a ${logfile}
case "${discard}" in
"keep")
;;
"delete")
/bin/rm "${infile}"
;;
"trash")
trash "${infile}"
;;
*)
trash "${infile}"
;;
esac
else
echo "$(date +"%Y%m%d_%H%M%S") Re-encode was bigger (${insize}<${outsize}), trashing outfile: ${outfile}" | tee -a ${logfile}
trash "${outfile}"
fi
else
echo "$(date +"%Y%m%d_%H%M%S") Re-Encoding failed." | tee -a ${logfile}
fi
fi
beep -f 5000 -l 5 2>&1>/dev/null
#https://stackoverflow.com/questions/30782771/what-does-past-duration-x-xxx-too-large-mean
# -c:a copy
#after input -framerate 60000/1001
#after output -r 60000/1001 -async 1 -vsync 1
# #-async 1 -vsync 1 might work on it's own
#-preset slow
# #(best compression and longest to run)
## # options
## #-an =no audio
## ffmpeg -i inputvideo -c:v libx264 outputvideo
## ffmpeg -i inputvideo -c:v libx265 -x265-params lossless=1 outputvideo
## ffmpeg -i inputvideo -c:v libx265 -crf 18 outputvideo
## ffmpeg -i inputvideo -threads 6 -stats -framerate 60000/1001 -c:v libx265 -crf 18 -preset slow outputvideo
## nice -n 19 ffmpeg -i "${infile}" -threads 6 -stats -framerate 60000/1001 -c:v libx265 -crf "$2" -preset slow "${outfile}"
#!/bin/bash
if !( which trash );
then
echo "please install trash-cli (sudo apt install trash-cli)";
exit;
fi;
if [ $# -lt 2 ]
then
echo "Usage: ${0##*/} <filename> <crf> [trash|delete|keep] , where if nothing specified, will trash as default."
echo " Ex: ${0##*/} INPUT.mp4 21"
echo " Ex: ${0##*/} INPUT.mp4 21 delete"
echo " Ex: ${0##*/} INPUT.mp4 22 trash"
echo " Ex: ${0##*/} INPUT.mp4 25 keep"
else
hostname=$(hostname)
#threads=$(( $(nproc) - 2 ))
threads=$(echo $(nproc) |awk '{printf "%.0f",$0*0.80}')
logfile="conversions.log"
infile="${1}"
outfile="${1}_crf${2}_libXh265.mp4"
echo "$(date +"%Y%m%d_%H%M%S") Re-Encoding: ${infile}" | tee -a ${logfile}
gopro=false
gpregex1='^G.*\.MP4$' #### GOPR1153.MP4 / GP011153.MP4
if [[ $infile =~ $gpregex1 ]] ; then gopro=true ; fi ;
if $gopro ; then
echo "gopro"
nice -n 19 ffmpeg -y -hide_banner -loglevel panic -i "${infile}" -movflags use_metadata_tags -map 0:v -map 0:a -map 0:3 -tag:2 gpmd -threads ${threads} -stats -framerate 60000/1001 -c:v libx265 -crf "$2" -preset slow "${outfile}" -r 60000/1001 -async 1 -vsync 1
else
echo "non gopro"
nice -n 19 ffmpeg -y -hide_banner -loglevel panic -i "${infile}" -threads ${threads} -stats -framerate 60000/1001 -c:v libx265 -crf "$2" -preset slow "${outfile}" -r 60000/1001 -async 1 -vsync 1
fi
failed=($?)
sleep 1
if [ ${failed} -eq 0 ] ; then
echo "$(date +"%Y%m%d_%H%M%S") Re-Encoding succeeded." | tee -a ${logfile}
touch "${outfile}" -r "${infile}"
insize=$(stat -c%s "$infile")
outsize=$(stat -c%s "$outfile")
if ((${insize}>${outsize})) ; then
#keep, trash(default), or delete
if [ $# -lt 3 ] ; then
discard="trash"
else
discard=$3
fi
echo "$(date +"%Y%m%d_%H%M%S") Source was bigger (${insize}>${outsize}), (${hostname}) will ${discard} source: ${infile}" | tee -a ${logfile}
case "${discard}" in
"keep")
;;
"delete")
rm "${infile}"
;;
"trash")
trash "${infile}"
;;
*)
trash "${infile}"
;;
esac
else
echo "$(date +"%Y%m%d_%H%M%S") Re-encode was bigger (${insize}<${outsize}), trashing outfile: ${outfile}" | tee -a ${logfile}
trash "${outfile}"
fi
else
echo "$(date +"%Y%m%d_%H%M%S") Re-Encoding failed." | tee -a ${logfile}
fi
fi
beep -f 5000 -l 5 2>&1>/dev/null
#https://stackoverflow.com/questions/30782771/what-does-past-duration-x-xxx-too-large-mean
# -c:a copy
#after input -framerate 60000/1001
#after output -r 60000/1001 -async 1 -vsync 1
# #-async 1 -vsync 1 might work on it's own
#-preset slow
# #(best compression and longest to run)
## # options
## #-an =no audio
## ffmpeg -i inputvideo -c:v libx264 outputvideo
## ffmpeg -i inputvideo -c:v libx265 -x265-params lossless=1 outputvideo
## ffmpeg -i inputvideo -c:v libx265 -crf 18 outputvideo
## ffmpeg -i inputvideo -threads 6 -stats -framerate 60000/1001 -c:v libx265 -crf 18 -preset slow outputvideo
## nice -n 19 ffmpeg -i "${infile}" -threads 6 -stats -framerate 60000/1001 -c:v libx265 -crf "$2" -preset slow "${outfile}"
#!/bin/bash
if !( which trash );
then
echo "please install trash-cli (sudo apt install trash-cli)";
exit;
fi;
if [ $# -lt 2 ]
then
echo "Usage: ${0##*/} <filename> <crf> [trash|delete|keep] , where if nothing specified, will trash as default."
echo " Ex: ${0##*/} INPUT.mp4 18"
echo " Ex: ${0##*/} INPUT.mp4 18 delete"
echo " Ex: ${0##*/} INPUT.mp4 20 trash"
echo " Ex: ${0##*/} INPUT.mp4 22 keep"
else
hostname=$(hostname)
#threads=$(( $(nproc) - 2 ))
threads=$(echo $(nproc) |awk '{printf "%.0f",$0*0.80}')
logfile="conversions.log"
infile="${1}"
# outfile="${1}_crf${2}_nvenc265.mp4"
outfile="${1}_crf${2}_cuda_LH20.mp4"
echo "$(date +"%Y%m%d_%H%M%S") Re-Encoding: ${infile}" | tee -a ${logfile}
# nice -n 19 ffmpeg -y -hide_banner -loglevel panic -i "${infile}" -threads ${threads} -stats -framerate 60000/1001 -c:v hevc_nvenc -crf "$2" "${outfile}" -r 60000/1001 -async 1 -vsync 1
# nice -n 19 ffmpeg -hwaccel cuda -y -hide_banner -loglevel panic -i "${infile}" -threads ${threads} -stats -framerate 60000/1001 "${outfile}" -r 60000/1001 -async 1 -vsync 1
# nice -n 19 ffmpeg -y -hwaccel cuda -rc-lookahead 20 -hide_banner -loglevel panic -i "${infile}" -threads ${threads} -stats -framerate 60000/1001 "${outfile}" -r 60000/1001 -async 1 -vsync 1
nice -n 19 ffmpeg -y -hwaccel cuda -rc-lookahead 20 -hide_banner -loglevel panic -i "${infile}" -threads ${threads} -stats -framerate 60000/1001 -crf "$2" "${outfile}" -r 60000/1001 -async 1 -vsync 1
failed=($?)
sleep 1nvenc_hevc
if [ ${failed} -eq 0 ] ; then
echo "$(date +"%Y%m%d_%H%M%S") Re-Encoding succeeded." | tee -a ${logfile}
touch "${outfile}" -r "${infile}"
insize=$(stat -c%s "$infile")
outsize=$(stat -c%s "$outfile")
if ((${insize}>${outsize})) ; then
#keep, trash(default), or delete
if [ $# -lt 3 ] ; then
discard="trash"
else
discard=$3
fi
echo "$(date +"%Y%m%d_%H%M%S") Source was bigger (${insize}>${outsize}), (${hostname}) will ${discard} source: ${infile}" | tee -a ${logfile}
case "${discard}" in
"keep")
;;
"notrash")
;;
"delete")
rm "${infile}"
;;
"trash")
trash "${infile}"
;;
*)
trash "${infile}"
;;
esac
else
echo "$(date +"%Y%m%d_%H%M%S") Re-encode was bigger (${insize}<${outsize}), deleting outfile: ${outfile}" | tee -a ${logfile}
rm "${outfile}"
fi
else
echo "$(date +"%Y%m%d_%H%M%S") Re-Encoding failed." | tee -a ${logfile}
fi
fi
beep -f 5000 -l 5 2>&1>/dev/null
#https://stackoverflow.com/questions/30782771/what-does-past-duration-x-xxx-too-large-mean
# -c:a copy
#after input -framerate 60000/1001
#after output -r 60000/1001 -async 1 -vsync 1
# #-async 1 -vsync 1 might work on it's own
#-preset veryslow
# #(best compression and longest to run)
## # options
## #-an =no audio
## ffmpeg -i inputvideo -c:v libx264 outputvideo
## ffmpeg -i inputvideo -c:v libx265 -x265-params lossless=1 outputvideo
## ffmpeg -i inputvideo -c:v libx265 -crf 18 outputvideo
## ffmpeg -i inputvideo -threads 6 -stats -framerate 60000/1001 -c:v libx265 -crf 18 -preset veryslow outputvideo
## nice -n 19 ffmpeg -i "${infile}" -threads 6 -stats -framerate 60000/1001 -c:v libx265 -crf "$2" -preset veryslow "${outfile}"
#!/bin/bash
if !( which trash );
then
echo "please install trash-cli (sudo apt install trash-cli)";
exit;
else
echo "trash command exists"
fi;
if [ $# -lt 2 ]
then
echo "Usage: ${0##*/} <filename> <crf> [trash|delete|keep] , where if nothing specified, will trash as default."
echo " Ex: ${0##*/} INPUT.mp4 18"
echo " Ex: ${0##*/} INPUT.mp4 18 delete"
echo " Ex: ${0##*/} INPUT.mp4 20 trash"
echo " Ex: ${0##*/} INPUT.mp4 22 keep"
else
hostname=$(hostname)
#threads=$(( $(nproc) - 2 ))
threads=$(echo $(nproc) |awk '{printf "%.0f",$0*0.80}')
logfile="conversions.log"
infile="${1}"
outfile="${1}_crf${2}.mp4"
echo "$(date +"%Y%m%d_%H%M%S") Processing: ${infile} with crf=${2}" | tee -a ${logfile}
gopro=false
gpregex1='^G.*\.MP4$' #### GOPR1153.MP4 / GP011153.MP4
if [[ $infile =~ $gpregex1 ]] ; then gopro=true ; fi ;
if $gopro ; then
echo "gopro"
nice -n 19 ffmpeg -y -hide_banner -loglevel error -stats -i "${infile}" -movflags use_metadata_tags -map 0:v -map 0:a -map 0:3 -tag:2 gpmd -threads ${threads} -framerate 60000/1001 -c:v libx264 -c:a copy -crf "$2" -preset slow "${outfile}" -r 60000/1001 -async 1 -vsync 1
else
echo "non gopro"
nice -n 19 ffmpeg -y -hide_banner -loglevel error -stats -i "${infile}" -threads ${threads} -framerate 60000/1001 -c:v libx264 -crf "$2" -preset slow "${outfile}" -r 60000/1001 -async 1 -vsync 1
fi
failed=($?)
sleep 1
if [ ${failed} -eq 0 ] ; then
echo "$(date +"%Y%m%d_%H%M%S") Re-Encoding succeeded." | tee -a ${logfile}
touch "${outfile}" -r "${infile}"
insize=$(stat -c%s "$infile")
outsize=$(stat -c%s "$outfile")
if [ ${insize}>${outsize} ] && [ -n ${outsize} ] ; then # bigger and non-zero
#keep, trash(default), or delete
if [ $# -lt 3 ] ; then
discard="trash"
else
discard=$3
fi
echo "$(date +"%Y%m%d_%H%M%S") Source was bigger (${insize}>${outsize}), (${hostname}) will ${discard} source: ${infile}" | tee -a ${logfile}
case "${discard}" in
"keep")
;;
"notrash")
;;
"delete")
/bin/rm "${infile}"
;;
"trash")
trash "${infile}"
;;
*)
trash "${infile}"
;;
esac
else
echo "$(date +"%Y%m%d_%H%M%S") Re-encode was bigger (${insize}<${outsize}), trashing outfile: ${outfile}" | tee -a ${logfile}
trash "${outfile}"
fi
else
echo "$(date +"%Y%m%d_%H%M%S") Re-Encoding failed." | tee -a ${logfile}
fi
fi
beep -f 5000 -l 5 2>&1>/dev/null
#https://stackoverflow.com/questions/30782771/what-does-past-duration-x-xxx-too-large-mean
# -c:a copy
#after input -framerate 60000/1001
#after output -r 60000/1001 -async 1 -vsync 1
# #-async 1 -vsync 1 might work on it's own
#-preset slow
# #(best compression and longest to run)
## # options
## #-an =no audio
## ffmpeg -i inputvideo -c:v libx264 outputvideo
## ffmpeg -i inputvideo -c:v libx265 -x265-params lossless=1 outputvideo
## ffmpeg -i inputvideo -c:v libx265 -crf 18 outputvideo
## ffmpeg -i inputvideo -threads 6 -stats -framerate 60000/1001 -c:v libx265 -crf 18 -preset slow outputvideo
## nice -n 19 ffmpeg -i "${infile}" -threads 6 -stats -framerate 60000/1001 -c:v libx265 -crf "$2" -preset slow "${outfile}"
#!/bin/bash
if [ $# -lt 1 ] ; then
echo "Usage: ${0##*/} <CRF> [trash|delete|keep] , where if nothing specified, will trash as default."
echo " where CRF is applied to only to GOPRO*.MPG, and"
echo " CRF = 18 (larger size)"
echo " CRF = 20 (moderate size)"
echo " CRF = 22 (smaller size)"
else
source ~/scripts/reduce-wildcard-crf-265.sh "FatSharkDVR_*.AVI" 25 "${2}"
source ~/scripts/reduce-wildcard-crf-265.sh "PICT*.AVI" 25 "${2}"
source ~/scripts/reduce-wildcard-crf-265.sh "OnBoardDVR_*.AVI" 23 "${2}"
source ~/scripts/reduce-wildcard-crf-265.sh "video*.webm" 23 "${2}"
cd 100GOPRO/
source ~/scripts/reduce-wildcard-crf-265.sh "*GO*.LRV" 22 "${2}"
source ~/scripts/reduce-wildcard-crf-265.sh "*GP*.LRV" 22 "${2}"
source ~/scripts/reduce-wildcard-crf-265.sh "*GO*.MP4" "${1}" "${2}"
source ~/scripts/reduce-wildcard-crf-265.sh "*GP*.MP4" "${1}" "${2}"
cd -
source ~/scripts/reduce-wildcard-crf-265.sh "*.MP4" "${1}" "${2}"
source ~/scripts/reduce-wildcard-crf-265.sh "*.MP4" "${1}" "${2}"
cd 100DSCIM
source ~/scripts/reduce-wildcard-crf.sh "PICT*.AVI" 25 "${2}"
cd -
fi
#!/bin/bash
if [ $# -lt 1 ] ; then
echo "Usage: ${0##*/} <crf-value> [trash|delete|keep] , where if nothing specified, will trash as default."
echo " where <crf> is applied to only to GOPRO*.MPG, and"
echo " crf ex. 18 (HQ, larger size)"
echo " crf ex. 21 (MQ, moderate size)"
echo " crf ex. 24 (LQ, smaller size)"
else
source ~/scripts/reduce-wildcard-crf-cuda.sh "FatSharkDVR_*.AVI" 25 "${2}"
source ~/scripts/reduce-wildcard-crf-cuda.sh "PICT*.AVI" 25 "${2}"
source ~/scripts/reduce-wildcard-crf-cuda.sh "OnBoardDVR_*.AVI" 23 "${2}"
source ~/scripts/reduce-wildcard-crf-cuda.sh "video*.webm" 23 "${2}"
crf=${1}
cd 100GOPRO/
source ~/scripts/reduce-wildcard-crf-cuda.sh "*GO*.LRV" "${crf}" "${2}"
source ~/scripts/reduce-wildcard-crf-cuda.sh "*GP*.LRV" "${crf}" "${2}"
source ~/scripts/reduce-wildcard-crf-cuda.sh "*GO*.MP4" "${crf}" "${2}"
source ~/scripts/reduce-wildcard-crf-cuda.sh "*GP*.MP4" "${crf}" "${2}"
cd -
source ~/scripts/reduce-wildcard-crf-cuda.sh "*.MP4" "${crf}" "${2}"
source ~/scripts/reduce-wildcard-crf-cuda.sh "*.MP4" "${crf}" "${2}"
cd 100DSCIM
source ~/scripts/reduce-wildcard-crf.sh "PICT*.AVI" 25 "${2}"
cd -
fi
#!/bin/bash
if [ $# -lt 1 ] ; then
echo "Usage: ${0##*/} <CRF> [trash|delete|keep] , where if nothing specified, will trash as default."
echo " where CRF is applied to only to GOPRO*.MPG, and"
echo " CRF = 18 (larger size)"
echo " CRF = 20 (moderate size)"
echo " CRF = 22 (smaller size)"
else
source ~/scripts/reduce-wildcard-crf.sh "FatSharkDVR_*.AVI" 25 "${2}"
source ~/scripts/reduce-wildcard-crf.sh "PICT*.AVI" 25 "${2}"
source ~/scripts/reduce-wildcard-crf.sh "OnBoardDVR_*.AVI" 23 "${2}"
source ~/scripts/reduce-wildcard-crf.sh "video*.webm" 23 "${2}"
cd 100GOPRO/
source ~/scripts/reduce-wildcard-crf.sh "*GO*.LRV" 22 "${2}"
source ~/scripts/reduce-wildcard-crf.sh "*GP*.LRV" 22 "${2}"
source ~/scripts/reduce-wildcard-crf.sh "*GO*.MP4" "${1}" "${2}"
source ~/scripts/reduce-wildcard-crf.sh "*GP*.MP4" "${1}" "${2}"
cd -
source ~/scripts/reduce-wildcard-crf.sh "*.MP4" "${1}" "${2}"
source ~/scripts/reduce-wildcard-crf.sh "*.MP4" "${1}" "${2}"
cd 100DSCIM
source ~/scripts/reduce-wildcard-crf.sh "PICT*.AVI" 25 "${2}"
cd -
fi
#!/bin/bash
if [ $# -ne 3 ]
then
echo "Usage: ${0##*/} <filename> <resolution> <crf>"
echo " Ex: ${0##*/} INPUT.mp4 1080 18"
else
infile="${1}"
outfile="${1}_${2}p_crf${3}.mp4"
gopro=false
gpregex1='^G.*\.MP4$' #### GOPR1153.MP4 / GP011153.MP4
if [[ $infile =~ $gpregex1 ]] ; then gopro=true ; fi ;
if $gopro ; then
echo "gopro"
nice -n 19 ffmpeg -i "${infile}" -movflags use_metadata_tags -map 0:v -map 0:a -map 0:3 -tag:2 gpmd -threads 6 -framerate 60000/1001 -vf scale=-1:"$2" -c:v libx264 -crf "$3" -preset slow -c:a copy "${outfile}" -r 60000/1001 -async 1 -vsync 1
else
echo "non gopro"
nice -n 19 ffmpeg -i "${infile}" -threads 6 -framerate 60000/1001 -vf scale=-1:"$2" -c:v libx264 -crf "$3" -preset slow -c:a copy "${outfile}" -r 60000/1001 -async 1 -vsync 1
fi
touch "${outfile}" -r "${infile}"
fi
#after input -framerate 60000/1001
#after output -r 60000/1001 -async 1 -vsync 1
# #-async 1 -vsync 1 might work on it's own
#!/bin/bash
if [ $# -lt 2 ] || ! [ $2 -ge 0 ] 2>/dev/null; then
echo "Re-encodes specified wildcard named files (except existing *_crf*)"
echo "Usage: ${0##*/} \"<filenamewildcard>\" <crf> [trash|delete|keep] , where if nothing specified, will trash as default."
echo " Ex: ${0##*/} \"DVR*.avi\" 18"
echo " Ex: ${0##*/} \"*.webm\" 23 keep"
echo " ***** QUOTED wildcard REQUIRED *****"
else
shopt -s nocaseglob nullglob #case insensitive & null empties
for infile in ${1} ; do
if [[ "${infile}" != *"_crf"* ]];then
echo "-----> ${infile} <-----"
if [ $# -eq 3 ] ; then
source ~/scripts/reduce-crf-only-265.sh "${infile}" "${2}" $3
else
source ~/scripts/reduce-crf-only-265.sh "${infile}" "${2}"
fi
fi
done
fi
#!/bin/bash
if [ $# -lt 2 ] || ! [ $2 -ge 0 ] 2>/dev/null; then
echo "Re-encodes specified wildcard named files (except existing *_crf*)"
echo "Usage: ${0##*/} \"<filenamewildcard>\" <crf> [trash|delete|keep] , where if nothing specified, will trash as default."
echo " Ex: ${0##*/} \"DVR*.avi\" 18"
echo " Ex: ${0##*/} \"*.webm\" 23 keep"
echo " ***** QUOTED wildcard REQUIRED *****"
else
shopt -s nocaseglob nullglob #case insensitive & null empties
for infile in ${1} ; do
if [[ "${infile}" != *"_crf"* ]];then
echo "-----> ${infile} <-----"
if [ $# -eq 3 ] ; then
source ~/scripts/reduce-crf-only-cuda.sh "${infile}" "${2}" $3
else
source ~/scripts/reduce-crf-only-cuda.sh "${infile}" "${2}"
fi
fi
done
fi
#!/bin/bash
if [ $# -lt 2 ] || ! [ $2 -ge 0 ] 2>/dev/null; then
echo "Re-encodes specified wildcard named files (except existing *_crf*)"
echo "Usage: ${0##*/} \"<filenamewildcard>\" <crf> [trash|delete|keep] , where if nothing specified, will trash as default."
echo " Ex: ${0##*/} \"DVR*.avi\" 18"
echo " Ex: ${0##*/} \"*.webm\" 23 keep"
echo " ***** QUOTED wildcard REQUIRED *****"
else
shopt -s nocaseglob nullglob #case insensitive & null empties
for infile in ${1} ; do
if [[ "${infile}" != *"_crf"* ]];then
echo "-----> ${infile} <-----"
if [ $# -eq 3 ] ; then
source ~/scripts/reduce-crf-only.sh "${infile}" "${2}" $3
else
source ~/scripts/reduce-crf-only.sh "${infile}" "${2}"
fi
fi
done
fi
#!/bin/bash
if !( which trash );
then
echo "please install trash-cli (sudo apt install trash-cli)";
exit;
fi;
if [ $# -lt 4 ]
then
echo "Usage: ${0##*/} <filename> <fromtime_HH:mm:ss> <totime_HH:mm:ss> <crf> [trash|delete|keep] , where if nothing specified, will KEEP as default."
echo " Ex: ${0##*/} INPUT.mp4 0:20 9:40 18"
echo " Ex: ${0##*/} INPUT.mp4 0:20 9:40 18 delete"
echo " Ex: ${0##*/} INPUT.mp4 0:20 9:40 20 trash"
echo " Ex: ${0##*/} INPUT.mp4 0:20 9:40 22 keep"
else
function to_sec() { echo "$1" | awk -F':' '{if (NF == 2) {print $1 * 60 + $2} else {print $1 * 60 * 60 + $2 * 60 + $3}}';}
hostname=$(hostname)
#threads=$(( $(nproc) - 2 ))
threads=$(echo $(nproc) |awk '{printf "%.0f",$0*0.80}')
logfile="conversions.log"
infile="${1}"
outfile="${1}_h265_crf${4}_cut.mp4"
echo "$(date +"%Y%m%d_%H%M%S") Re-Encoding: ${infile}" | tee -a ${logfile}
gopro=false
gpregex1='^G.*\.MP4$' #### GOPR1153.MP4 / GP011153.MP4
if [[ $infile =~ $gpregex1 ]] ; then gopro=true ; fi ;
if $gopro ; then
echo "gopro"
nice -n 19 ffmpeg -y -hide_banner -loglevel panic -ss $(to_sec ${2}) -t $( expr $(to_sec ${3}) - $(to_sec ${2}) ) -i "${infile}" -movflags use_metadata_tags -map 0:v -map 0:a -map 0:3 -tag:2 gpmd -threads ${threads} -stats -framerate 60000/1001 -c:v libx265 -crf "${4}" -preset slow "${outfile}" -r 60000/1001 -async 1 -vsync 1
else
echo "non gopro"
nice -n 19 ffmpeg -y -hide_banner -loglevel panic -ss $(to_sec ${2}) -t $( expr $(to_sec ${3}) - $(to_sec ${2}) ) -i "${infile}" -threads ${threads} -stats -framerate 60000/1001 -c:v libx265 -crf "${4}" -preset slow "${outfile}" -r 60000/1001 -async 1 -vsync 1
fi
failed=($?)
sleep 1
if [ ${failed} -eq 0 ] ; then
echo "$(date +"%Y%m%d_%H%M%S") Re-Encoding succeeded." | tee -a ${logfile}
touch "${outfile}" -r "${infile}"
insize=$(stat -c%s "$infile")
outsize=$(stat -c%s "$outfile")
if ((${insize}>${outsize})) ; then
#keep, trash(default), or delete
discard="keep"
echo "$(date +"%Y%m%d_%H%M%S") Source was bigger (${insize}>${outsize}), (${hostname}) will ${discard} source: ${infile}" | tee -a ${logfile}
case "${discard}" in
"keep")
;;
"notrash")
;;
"delete")
rm "${infile}"
;;
"trash")
gio trash "${infile}"
;;
*)
;;
esac
else
echo "$(date +"%Y%m%d_%H%M%S") Re-encode was bigger (${insize}<${outsize}); No reduction; purging re-encoded outfile: ${outfile}" | tee -a ${logfile}
rm "${outfile}"
fi
else
echo "$(date +"%Y%m%d_%H%M%S") Re-Encoding failed." | tee -a ${logfile}
fi
fi
beep -f 5000 -l 5 2>&1>/dev/null
#!/bin/bash
if !( which trash );
then
echo "please install trash-cli (sudo apt install trash-cli)";
exit;
fi;
if [ $# -lt 4 ]
then
echo "Usage: ${0##*/} <filename> <fromtime_HH:mm:ss> <totime_HH:mm:ss> <crf> [trash|delete|keep] , where if nothing specified, will KEEP as default."
echo " Ex: ${0##*/} INPUT.mp4 0:20 9:40 18"
echo " Ex: ${0##*/} INPUT.mp4 0:20 9:40 18 delete"
echo " Ex: ${0##*/} INPUT.mp4 0:20 9:40 20 trash"
echo " Ex: ${0##*/} INPUT.mp4 0:20 9:40 22 keep"
else
function to_sec() { echo "$1" | awk -F':' '{if (NF == 2) {print $1 * 60 + $2} else {print $1 * 60 * 60 + $2 * 60 + $3}}';}
hostname=$(hostname)
#threads=$(( $(nproc) - 2 ))
threads=$(echo $(nproc) |awk '{printf "%.0f",$0*0.80}')
logfile="conversions.log"
infile="${1}"
outfile="${1}_crf${4}_cut.mp4"
echo "$(date +"%Y%m%d_%H%M%S") Re-Encoding: ${infile}" | tee -a ${logfile}
gopro=false
gpregex1='^G.*\.MP4$' #### GOPR1153.MP4 / GP011153.MP4
if [[ $infile =~ $gpregex1 ]] ; then gopro=true ; fi ;
if $gopro ; then
echo "gopro"
nice -n 19 ffmpeg -y -hide_banner -loglevel panic -ss $(to_sec ${2}) -t $( expr $(to_sec ${3}) - $(to_sec ${2}) ) -i "${infile}" -movflags use_metadata_tags -map 0:v -map 0:a -map 0:3 -tag:2 gpmd -threads ${threads} -stats -framerate 60000/1001 -c:v libx264 -crf "${4}" -preset slow "${outfile}" -r 60000/1001 -async 1 -vsync 1
else
echo "non gopro"
nice -n 19 ffmpeg -y -hide_banner -loglevel panic -ss $(to_sec ${2}) -t $( expr $(to_sec ${3}) - $(to_sec ${2}) ) -i "${infile}" -threads ${threads} -stats -framerate 60000/1001 -c:v libx264 -crf "${4}" -preset slow "${outfile}" -r 60000/1001 -async 1 -vsync 1
fi
failed=($?)
sleep 1
if [ ${failed} -eq 0 ] ; then
echo "$(date +"%Y%m%d_%H%M%S") Re-Encoding succeeded." | tee -a ${logfile}
touch "${outfile}" -r "${infile}"
insize=$(stat -c%s "$infile")
outsize=$(stat -c%s "$outfile")
if ((${insize}>${outsize})) ; then
#keep, trash(default), or delete
discard="keep"
echo "$(date +"%Y%m%d_%H%M%S") Source was bigger (${insize}>${outsize}), (${hostname}) will ${discard} source: ${infile}" | tee -a ${logfile}
case "${discard}" in
"keep")
;;
"notrash")
;;
"delete")
rm "${infile}"
;;
"trash")
trash "${infile}"
;;
*)
;;
esac
else
echo "$(date +"%Y%m%d_%H%M%S") Re-encode was bigger (${insize}<${outsize}); No reduction; purging re-encoded outfile: ${outfile}" | tee -a ${logfile}
rm "${outfile}"
fi
else
echo "$(date +"%Y%m%d_%H%M%S") Re-Encoding failed." | tee -a ${logfile}
fi
fi
beep -f 5000 -l 5 2>&1>/dev/null
#!/bin/bash
if [ $# -lt 3 ]
then
echo "Usage: ${0##*/} <filename> <fromtime_HH:mm:ss> <totime_HH:mm:ss> [suffix]"
echo " Ex: ${0##*/} INPUT.mp4 0:20 9:40 [001]"
else
function to_sec() { echo "$1" | awk -F':' '{if (NF == 2) {print $1 * 60 + $2} else {print $1 * 60 * 60 + $2 * 60 + $3}}';}
filename=$(basename -- "${1}")
extension="${1##*.}"
filename="${1%.*}"
infile="${1}"
if [ "$4" == "" ]
then
outfile="${filename}_cut.${extension}"
else
outfile="${filename}_cut_${4}.${extension}"
fi
if [ "${extension,,}" == "avi" ] ; then ## if AVI case-insensitive
nice -n 19 ffmpeg -ss $(to_sec ${2}) -i ${infile} -c copy -t $( expr $(to_sec ${3}) - $(to_sec ${2}) ) ${outfile}
else
#nice -n 19 MP4Box -splitx $(to_sec "${2}"):$(to_sec "${3}") "${infile}" -out "${outfile}"
nice -n 19 MP4Box -splitz $(to_sec "${2}"):$(to_sec "${3}") "${infile}" -out "${outfile}"
fi
touch "${outfile}" -r "${infile}"
fi
#AVI:
#ffmpeg -ss $(to_sec ${2}) -i ${infile} -c copy -t $( expr $(to_sec ${3}) - $(to_sec ${2}) ) ${outfile}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment