2010-05-24 1 views
4

Я немного поработал здесь и на других сайтах, кажется, что этот вопрос задан несколько раз, но вместо того, чтобы давать реальный код, люди только дают теорию.надежный способ получить ход преобразования ffmpeg в BASH

Я хочу создать надежный способ получить прогресс в транскоде. Кажется, лучший способ - использовать полные кадры исходного файла, а затем получить текущий фрейм, который включен ffmpeg. Как отмечают люди, поскольку ffmpeg странно выводит свой прогресс с использованием Carriage Returns (/ r или^M) и потому, что иногда существует промежуток между выходом, а иногда и нет, в лучшем случае это может быть ненадежным. Вот пример вывода:

frame=73834 fps=397 q=0.0 size=  -0kB time=2462.14 bitrate= -0.0kbits/s frame=74028 fps=397 q=0.0 size=  -0kB time=2468.64 bitrate= -0.0kbits/s frame=74133 fps=397 q=0.0 Lsize=  -0kB time=2472.06 bitrate= -0.0kbits/ 

Я написал функцию, которая вызывается в то время как преобразование FFmpeg идет вперед. Вот что у меня до сих пор:

Во-первых, чтобы получить общее количество кадров исходного файла:

duration=($(ffmpeg -i "$SourceFile" 2>&1 | sed -n "s/.* Duration: \([^,]*\), start: .*/\1/p")) 
fps=($(ffmpeg -i "$SourceFile" 2>&1 | sed -n "s/.*, \(.*\) tbr.*/\1/p")) 
hours=($(echo $duration | cut -d":" -f1)) 
minutes=($(echo $duration | cut -d":" -f2)) 
seconds=($(echo $duration | cut -d":" -f3)) 
# Get the integer part with cut 
frames=($(echo "($hours*3600+$minutes*60+$seconds)*$fps" | bc | cut -d"." -f1)) 
if [ -z $frames ]; then 
    zenity --info --title "$WindowTitle" --text "Can't calculate frames, sorry." 
    exit 
echo ""$SourceFile" has $frames frames, now converting" > $ffmpeglog 
echo ""$SourceFile" has $frames frames, now converting" 

Тогда это функция прогресс я называю во время преобразования:

progress() { 
sleep 10 
#some shenanigans due to the way ffmpeg uses carriage returns 
cat -v $ffmpeglog | tr '^M' '\n' > $ffmpeglog1 
#calculate percentage progress based on frames 
cframe=($(tac $ffmpeglog1 | grep -m 1 frame= | awk '{print $1}' | cut -c 7-)) 
if [ -z $cframe ]; then 
    cframe=($(tac $ffmpeglog1 | grep -m 1 frame= | awk '{print $2}')) 
fi 
if is_integer $frame; then 
    percent=$((100 * cframe/frames)) 
    #calculate time left and taken etc 
    fps=($(tac $ffmpeglog1 | grep -m 1 frame= | awk '{print $3}')) 
    if [ "$fps" = "fps=" ]; then 
     fps=($(tac $ffmpeglog1 | grep -m 1 frame= | awk '{print $4}')) 
    fi 
    total=$((frames + cframe + percent + fps)) 
    #simple check to ensure all values are numbers 
    if is_integer $total; then 
     #all ok continue 
     if [ -z $fps ]; then 
      echo -ne "\rffmpeg: $cframe of $frames frames, progress: $percent"%" and ETA: error fps:0" 
     else 
      if [ -z $cframe ]; then 
       echo -ne "\rffmpeg: total $frames frames, error cframes:0" 
      else 
       remaining=$((frames - cframe)) 
       seconds=$((remaining/fps)) 
       h=$((seconds/3600)) 
       m=$(((seconds/60) % 60)) 
       s=$((seconds % 60)) 
       echo -ne "\rffmpeg: $cframe of $frames frames, progress: $percent"%" and ETA: "$h"h "$m"m "$s"s" 
      fi 
     fi 
    else 
     echo "Error, one of the values wasn't a number, trying again in 10s." 
    fi 
else 
    echo "Error, frames is 0, progress wont work, sorry." 

fi 
} 

И вот, для полноты картины, что is_integer функция:

is_integer() { 
    s=$(echo $1 | tr -d 0-9) 
    if [ -z "$s" ]; then 
     return 0 
    else 
     return 1 
    fi 

} 

Как вы можете видеть, мой approac h довольно грубо, потому что я пишу один файл журнала в другой, а затем обрабатываю этот 2-й файл журнала, чтобы попытаться справиться с возвратом каретки. Основная проблема, которую я обнаружил, заключается в том, что никакая команда, которую может вызывать BASH, кажется, имеет возможность вырезать вывод ffmpegs только на последнюю строку из-за откровенно беспричинного использования возвратов каретки. Мои навыки awk не очень хороши, и функция прогресса не работает, когда между частью frame = xxxxxx нет места, как это иногда бывает. Мне было интересно, может ли какой-нибудь BASH headz сделать мой код немного более устойчивым и надежным.

ответ

3

Причина возврата каретки, как я уверен, вы знаете, так что строки прогресса переписывают друг друга (выход остается на одной строке, так как нет перевода строки).

Вы можете попробовать этот метод для извлечения строки после последнего возврата каретки:

$ sample=$'cherry\rbanana\rapple' 
$ echo "$sample" 
applea 
$ cr=$'\r'     # A 
$ extract="${sample##*$cr}" # B 
$ echo "$extract" 
apple 

линии с маркировкой «A» и «B» являются предметами первой необходимости, остальные только для демонстрации. Используя этот метод, вы можете устранить некоторые из ваших поворотов, которые вы сейчас используете.

 Смежные вопросы

  • Нет связанных вопросов^_^