
찾기 결과를 반복하고 일부 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)
의-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