Странные ошибки при использовании ffmpeg в цикле

Странные ошибки при использовании ffmpeg в цикле

У меня есть скрипт bash, который циклически проходит по результатам поиска и выполняет кодирование ffmpeg некоторых файлов FLV. Пока скрипт работает, вывод ffmpeg, похоже, прерывается и выводит какие-то странные ошибки, как показано ниже. Я понятия не имею, что здесь происходит. Может ли кто-нибудь указать мне правильное направление?

Как будто цикл все еще выполняется, хотя он не должен выполняться, и прерывает процесс ffmpeg.

Конкретная ошибка:

frame=   68 fps= 67 q=28.0 00000000000000000000000000001000size=      22kB time=00:00:00.50 bitrate= 363.2kbits/s dup=1 drop=0    
Enter command: <target> <time> <command>[ <argument>]
Parse error, at least 3 arguments were expected, only 1 given in string 'om/pt_br/nx/R3T4N2_HD3D_demoCheckedOut.flv'

Еще немного подробностей из вывода ffmpeg:

[buffer @ 0xa30e1e0] w:800 h:600 pixfmt:yuv420p tb:1/1000000 sar:0/1 sws_param:flags=2
[libx264 @ 0xa333240] using cpu capabilities: MMX2 SSE2Fast SSSE3 FastShuffle SSE4.1 Cache64
[libx264 @ 0xa333240] profile High, level 3.1
[libx264 @ 0xa333240] 264 - core 122 r2184 5c85e0a - H.264/MPEG-4 AVC codec - Copyleft 2003-2012 - http://www.videolan.org/x264.html - options: cabac=1 ref=5 deblock=1:0:0 analyse=0x3:0x113 me=umh subme=8 psy=1 psy_rd=1.00:0.00 mixed_ref=1 me_range=16 chroma_me=1 trellis=1 8x8dct=1 cqm=0 deadzone=21,11 fast_pskip=1 chroma_qp_offset=-2 threads=1 sliced_threads=0 nr=0 decimate=1 interlaced=0 bluray_compat=0 constrained_intra=0 bframes=3 b_pyramid=2 b_adapt=2 b_bias=0 direct=3 weightb=1 open_gop=0 weightp=2 keyint=250 keyint_min=25 scenecut=40 intra_refresh=0 rc_lookahead=50 rc=cbr mbtree=1 bitrate=500 ratetol=1.0 qcomp=0.60 qpmin=0 qpmax=69 qpstep=4 vbv_maxrate=500 vbv_bufsize=1000 nal_hrd=none ip_ratio=1.40 aq=1:1.00
Output #0, mp4, to './mp4s/pt_br/teamcenter/tc8_interactive/videos/8_SRM_EN.mp4':
  Metadata:
    audiodelay      : 0
    canSeekToEnd    : true
    encoder         : Lavf54.3.100
    Stream #0:0: Video: h264 (![0][0][0] / 0x0021), yuv420p, 800x600, q=-1--1, 500 kb/s, 30k tbn, 29.97 tbc
    Stream #0:1: Audio: aac (@[0][0][0] / 0x0040), 44100 Hz, mono, s16, 128 kb/s
Stream mapping:
  Stream #0:1 -> #0:0 (vp6f -> libx264)
  Stream #0:0 -> #0:1 (mp3 -> libfaac)
Press [q] to stop, [?] for help
error parsing debug value0 00000000000000000000000000000000size=      13kB time=00:00:00.-3 bitrate=-3165.5kbits/s dup=1 drop=0    
debug=0
frame=   68 fps= 67 q=28.0 00000000000000000000000000001000size=      22kB time=00:00:00.50 bitrate= 363.2kbits/s dup=1 drop=0    
Enter command: <target> <time> <command>[ <argument>]
Parse error, at least 3 arguments were expected, only 1 given in string 'om/pt_br/nx/R3T4N2_HD3D_demoCheckedOut.flv'

Сценарий следующий

#!/bin/bash
LOGFILE=encodemp4ize.log
echo '' > $LOGFILE
STARTTIME=date
echo "Started at `$STARTTIME`" >> $LOGFILE
rsync -avz flvs/ mp4s/ --exclude '*.flv'
#find flvs/ -name "*.flv" > flv-files
# The loop
find flvs/ -name "*.flv" | while read f
do
FILENAME=`echo $f | sed 's#flvs/##'`
MP4FILENAME=`echo $FILENAME | sed 's#.flv#.mp4#'`
ffmpeg -i "$f" -vcodec libx264 -vprofile high -preset slow -b:v 500k -maxrate 500k -bufsize 1000k -threads 0 -acodec libfaac -ab 128k "./mp4s/$MP4FILENAME"
echo "$f MP4 done" >> $LOGFILE
done

