diff --git a/metric_encoder.sh b/metric_encoder.sh new file mode 100644 index 0000000..0fc19ce --- /dev/null +++ b/metric_encoder.sh @@ -0,0 +1,118 @@ +#!/usr/bin/env bash +# +# MIT License +# +# Copyright (c) 2024 Mitsudori +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# +# Use: ssim_optimizer.sh input.ext output.ext (to compare) bitrate_in_kbps (or none). +# The extension can be what ffmpeg was compiled with. +# The script will not work with downscale\upscale encode unless under comparative function (not implemented yet). +# Does not work with interlaced source yet. +# Depends: Bash, FFmpeg, FFprobe, Gnu AWK, Grep, bc, sed. +# Matroska may broke the results, because sometimes when FFmpeg encodes Matroska, inserts a frame plus. +# If no video correlation as param, the script will made a encode themselve. +# The execution under cygwin in Windows should not work for RAMdisk mounting, as you should do it manually. +# Not tested on Mac, BSD. +constantssim=0.979889 +constantvmaf=96 +qcmp=0.50 +crf=16 +ext=`echo "$1" | cut -d'.' -f2` +safeparams="-me_method hex -refs 8 -bf 8 -b_strategy 2 -trellis 2 -aq-mode 2 -x264-params partitions=all" +killparms="-me_method umh -me_range 32 -refs 16 -bf 16 -b_strategy 1 -trellis 2 -aq-mode 2 -x264-params partitions=all:subme=9:no-dct-decimate=1:no-fast-pskip=1" + +if [ "$ext" = "yuv" ]; then + read -p "Enter size in widthxheight for YUV input." ryuv; + yuvin="-s $ryuv -r 25 -pix_fmt yuv420p"; +fi + +if [ -z "$1" ]; then + printf "Arguments: ssim_optimizer.sh 'reference.mp4' 'correlation.mp4' 'initial_bitrate_int'\n\t\t\t\tAt least the reference needs to be insert." ; exit +fi + +if [ -z "$3" ] && [ ! -n "$2" ]; then + read -p "Proceed to determine qcomp and qpfile (more precise encode)? (y/N)" q1; + if [[ $q1 == [yY] || $q1 == [yY][eE][sS] ]]; then + qcmp=`ffmpeg -i $1 -c:v libx264 -loglevel debug -qp 0 -g 1 -preset superfast -f null -y /dev/null 2>&1 | grep -oP "(?<=size=)\d+(?= b)" | gawk '!_[$0]++{z[++c]=$0}{l[NR]=$0}END{asort(z);for (a in l) for (b in z) if (l[a] == z[b]) {print b; break}}' | gawk '{q=$0;z[NR]=q;sum+=q}END{m=sum/NR;for (a in z) stdp+=(z[a]-m)**2;std=sqrt(stdp/NR); print std/m}'`; + if [ -n "$yuvin" ]; then + echo "QPfile function does not apply to yuv input."; else + ffprobe $1 -show_frames -print_format csv -show_entries stream=pict_type | gawk -F"," '$19=="I"{print $20 " " $19 " -1" }' > qpfile_bruto.txt; + telos=`gawk 'END{ print NR; }' qpfile_bruto.txt;` + fi + if [ $qcmp -gt 0.58 ]; then crf=$((crf-4)); fi + fi +fi + +if [ -n "$1" ] && [ -n "$2" ] ; then + probe="-select_streams v -show_entries stream=width -of default=noprint_wrappers=1"; + a=`ffprobe -v error $probe "$2" | grep -Eo '[0-9]{1,4}' -`; b=`ffprobe -v error $probe "$1" | grep -Eo '[0-9]{1,4}' -` + if [ "$a" != "$b" ]; then + c=`ffprobe -v error $probe "$1" | grep -Eo '[0-9]{1,4}' -` + parsedssim=`ffmpeg -hide_banner -i "$2" -i "$1" -filter_complex "[0:v]scale=$b:$c[v0r];[1:v][v0r] ssim" -f null - 2>&1 | grep -oP "(?<=All:).*(?= )"` + if (( $(echo "$parsedssim < $constantssim" |bc -l) )); then + printf "\nYour correlation video is not optimized, with a round SSIM value of $parsedssim\n"; + else + printf "\nYour correlation video is optimized, with a round SSIM value of $parsedssim\n"; + fi + else + parsedssim=`ffmpeg -hide_banner -i $1 -i $2 -lavfi ssim -f null - 2>&1 | grep -oP "(?<=All:).*(?= )"`; + if (( $(echo "$parsedssim < $constantssim" |bc -l) )) ; then + printf "\nYour correlation video is not SSIM optimized, with a round SSIM value of $parsedssim"; + else + printf "\nYour video is optimized, with a round SSIM value of $parsedssim"; + fi + parsedvmaf=`ffmpeg -hide_banner -i $1 -i $2 -lavfi libvmaf -f null - 2>&1 | grep -oP "(?<=score: ).*"`; + if (( $(echo "$parsedvmaf < $constantvmaf" |bc -l) )) ; then + printf "\nYour correlation video is not VMAF optimized, with a round VMAF value of $parsedvmaf"; + else + printf "\nYour video is VMAF optimized, with a round VMAF value of $parsedvmaf"; + fi + exit + fi +fi + +encode_function() +{ + read -p "Procede to encode?" q2; + if [[ $q2 == [yY] || $q2 == [yY][eE][sS] ]]; then + fps=`ffprobe -hide_banner $1 2>&1 | grep -oP "(?<= )\d+(\.\d+)*(?= fps)" | gawk '{printf("%d\n",$1 + 0.5)}'` + gop=$((10*$fps)); + scc=$((3*$fps)); + # for ((i=1;i<=telos;i++)); do + # flag=$((flag+1)); + # aframe`gawk -v var="$flag" 'NR==var{ print $1; }' qpfile_bruto.txt` + # flag=$((flag+1)); + # zframe`gawk -v var="$flag" 'NR==var{ print $1; }' qpfile_bruto.txt` + # done; + # gawk 'NR==1{ print $1; }' qpfile_bruto.txt + if [ $qcmp -gt 0.58 ]; then + brate=`ffmpeg -i $1 -an -c:v libx264 -fastfirstpass 0 -pass 1 -qcomp $qcmp -g $gop -sc_threshold $scc -rc-lookahead $(($scc+$fps)) -crf $crf $killparms -f null /dev/null | grep -oP "(?<=kb/s:).*"` + ffmpeg -i $1 -an -c:v libx264 -pass 2 -qcomp $qcmp -g $gop -sc_threshold $scc -rc-lookahead $(($scc+$fps)) -b:v "$brate"k -y encode.mp4 + else + brate=`ffmpeg -i $1 -an -c:v libx264 -fastfirstpass 0 -pass 1 -qcomp $qcmp -g $gop -sc_threshold $scc -rc-lookahead $(($scc+$fps)) -crf $crf $safeparams -f null /dev/null | grep -oP "(?<=kb/s:).*"` + ffmpeg -i $1 -an -c:v libx264 -pass 2 -qcomp $qcmp -g $gop -sc_threshold $scc -rc-lookahead $(($scc+$fps)) -b:v "$brate"k -y encode.mp4 + fi + else + exit; + fi +} + +encode_function \ No newline at end of file