결과를 반복하고 일부 FLV 파일에서 ffmpeg 인코딩을 수행하는 bash 스크립트가 있습니다. 스크립트가 실행되면 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
귀하의 질문은 실제로배쉬 FAQ #89: 표준 입력을 읽지 못하게 </dev/null
하려면 추가하세요 .ffmpeg
스크립트에는 잠재적인 오류가 많이 포함되어 있으므로 스크립트를 수정해 드렸습니다. 몇 가지 핵심 사항:
파일 이름은 대부분의 파일 시스템에서 일반 사람들이 쓰레기로 간주할 수 있는 모든 종류의 인쇄할 수 없는 문자를 포함할 수 있도록 허용하기 때문에 다루기가 까다롭습니다. "파일 이름에는 '일반' 문자만 포함되어 있습니다"와 같은 단순화된 가정을 하면 취약한 쉘 스크립트가 되는 경우가 많습니다.나타나다"일반적인" 파일 이름을 처리한 다음 스크립트의 가정을 따르지 않는 특히 불쾌한 파일 이름을 발견한 날 이를 분류합니다. 반면, 이상한 파일 이름을 접할 확률이 0에 가까울 것으로 예상되는 경우(즉, 자신의 파일에만 스크립트를 사용하고 자신의 파일에 "간단한" 이름을 부여하는 경우) 파일 이름을 올바르게 처리하는 것은 문제가 될 수 있습니다. 때로는 파일 이름을 전혀 구문 분석하지 않음으로써 이러한 결정을 완전히 피할 수 있습니다. 다행히도
find(1)
이는 s 옵션을 통해 가능합니다-exec
.{}
매개변수 만 입력하면 출력 구문-exec
분석에 대해 걱정할 필요가 없습니다 .find
sed
확장자 및 접두사 제거와 같은 간단한 문자열 작업을 수행하기 위해 또는 기타 외부 프로세스를 사용하는 것은 비효율적입니다. 대신, 쉘의 일부인 매개변수 확장을 사용하십시오(외부 프로세스가 없다는 것은 더 빠르다는 것을 의미합니다). 아래에는 이 주제에 대한 유용한 기사가 나열되어 있습니다.- 배쉬 FAQ 73:매개변수 확장
- 배쉬 FAQ 100: 문자열 연산
중고
$( )
및 더 이상 사용되지 않음``
: 배쉬 FAQ 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
' _ {} +
참고: 원래 버전에서는 sh
사용하지 않거나 필요하지 않은 특정 기능이 있기 때문에 POSIX를 사용하고 있습니다.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"
이제 find를 수행하면 오류를 일으킬 수 있는 파일에 대한 절대 경로가 제공되므로 를 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