Bash脚本以从ffprobe获取信息

5
我正试图创建一个处理视频的脚本,但希望能从输入文件中获取bit_rate、width和height信息以更好地调整输出。当我逐个处理文件时,脚本可以正常工作,但当我放到循环中时,突然间就获取不到任何信息了。
所以这个可以正常工作:
#!/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;

当从以下命令行执行时,它不起作用: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

我在循环中使用bitrate的数学运算时出现了错误,但即使我将其注释掉,仍然没有结果。由于一个接一个地工作,我认为问题与ffmpeg / ffprobe无关,而是与bash脚本有关。

话虽如此,我可以这样做:

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

并返回

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

所以它确实会返回一些信息,但却失去了eval语句中的信息。


为什么需要知道输入的比特率?请使用shellcheck.net检查您的脚本。如果仍然有问题,请展示您清理过的脚本。 - llogan
1
我正在对数千个视频进行编码,有些输入视频的分辨率和比特率远低于其他视频,但由于我想使用nvenc_hvec,它的选定适当比特率的算法要比libx265更不直观,所以我必须为每个文件指定它。我打算使用一些“if,else”逻辑来为输出选择适当的速率,这样我就不会意外地将一个400kbps的输入文件编码为1,200kbps。 - Alan
我使用了shellcheck.net,虽然没有发现任何值得注意的问题,但我很感谢你的推荐,这个网站对我来说是新的。 - Alan
一般来说,我会非常犹豫地使用eval这种方式。你基本上是在你的shell中运行成千上万个命令,这些命令是由ffprobe的输出结果产生的。我认为一个快速的Python脚本或者也许是sedawk更适合这个任务。 - eddiem
请忽略我之前的评论,如果您删除eval命令周围参数的单引号,它是否有效? - eddiem
1
原来,在ffprobe语句中需要使用"$i"来处理带有空格的文件。 - Alan
1个回答

5

我发现问题出在变量$i中含有空格的文件。

这段代码将所有命令合并为一个单独的shell命令,搜索当前文件夹和所有子文件夹中的所有视频文件,并通过一些选项循环设置不同分辨率的比特率设置以及其他一些可调整的参数。

#!/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  

太酷了 :) 非常感谢!我因为某些疯狂的原因无法让 ffprobestdout 上输出数据而变得非常沮丧,只能在 stderr 上输出,因此无法将结果与其他 shell 脚本一起使用... 原来我需要更多的参数,你的例子指明了方向并带来了启示! - Gwyneth Llewelyn

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接