Lỗi lạ khi sử dụng ffmpeg trong một vòng lặp


23

Tôi có một tập lệnh bash lặp qua các kết quả tìm và thực hiện mã hóa ffmpeg của một số tệp FLV. Trong khi tập lệnh đang chạy, đầu ra ffmpeg dường như bị gián đoạn và xuất ra một số lỗi trông lạ như bên dưới. Tôi không biết chuyện gì đang xảy ra ở đây. ai đó có thể chỉ cho tôi phương hướng đúng không?

Dường như vòng lặp vẫn chạy khi không nên và xen vào quá trình ffmpeg.

Lỗi cụ thể là:

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'

Một số chi tiết khác từ đầu ra 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'

Kịch bản như sau

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

Tôi không phải là một người viết kịch bản, nhưng là một gợi ý rõ ràng - hãy để tập lệnh của bạn in ra các dòng mà nó đang thực thi. Họ có thể không phải là những gì bạn nghĩ rằng họ là.
Faheem Mitha

Là một vấn đề phụ: mp4filename=$(basename "$f" mp4)có thể hữu ích (xem man basenameman dirnameđể biết thêm thông tin)
Peter.O

Nói bash -x myscriptđể có được dấu vết từng dòng của việc thực thi tập lệnh, với tất cả các biến được mở rộng. Ồ, và thật tình cờ, bạn đã phát minh lại basenamebánh xe trên FILENAME=đường dây. :)
Warren Young

1
Tôi đã tìm thấy giải pháp. Tập lệnh bash dường như nhập vào sản phẩm (Cụ thể là khóa 'c') gây cản trở quá trình ffmpeg. Đường ống "</ dev / null" vào ffmpeg như vậy: ffmpeg -i "./$f" -vcodec libx264 -vprofile high -preset chậm -b: v 500k -maxrate 500k -bufsize 1000k -threads 128k "./mp4s/$MP4FILENAME" </ dev / null Khắc phục sự cố. qua [ linuxquestions.org/questions/programming-9/... [1]: linuxquestions.org/questions/programming-9/...
Mark Williams

Câu trả lời:


56

Câu hỏi của bạn thực sự là Bash FAQ # 89 : chỉ cần thêm </dev/nullđể ngăn ffmpegđọc đầu vào tiêu chuẩn của nó.


Tôi đã tự do sửa chữa tập lệnh của bạn cho bạn vì nó chứa rất nhiều lỗi tiềm ẩn. Một vài trong số những điểm quan trọng:

  • Tên tệp rất khó xử lý, vì hầu hết các hệ thống tệp cho phép chúng chứa tất cả các loại ký tự không thể in được mà người bình thường sẽ xem là rác. Việc đơn giản hóa các giả định như "tên tệp chỉ chứa các ký tự 'bình thường' có xu hướng dẫn đến các tập lệnh shell mong manh xuất hiệnđể làm việc với tên tệp "bình thường" và sau đó phá vỡ ngày họ chạy vào một tên tệp đặc biệt khó chịu không tuân theo các giả định của tập lệnh. Mặt khác, việc xử lý chính xác tên tệp có thể gây phiền toái đến mức bạn có thể thấy nó không đáng nỗ lực nếu cơ hội gặp phải một tên tệp lạ được dự kiến ​​là gần bằng 0 (tức là bạn chỉ sử dụng tập lệnh trên các tệp của riêng mình và bạn đặt tên tập tin của riêng bạn "đơn giản"). Đôi khi có thể tránh quyết định này hoàn toàn bằng cách không phân tích tên tệp. May mắn thay, có nghĩa là có thể với find(1)'s -execlựa chọn. Chỉ cần đưa {}vào đối số -execvà bạn không phải lo lắng về phân tích cú pháp findđầu ra.

  • Sử dụng sedhoặc các quy trình bên ngoài khác để thực hiện các hoạt động chuỗi đơn giản như tước phần mở rộng và tiền tố là không hiệu quả. Thay vào đó, sử dụng các mở rộng tham số là một phần của vỏ (không có quá trình bên ngoài có nghĩa là nó sẽ nhanh hơn). Một số bài viết hữu ích về chủ đề được liệt kê dưới đây:

  • Sử dụng $( )và không sử dụng ``nữa: Bash FAQ 82 .

  • Tránh sử dụng tên biến UPPERCASE. Không gian tên đó thường được dành riêng cho shell cho các mục đích đặc biệt (như PATH), vì vậy sử dụng nó cho các biến của riêng bạn là một ý tưởng tồi.

Và bây giờ, không cần phải quảng cáo thêm, đây là một kịch bản được làm sạch cho bạn:

#!/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
' _ {} +

Lưu ý: Tôi đã sử dụng POSIX shvì bạn không sử dụng hoặc cần bất kỳ bashtính năng cụ thể nào trong bản gốc của mình.


3
Đó là một câu trả lời tuyệt vời! Cảm ơn bạn đã nỗ lực viết lên kịch bản sửa chữa. Chỉ tự hỏi là có tương tự như hướng dẫn Wiki của Greg với zsh không? Cảm ơn!
Nghệ thuật

1
@Art Xin lỗi, tôi không biết nhiều về zsh. Có lẽ một số người zsh trên trang web sẽ biết.
jw013

Vấn đề là tôi cần kiểm tra xem ffmpeg có tạo ra lỗi hay không để sau đó xuống tập lệnh quyết định có xóa phiên bản trước của tệp đã chuyển đổi hay không. Tôi đang chuyển đổi mkv sang mp4 cho Plex Media Server. Tôi đã nói lắp với các tập tin mkv lớn, vì vậy tôi quyết định chuyển đổi tất cả mkv sang mp4. Một vấn đề khác là tôi cần kiểm tra lỗi chuyển đổi luồng phụ đề cho các định dạng dựa trên hình ảnh, trong trường hợp đó tôi sử dụng một bộ xử lý khác để trích xuất phụ. Vì vậy, làm thế nào để tôi chạy ffmpeg, nhận đầu ra của nó và không gặp phải vấn đề này?
dacabdi

15

Tôi đã tìm thấy giải pháp . Tập lệnh bash dường như tạo ra đầu vào (Cụ thể là khóa 'c') gây cản trở ffmpegquá trình.

Thêm < /dev/nullvào ffmpegdòng lệnh, như vậy:

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

khắc phục sự cố.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.