решение1

Ваш вопрос на самом делеЧасто задаваемые вопросы по Bash #89: просто добавьте, </dev/nullчтобы запретить ffmpegчтение стандартного ввода.


Я взял на себя смелость исправить ваш сценарий, потому что он содержит много потенциальных ошибок. Несколько важных моментов:

  • С именами файлов сложно работать, поскольку большинство файловых систем позволяют им содержать всевозможные непечатаемые символы, которые обычные люди посчитали бы мусором. Упрощающие предположения, такие как «имена файлов содержат только «нормальные» символы», приводят к появлению хрупких скриптов оболочки, которыепоявлятьсяработать с "нормальными" именами файлов, а затем прерываться в тот день, когда они сталкиваются с особенно неприятным именем файла, которое не соответствует предположениям скрипта. С другой стороны, правильная обработка имен файлов может быть такой хлопотной, что вы можете посчитать это не стоящим усилий, если вероятность столкнуться со странным именем файла, как ожидается, близка к нулю (т. е. вы используете скрипт только для своих собственных файлов и даете своим собственным файлам "простые" имена). Иногда можно вообще избежать этого решения, не анализируя имена файлов вообще. К счастью, это возможно с find(1)опцией -exec. Просто введите {}аргумент to -execи вам не придется беспокоиться о анализе findвывода.

  • Использование sedили других внешних процессов для выполнения простых строковых операций, таких как удаление расширений и префиксов, неэффективно. Вместо этого используйте расширения параметров, которые являются частью оболочки (отсутствие внешнего процесса означает, что это будет быстрее). Ниже перечислены некоторые полезные статьи по этой теме:

  • Используйте $( )и ``больше не используйте: Часто задаваемые вопросы по Башу 82.

  • Избегайте использования имен переменных в ВЕРХНЕМ РЕГИСТРЕ. Это пространство имен обычно резервируется оболочкой для специальных целей (например, PATH), поэтому использование его для собственных переменных — плохая идея.

А теперь, без лишних слов, вот вам очищенный скрипт:

#!/bin/sh

logfile=encodemp4ize.log
echo "Started at $(date)." > "$logfile"
rsync -avz --exclude '*.flv' flvs/ mp4s/

find flvs/ -type f -name '*.flv' -exec sh -c '
for flvsfile; do
    file=${flvsfile#flvs/}
    < /dev/null ffmpeg -i "$flvsfile" -vcodec libx264 -vprofile high \
        -preset slow -b:v 500k -maxrate 500k -bufsize 1000k \
        -threads 0 -acodec libfaac -ab 128k \
        "mp4s/${file%flv}"mp4
    printf %s\\n "$flvsfile MP4 done." >> "$logfile"
done
' _ {} +

Примечание: Я использовал POSIX, поскольку в вашем оригинале shне использовались и не требовались какие-либо специфические функции.bash

решение2

Я нашелрешение. Скрипт bash, по-видимому, создает ввод (а именно клавишу «c»), который мешает процессу ffmpeg.

Добавляем < /dev/nullв ffmpegкомандную строку, например так:

ffmpeg -i "./$f" -vcodec libx264 -vprofile high -preset slow -b:v 500k -maxrate 500k -bufsize 1000k -threads 0 -acodec libfaac -ab 128k "./mp4s/$MP4FILENAME" < /dev/null

решает проблему.

решение3

В качестве альтернативного решения ffmpeg [...] < /dev/nullвы можете использовать:

ffmpeg -nostdin [...]

Подробности отдокументация ffmpeg:

Чтобы явно отключить взаимодействие, необходимо указать -nostdin.

Отключение взаимодействия на стандартном вводе полезно, например, если ffmpeg находится в группе фоновых процессов. Примерно того же результата можно добиться с помощью ffmpeg ... < /dev/null, но для этого требуется оболочка.

решение4

В whileцикле я столкнулся с похожими проблемами. Вы можете использовать forцикл, а в forцикле вы можете избежать взятия списка аудио и запуска его в цикле с помощью команды find.

Я использовал findи sedдля получения списка аудиофайлов в моем каталоге, потому что я видел ситуации, когда использование подстановочных знаков приводило к "argument list too long"ошибке.

Теперь, если мы просто выполним поиск, то он выдаст абсолютный путь к файлам, что приведет к ffmpegсбою, поэтому мы удалили абсолютный путь с помощью sed.

Вы можете использовать такую ​​команду (использовал ее много раз, и она работает отлично)

for f1 in `find . -maxdepth 1 -name "*.mkv" | sed 's/^\.\///g'`; do ffmpeg -i "$f1" -q:a 0 -map a ../wav/"${f1%.*}.wav"; done

Связанный контент