Bir döngüde ffmpeg kullanırken garip hatalar


23

Bazı FLV dosyalarının ffmpeg kodlamasını ve bulgusunun sonuçlarının arasında geçen bir bash betiği var. Betik çalışırken ffmpeg çıktısı kesilmiş gibi görünüyor ve aşağıdaki gibi bazı garip görünen hatalar çıkarıyor. Burada neler olduğu hakkında hiçbir fikrim yok. Birisi beni doğru yöne işaret edebilir mi?

Olmaması gerektiği ve ffmpeg işlemini kesmesi gerektiği zaman döngü hala çalışıyor gibi.

Özel hata:

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 çıktısından bazı daha detaylar:

[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'

Komut aşağıdaki gibidir

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

Çok fazla bir komut dosyası değilim, ancak bariz bir öneri - komut dosyanızın yürütmekte olduğu satırları yazdırmasını sağlayın. Onlar düşündüğün gibi olmayabilir.
Faheem Mitha

Bir yan sayısında gibi: mp4filename=$(basename "$f" mp4)kullanışlı (bkz olabilir man basenameve man dirnamedaha fazla bilgi için)
Peter.O

Say bash -x myscriptbütün değişkenler genişletilmiş ile, betiğin çalışması bir çizgi-by-line izleme almak için. Oh, ve tesadüfen, hatta basenametekerleği yeniden icat ettin FILENAME=. :)
Warren Young

1
Çözümü buldum. Bash betiği, ffmpeg sürecini engelleyen ürün girdisi (yani 'c' anahtarı) gibi gözüküyor. "</ Dev / null" işlevini şu şekilde ffmpeg'e: ffmpeg -i "./$f" -vcodec libx264 -vprofile yüksek-önceden ayarlanmış yavaş -b: v 500k -maxrate 500k -bufsize 1000k -threads 0 -acodec libfaac -ab 128k "./mp4s/$MP4FILENAME" </ dev / null Sorunu düzeltir. [ linuxquestions.org/questions/programming-9/… [1] aracılığıyla : linuxquestions.org/questions/programming-9/…
Mark Williams 18

Yanıtlar:


56

Sorunuz aslında Bash SSS # 89'dur : yalnızca standart girişini okumasını </dev/nullönlemek için ekleyin ffmpeg.


Çok fazla potansiyel hata içerdiğinden senaryoyu sizin için düzeltme özgürlüğünü aldım. Önemli noktalardan birkaçı:

  • Dosya adları işlemek için zordur, çünkü çoğu dosya sistemi normal insanların çöp olarak göreceği her türlü yazdırılamaz karakterleri içerebilmelerini sağlar. "Dosya adları sadece 'normal' karakter içeriyor" gibi basit varsayımlar yapma kırılgan kabuk komut dosyalarını sonuçlanma eğilimindedir görünür"normal" dosya isimleri üzerinde çalışmak ve sonra betiğin varsayımlarını takip etmeyen özellikle iğrenç bir dosya adına girdikleri günü kırmak için. Öte yandan, dosya adlarının doğru bir şekilde işlenmesi, garip bir dosya adıyla karşılaşma şansının sıfıra yakın olması beklendiğinde, çabaya değmeyecek kadar zahmetli olabilir (örn. Komut dosyasını yalnızca kendi dosyalarınızda kullanıyorsanız ve kendi dosyalarına "basit" adlar veriyorsun). Bazen bu karardan tamamen kaçınılması, dosya adlarını hiç ayrıştırmama ile mümkündür. Neyse ki, bu mümkündür find(1)bireyin -execseçeneği. Sadece {}argüman koymak -execve findçıktı ayrıştırma konusunda endişelenmenize gerek yok .

  • Kullanılması sedveya diğer harici süreçler sıyırma uzantıları ve önekleri gibi basit dize işlemlerini yapmak verimsizdir. Bunun yerine, kabuğun bir parçası olan parametre genişlemelerini kullanın (dış işlem yok, daha hızlı olacağı anlamına gelir). Konuyla ilgili bazı yararlı makaleler aşağıda listelenmiştir:

  • Kullan $( )ve ``artık kullanma : Bash FAQ 82 .

  • UPPERCASE değişken isimlerini kullanmaktan kaçının. Bu ad alanı, genellikle kabuk tarafından özel amaçlar (örneğin PATH) için ayrılmıştır , bu nedenle kendi değişkenleriniz için kullanmak kötü bir fikirdir.

Ve şimdi, daha fazla uzatmadan, işte sizin için temizlenmiş bir senaryo:

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

Not: POSIX’i kullandım, shçünkü bashorijinalinizde herhangi bir özel özellik kullanmadınız ya da buna ihtiyacınız yoktu .


3
Mükemmel bir cevap! Düzeltilmiş senaryo yazma çabası için teşekkür ederiz. Merak ediyorum, Greg'in Wiki'nin zsh rehberine benzer bir şey var mı? Teşekkürler!
Sanat

1
@Art Üzgünüz, hakkında fazla bir şey bilmiyorum zsh. Belki sitedeki bazı zsh insanlar bilecektir.
jw013

Sorun şu ki, ffmpeg'in betiği daha sonra aşağıya dönüştürmek için bir hata üretip üretmediğini kontrol etmem gerekiyor, dönüştürülen dosyanın önceki sürümünün silinip silinmeyeceğine karar vermek. Bir Plex Media Server için mkv'yi mp4'e dönüştürüyorum. Ben büyük mkv dosyaları ile kekemelik, bu yüzden tüm mkv mp4 dönüştürmeye karar verdim. Başka bir sorun da, resim tabanlı formatlar için altyazı akış dönüştürme hatası olup olmadığını kontrol etmem gerektiği, bu durumda altları çıkarmak için başka bir işlem kullanıyorum. Öyleyse, ffmpeg'i nasıl çalıştırabilirim, çıktısını alabilirim ve bu sorunla karşılaşmaz mıyım?
dacabdi

15

Çözümü buldum . Bash betiği, ffmpegsürece müdahale eden girdi (yani 'c' anahtarı) üretiyor gibi görünmektedir .

Ekleme < /dev/nulliçin ffmpegkomut satırında, bu nedenle gibi:

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

sorunu düzeltir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.