5

I am trying to create a script to process videos, but I was hoping to get bit_rate, width, and height info from the incoming files so I could better tune the output. The script works when I do the files one at a time, but when I put it into a loop all of a sudden I don't get any info.

So this works:

#!/bin/bash
eval $(ffprobe -v quiet -show_format -of flat=s=_ -show_entries stream=height,width,nb_frames,duration,codec_name input.mp4);
width=${streams_stream_0_width};
height=${streams_stream_0_height};
bitrate=$((${format_bit_rate}/1000));
echo $width,$height,$bitrate;

This doesn't when executed from find ./ -type f -regex ".*\.\(mkv\|mp4\|wmv\|flv\|webm\|mov\|avi\)" -print0 | xargs -0 /root/newbatch.sh

for i; do
eval '$(ffprobe -v quiet -show_format -of flat=s=_ -show_entries stream=height,width,nb_frames,duration,codec_name $i)';
width=${streams_stream_0_width};
height=${streams_stream_0_height};
bitrate=${format_bit_rate};
kbitrate=$((bitrate/1000));
echo $i,$width,$height,$kbitrate;

done

I also get an error with the math of bitrate in the loop, but even when I comment it out I still get no results. Since it works one at a time, I am assuming the problem is a bash scripting and nothing to do with ffmpeg / ffprobe.

That being said, I can do this:

echo $i,$width,$height,$bitrate;

and get back

./file1.mkv,,,
./file2.mkv,,,
./file3.mkv,,,
./file4.mkv,,,

So it does get some info back, but it loses the info from the eval statement.

Alan
  • 2,046
  • 2
  • 20
  • 43
  • Why do you need to know the bitrate from the input? Check your scripts with [shellcheck.net](http://www.shellcheck.net/). If you still have issues show your cleaned up scripts. – llogan Nov 11 '16 at 19:53
  • 1
    I am encoding a couple thousand videos and some videos coming in are of much lower resolution and bitrate than others, but since I want to use nvenc_hvec which has a much less intuitive algorithm for picking an appropriate bitrate than libx265, I have to specify it for each file. I was thinking of using some `if, else` logic to pick an appropriate rate for the output so I don't accidentally encode an incoming 400kbps file to 1,200kbps. – Alan Nov 11 '16 at 20:01
  • I used shellcheck.net, nothing of note discovered though I appreciate the recommendation, the site is new to me. – Alan Nov 11 '16 at 20:18
  • In general, I would be very hesitant about using `eval` in this way. You're basically running thousands of commands in your shell that are the result of output from `ffprobe`. I would think a quick Python script or maybe `sed` and `awk` would be better suited to this task. – eddiem Nov 11 '16 at 21:45
  • Ignoring my previous comment, does it work if you remove the single quotes around the arguments to the `eval` command? – eddiem Nov 11 '16 at 21:50
  • 1
    Turns out it needs to have `"$i"` in the ffprobe statement to handle files with whitespaces. – Alan Nov 11 '16 at 22:05

1 Answers1

5

I found the problem was files with whitespaces in the $i variable.

This code combines all the commands into a single shell command that searches the current folder and all subdirectories for all video files, loops though with some options to setup bitrate settings for different resolutions along with some other things to spruce it up.

#!/bin/bash
IFS=$'\n'   

# Reset
Color_Off='\033[0m'       # Text Reset

# Regular Colors
Black='\033[0;30m'        # Black
Red='\033[0;31m'          # Red
Green='\033[0;32m'        # Green
Yellow='\033[0;33m'       # Yellow
Blue='\033[0;34m'         # Blue
Purple='\033[0;35m'       # Purple
Cyan='\033[0;36m'         # Cyan
White='\033[0;37m'        # White

# Bold
BBlack='\033[1;30m'       # Black
BRed='\033[1;31m'         # Red
BGreen='\033[1;32m'       # Green
BYellow='\033[1;33m'      # Yellow
BBlue='\033[1;34m'        # Blue
BPurple='\033[1;35m'      # Purple
BCyan='\033[1;36m'        # Cyan
BWhite='\033[1;37m'       # White

# Underline
UBlack='\033[4;30m'       # Black
URed='\033[4;31m'         # Red
UGreen='\033[4;32m'       # Green
UYellow='\033[4;33m'      # Yellow
UBlue='\033[4;34m'        # Blue
UPurple='\033[4;35m'      # Purple
UCyan='\033[4;36m'        # Cyan
UWhite='\033[4;37m'       # White

# Background
On_Black='\033[40m'       # Black
On_Red='\033[41m'         # Red


VideoFiles=$(find ./ -maxdepth 10 -regex ".*\.\(mkv\|mp4\|wmv\|flv\|webm\|mov\|avi\|m4v\)")  

for i in $VideoFiles  
do  
  filename=$(basename "$i");
  extension="${filename##*.}";
  filename="${filename%.*}";
echo -e "${UGreen}############################################################################################################################################################################${Color_Off}\n";
echo -e "${Color_Off}Getting info of ${BCyan}$i${Color_Off}";

    eval $(ffprobe -v quiet -show_format -of flat=s=_ -show_entries stream=height,width,nb_frames,duration,codec_name -sexagesimal "$i");
    width=${streams_stream_0_width};
    height=${streams_stream_0_height};
    bitrate=${format_bit_rate};
    kbitrate=$((bitrate/1000));
    duration=${format_duration};
    #duration=$((durationSec/60));
    d=$(dirname "$i")
echo -e "${Color_Off}Duration = ${URed}$duration ${Color_Off}, Height/Width = ${URed}$height/$width ${Color_Off} Bitrate =${URed} $bitrate${Color_Off}\n";
echo -e "${UGreen}############################################################################################################################################################################${Color_Off}";
mkdir $d/Processed;

if ((1<= $height &&  $height<=400))
then    
    desired="200k";
    min="100k";
    max="800k";
    echo -e "This is a ${UPurple}LOW Quality${Color_Off} File\n.";

elif ((401<= $height &&  $height<=660))
then
    desired="500k";
    min="200k";
    max="1000k";
    echo -e "This is a ${UPurple}480p${Color_Off} File\n";
elif ((661<= $height &&  $height<=890))
then
    desired="800k";
    min="250k";
    max="1300k";
    echo -e "This is a ${UPurple}720p${Color_Off} File\n";

elif ((891<= $height &&  $height<=1200))
then
    desired="1200k";
    min="350k";
    max="2300k";
    echo -e "This is a ${UPurple}1080p${Color_Off} File\n";
else
    desired="1500k";
    min="550k";
    max="2700k";
    echo -e "This is a ${UPurple}HQ${Color_Off} File\n";
fi
    ffmpeg -n -i "$i" -c:v hevc_nvenc -hide_banner -preset fast -x265-params keyint=33:min-keyint=33 -crf 30 -b:v $desired -minrate $min -maxrate $max -bufsize 25M -c:a copy "$d/X265_$filename.mp4"
mv $i $d/Processed;
done  
Alan
  • 2,046
  • 2
  • 20
  • 43
  • So cool :) Thank you a lot! I was getting terribly frustrated because, for some insane reason, I was unable to get `ffprobe` to spew out data on `stdout` — only on `stderr` — and thus couldn't use the results with the rest of the shell scripts... it turns out that I needed far more parameters, and your example pointed the way and brought enlightenment! – Gwyneth Llewelyn Jul 30 '22 at 11:32