SHARE
TWEET

webm-convert

a guest Nov 30th, 2014 202 Never
  1. #!/bin/bash
  2.  
  3. filesize=$1
  4. audio_bitrate=$2
  5. source=$3
  6.  
  7. temp="/tmp/${RANDOM}_ffmpeg_vstats"
  8. quality_decrease=2.5 #decreases quality X times
  9. absolute_minimum_bitrate=64 #minimum video bitrate and vertical resolution
  10. q_min=4 #starting value for qmin
  11. q_max=20 #starting value for qmax
  12. q_max_maximum=40 #maximum value for qmax
  13. percent_expectation=0.1 #required gains for quality loss
  14.  
  15. fullpath="$(readlink -f "$source")"
  16.  
  17. source_dir="$(dirname "$fullpath")"
  18.  
  19. filename=$(basename "$source")
  20. filename="${filename%.*}"
  21.  
  22. if [ -z "$filesize" ] || [ -z "$audio_bitrate" ] || [ -z "$source" ] || [ -z "$(echo $filesize | grep "[0-9]")" ] || [ -z "$(echo $audio_bitrate | grep "[0-9]")" ]
  23. then
  24.         echo "USAGE: $0 [Filesize in MB] [Audio bitrate in kbit/s] [Filename]"
  25.         exit 0
  26. fi
  27.  
  28. if [ "$audio_bitrate" -ge "45" ]
  29. then
  30.         encode_audio="-codec:a libvorbis -b:a ${audio_bitrate}k -ac 2 -clev 3dB -slev -6dB"
  31. else
  32.         audio_bitrate=0
  33.         encode_audio="-an"
  34. fi
  35.  
  36. filesize_bytes="$(echo "$filesize * 1048576" | bc | awk -F'.' '{print $1}')"
  37.  
  38. display ()
  39. {
  40. time_start=$(date +%s)
  41. frame_count=0
  42. time_eta=0
  43. time_elapsed=0
  44. while [ -e /proc/$PID ]
  45. do
  46.         sleep 2
  47.         if [ -e "$temp" ]
  48.         then
  49.                 ffmpeg_vstats=$(awk '{gsub(/frame=/, "")}/./{line=$1-1} END{print line}' $temp)
  50.                 if [ -n "$ffmpeg_vstats" ]
  51.                 then
  52.                         if [ "$ffmpeg_vstats" -gt "$frame_count" ]
  53.                         then
  54.                                 frame_count=$ffmpeg_vstats
  55.                                 progress=$(( 100 * frame_count / source_frames ))
  56.                                 time_elapsed=$(( $(date +%s) - time_start ))
  57.                                 echo $time_elapsed > /tmp/elapsed.value
  58.                                 time_eta=$(date -d @$(awk 'BEGIN{print int(('$time_elapsed' / '$frame_count') * ('$source_frames' - '$frame_count'))}') -u +%H:%M:%S)
  59.                         fi
  60.                 fi
  61.                 echo -ne "\rElapsed Time: $(date -d @$time_elapsed -u +%H:%M:%S)\tETA: $time_eta\t ${progress}%"
  62.         fi
  63. done
  64. }
  65.  
  66. cleanup ()
  67. {
  68.         rm -f "$temp" 2> /dev/null
  69.         rm -f "$source_dir/$source_checksum-0.log" 2> /dev/null
  70. }
  71.  
  72. badrun ()
  73. {
  74.         rm -f "$temp" 2> /dev/null
  75.         rm -f "$output_file_new" 2> /dev/null
  76.         rm -f "$source_dir/$source_checksum-0.log" 2> /dev/null
  77. }
  78.  
  79. dirtyexit ()
  80. {
  81.         rm -f "$temp" 2> /dev/null
  82.         rm -f "$output_file_new" 2> /dev/null
  83.         rm -f "$output_file_old" 2> /dev/null
  84.         rm -f "$source_dir/$source_checksum-0.log" 2> /dev/null
  85. }
  86.  
  87. calculateresize ()
  88. {
  89.         if [ "$bitrate" -le "$absolute_minimum_bitrate" ]
  90.         then
  91.                 bitrate=$absolute_minimum_bitrate
  92.                 resize_height=$absolute_minimum_bitrate
  93.                 resize="-vf scale=-1:${bitrate}"
  94.         else
  95.                 source_bpp=$(echo "scale=10; ($source_bitrate/$source_area)/$quality_decrease" | bc)
  96.                 resize_area=$(echo "scale=10; $bitrate/$source_bpp" | bc)
  97.                 resize_height=$(echo "scale=10; $source_height * ($resize_area/$source_area)" | bc | awk -F'.' '{print $1}' | tr -d ' ')
  98.                 if [ "$resize_height" -ge "$source_height" ]
  99.                 then
  100.                         resize_height=$source_height
  101.                 fi
  102.                 resize="-vf scale=-1:${resize_height}"
  103.         fi
  104. }
  105.  
  106. adjustmaxbitrate ()
  107. {
  108.         if [ "$source_bitrate" -le "$bitrate" ]
  109.         then
  110.                 bitrate=$source_bitrate
  111.                 resize_height=$source_height
  112.                 resize=""
  113.                 exit_increase=1
  114.         fi
  115. }
  116.  
  117. adjustslices ()
  118. {
  119.         if [ "$resize_height" -le "480" ]
  120.         then
  121.                 slices="-slices 1"
  122.         else
  123.                 if [ "$resize_height" -lt "720" ]
  124.                 then
  125.                         slices="-slices 2"
  126.                 else
  127.                         slices="-slices 4"
  128.                 fi
  129.         fi
  130. }
  131.  
  132. adjustquantizer ()
  133. {
  134.         byte_check=$(echo "$output_size - $filesize_bytes" | bc | awk -F'.' '{print $1}')
  135.         #echo "adjust quantizer"
  136.         if [ "$byte_check" -ge "2000000" ]
  137.         then
  138.                 let q_max=q_max+10
  139.                 q_adjust=10
  140.         else
  141.                 if [ "$byte_check" -ge "1000000" ]
  142.                 then
  143.                         let q_max=q_max+6
  144.                         q_adjust=6
  145.                 else
  146.                         if [ "$byte_check" -ge "10000" ]
  147.                         then
  148.                                 let q_max=q_max+4
  149.                                 q_adjust=4
  150.                         else
  151.                                 let q_max=q_max+2
  152.                                 q_adjust=2
  153.                         fi
  154.                 fi
  155.  
  156.                 if [ "$q_max" -gt "$q_max_maximum" ]
  157.                 then
  158.                         #echo "adjust bitrate 3"
  159.                         q_max=$q_max_maximum
  160.                         q_adjust=255
  161.                         let bitrate=bitrate-10
  162.                         calculateresize
  163.                         adjustslices
  164.                 fi
  165.         fi
  166. }
  167.  
  168. if [ -e "$source" ]
  169. then
  170.         time=$(ffmpeg -i "$source" 2>&1 | grep Duration | cut -d ' ' -f 4 | cut -d '.' -f 1 | awk -F: '{ print ($1 * 3600) + ($2 * 60) + $3 }')
  171.         if [ "$(echo $time | grep [0-9])" ]
  172.         then
  173.                 thread_number=$(grep -m1 "siblings" /proc/cpuinfo | awk -F": " '{print $2}')
  174.  
  175.                 source_checksum=$(md5sum "$source" | awk '{print $1}')
  176.                 source_fps=$(ffmpeg -i "$source" 2>&1 | sed -n "s/.*, \(.*\) tbr.*/\1/p")
  177.                 source_duration=$(ffmpeg -i "$source" 2>&1 | sed -n "s/.* Duration: \([^,]*\), .*/\1/p" | awk -F':' '{print $1 * 3600 + $2 * 60 + $3}')
  178.                 source_bitrate=$(ffmpeg -i "$source" 2>&1 | grep bitrate | awk '{print $6}')
  179.                 source_area=$(ffmpeg -i "$source" 2>&1 | grep Video | grep 0.0 | awk -F'[' '{print $1}' | awk -F',' '{print $3}' | awk -F'x' '{print $1 * $2}')
  180.                 source_height=$(ffmpeg -i "$source" 2>&1 | grep Video | grep 0.0 | awk -F'[' '{print $1}' | awk -F',' '{print $3}' | awk -F'x' '{print $2}')
  181.                 source_frames=$(echo "scale=4; $source_duration * $source_fps" | bc | awk -F'.' '{print $1}')
  182.  
  183.                 bitrate=$(echo "(($filesize*8192)/$time)-$audio_bitrate-10" | bc)
  184.                 max_bitrate=$(echo "$bitrate*4" | bc)
  185.                 min_bitrate=$(echo "$bitrate/10" | bc)
  186.  
  187.                 if [ -z "$source_height" ] || [ -z "$source_bitrate" ] || [ -z "$source_area" ]
  188.                 then
  189.                         echo "$source cannot be read by ffmpeg."
  190.                         exit 1
  191.                 else
  192.                         if [ -z "$(echo $source_height | grep "[0-9]")" ]
  193.                         then
  194.                                 echo "$source cannot be read by ffmpeg."
  195.                                 exit 1
  196.                         fi
  197.  
  198.                         if [ -z "$(echo $source_bitrate | grep "[0-9]")" ]
  199.                         then
  200.                                 echo "$source cannot be read by ffmpeg."
  201.                                 exit 1
  202.                         fi
  203.  
  204.                         if [ -z "$(echo $source_area | grep "[0-9]")" ]
  205.                         then
  206.                                 echo "$source cannot be read by ffmpeg."
  207.                                 exit 1
  208.                         fi
  209.                 fi
  210.  
  211.                 if [ "$source_bitrate" -le "$bitrate" ]
  212.                 then
  213.                         bitrate=$source_bitrate
  214.                         resize_height=$source_height
  215.                         resize=""
  216.                 else
  217.                         calculateresize
  218.                 fi
  219.  
  220.                 adjustslices
  221.                 output_file_new="$source_dir/${filename}_vbr_${bitrate}k.webm"
  222.  
  223.                 max_bitrate=$(echo "$bitrate*2" | bc)
  224.                 min_bitrate=$(echo "$bitrate/10" | bc)
  225.  
  226.                 trap "{ dirtyexit; exit 255; }" SIGINT SIGTERM
  227.  
  228.                 if [ ! -e "$output_file_new" ]
  229.                 then
  230.                         attempt=1
  231.                         finished=0
  232.                         q_adjust=0
  233.                         increase=0
  234.                         exit_increase=0
  235.                         while [ "$finished" -ne "1" ]
  236.                         do
  237.                                 output_file_new="$source_dir/${filename}_vbr_${bitrate}k.webm"
  238.                                 #echo $output_file_new
  239.                                 clear
  240.                                 #echo
  241.                                 echo "Encoding: $filename"
  242.                                 echo "Video @ ${bitrate}kbit/s"
  243.                                 if [ "$audio_bitrate" -eq "0" ]
  244.                                 then
  245.                                         echo "Audio @ Disabled"
  246.                                 else
  247.                                         echo "Audio @ ${audio_bitrate}kbit/s"
  248.                                 fi
  249.                                 echo "qmin: $q_min"
  250.                                 echo "qmax: $q_max"
  251.                                 if [ -n "$old_size" ]
  252.                                 then
  253.                                         echo "Last attempt was: ${old_size} bytes"
  254.                                 fi
  255.                                 echo "Attempt: $attempt"
  256.                                 echo "Starting first pass."
  257.                                 ffmpeg -y -i "$source" \
  258.                                 -vstats_file $temp \
  259.                                 -loglevel quiet -c:v libvpx \
  260.                                 -threads $thread_number \
  261.                                 -passlogfile "$source_dir/$source_checksum" \
  262.                                 -auto-alt-ref 1 $slices \
  263.                                 -lag-in-frames 16 \
  264.                                 -cpu-used 0 \
  265.                                 -keyint_min 0 \
  266.                                 -g 360 \
  267.                                 -qmin $q_min \
  268.                                 -qmax $q_max \
  269.                                 -quality good \
  270.                                 -minrate ${min_bitrate}k \
  271.                                 -maxrate ${max_bitrate}k \
  272.                                 -b:v ${bitrate}k ${resize} \
  273.                                 -an -pass 1 -f webm /dev/null
  274.  
  275.                                 echo "Starting second pass."
  276.                                 ffmpeg -y -i "$source" \
  277.                                 -vstats_file $temp \
  278.                                 -loglevel quiet -c:v libvpx \
  279.                                 -threads $thread_number \
  280.                                 -passlogfile "$source_dir/$source_checksum" \
  281.                                 -auto-alt-ref 1 $slices \
  282.                                 -lag-in-frames 16 \
  283.                                 -cpu-used 0 \
  284.                                 -keyint_min 0 \
  285.                                 -g 360 \
  286.                                 -qmin $q_min \
  287.                                 -qmax $q_max \
  288.                                 -quality good \
  289.                                 -minrate ${min_bitrate}k \
  290.                                 -maxrate ${max_bitrate}k \
  291.                                 -b:v ${bitrate}k ${resize} \
  292.                                 $encode_audio -pass 2 -f webm "$output_file_new" &
  293.                                 PID=$! &&
  294.                                 display
  295.                                 rm -f $temp
  296.  
  297.                                 output_size=$(du -b "$output_file_new" | awk '{print $1}')
  298.  
  299.                                 if [ "$output_size" -lt "$filesize_bytes" ]
  300.                                 then
  301.                                         if [ "$attempt" -eq "1" ] || [ "$increase" -eq "1" ] || [ "$q_adjust" -eq "10" ] || [ "$q_adjust" -eq "6" ] || [ "$q_adjust" -eq "4" ] || [ "$q_adjust" -eq "2" ] && [ "$exit_increase" -eq "0" ]
  302.                                         then
  303.                                                 rm -f "$output_file_old" 2> /dev/null
  304.                                                 output_file_old=$output_file_new
  305.                                                 increase=1
  306.                                                 let bitrate=bitrate+10
  307.                                                 calculateresize
  308.                                                 adjustmaxbitrate
  309.                                                 adjustslices
  310.                                         else
  311.                                                 if [ "$output_size" -eq "0" ]
  312.                                                 then
  313.                                                         badrun
  314.                                                         echo "The file failed to encode."
  315.                                                         echo "Please try again with a larger filesize or audio bitrate."
  316.                                                         exit 5
  317.                                                 else
  318.                                                         finished=1
  319.                                                 fi
  320.                                         fi
  321.                                 else
  322.                                         if [ ! -e "$output_file_old" ]
  323.                                         then
  324.                                                 badrun
  325.                                                 if [ "$q_adjust" -eq "255" ]
  326.                                                 then
  327.                                                         let bitrate=bitrate-10
  328.                                                         calculateresize
  329.                                                         adjustslices
  330.                                                         #echo "adjust bitrate 1"
  331.                                                 else
  332.                                                         if [ "$attempt" -gt "2" ]
  333.                                                         then
  334.                                                                 output_difference="$(echo "($old_size - $output_size)" | bc | awk -F'.' '{print $1}')"
  335.                                                                 expectation="$(echo "$old_size * $percent_expectation" | bc | awk -F'.' '{print $1}')"
  336.                                                                 if [ "$output_difference" -lt "$expectation" ]
  337.                                                                 then
  338.                                                                         if [ "$q_adjust" -eq 10 ]
  339.                                                                         then
  340.                                                                                 let q_max=q_max-q_adjust
  341.                                                                         fi
  342.                                                                         q_adjust=255
  343.                                                                         let bitrate=bitrate-10
  344.                                                                         calculateresize
  345.                                                                         adjustslices
  346.                                                                         #echo "adjust bitrate 2"
  347.                                                                 else
  348.                                                                         adjustquantizer
  349.                                                                 fi
  350.                                                         else
  351.                                                                 adjustquantizer
  352.                                                         fi
  353.                                                 fi
  354.                                         else
  355.                                                 badrun
  356.                                                 output_file_new=$output_file_old
  357.                                                 finished=1
  358.                                         fi
  359.                                 fi
  360.                                 old_size=$output_size
  361.                                 let attempt=attempt+1
  362.                         done
  363.  
  364.                         if [ "$finished" -eq "1" ]
  365.                         then
  366.                                 echo
  367.                                 echo "Encode finished."
  368.                                 du -b "$output_file_new"
  369.                                 cleanup
  370.                         else
  371.                                 echo
  372.                                 echo "Unable to encode file to required size."
  373.                                 echo "Increase filesize limit to accomidate this file."
  374.                                 cleanup
  375.                         fi
  376.                 else
  377.                         echo "File already exists."
  378.                 fi
  379.         else
  380.                 echo "$source cannot be read by ffmpeg."
  381.                 cleanup
  382.                 exit 1
  383.         fi
  384. else
  385.         echo "File does not exist."
  386.         cleanup
  387.         exit 2
  388. fi
RAW Paste Data
Top