Otomasyonum üç gün üst üste aynı videoda çöktü. Her sabah aynı mail geliyordu: bir Instagram paylaşımı yapılamadı, ffmpeg hata verdi.
Hata satırı şuydu:
subprocess.CalledProcessError: Command '['ffmpeg', ...]' returned non-zero exit status 234
234 diye bir ffmpeg hata kodu yok. Belgelerde de aramayın, bulamazsınız. O yüzden ilk gün bunu "geçici bir aksaklık" sanıp geçtim. İkinci gün yine geldi. Üçüncü gün oturup baktım ve sebebin iki piksel olduğunu gördüm.
Kod neden hiçbir şey söylemiyordu
Önce şu satıra bakın:
subprocess.run([...], check=True, timeout=900)
capture_output yok. Yani ffmpeg'in kendi hata mesajı hiçbir yere yazılmıyordu. Python sadece "sıfırdan farklı çıkış kodu" diyordu, ffmpeg'in ekrana bastığı asıl sebep çöpe gidiyordu.
Aynı komutu elle çalıştırınca cevap ilk denemede geldi:
[Parsed_pad_1] Padded dimensions cannot be smaller than input dimensions.
[vf#0:0] Task finished with error code: -22 (Invalid argument)
Conversion failed!
İşte 234'ün sırrı burada. ffmpeg -22 döndürüyor, yani EINVAL. Kabuk çıkış kodlarını 0-255 aralığında taşır, 256 - 22 = 234. Yani gördüğünüz o anlamsız sayı aslında "geçersiz argüman" demek.
Bunu bir yere not edin: ffmpeg'den 234 görüyorsanız bir filtreniz geçersiz parametre almış demektir.
İki piksel
Boru hattı yatay videoları dikeye çeviriyordu. Filtre şuydu:
scale=1080:-2:force_original_aspect_ratio=decrease,
pad=1080:1920:(1080-iw)/2:(1920-ih)/2:black
Okunduğunda gayet mantıklı görünüyor. Genişliği 1080'e ölçekle, yüksekliği oranı koruyacak şekilde hesapla, sonra kalan boşluğu siyahla doldur. Aylarca da çalıştı.
Sorun çıkaran videonun boyutu şuydu:
1078 x 1920
Dikkat edin, 1080 değil 1078. İki piksel dar. Yani video 9:16'dan biraz daha uzun.
Şimdi filtrenin ne yaptığını adım adım takip edelim. scale=1080:-2 genişliği 1080'e çıkarıyor. Yükseklik -2 olduğu için oran korunarak hesaplanıyor:
1920 x 1080 / 1078 = 1923.56 -> cift sayiya yuvarlanir -> 1924
Ölçekten çıkan görüntü artık 1080x1924. Ama bir sonraki adım olan pad hedefi 1920. Yani pad'den kendisinden dört piksel uzun bir görüntüyü 1920'ye sığdırması isteniyor. Pad çerçeve ekler, kırpamaz. Reddediyor.
Peki force_original_aspect_ratio=decrease niye kurtarmadı? Çünkü o parametre iki boyutun da açıkça verilmesini bekliyor. Yüksekliğe -2 yazdığınız anda karşılaştıracak bir hedef kalmıyor ve parametre sessizce işlevsiz hale geliyor. Hata da vermiyor, uyarı da. Sadece hiçbir şey yapmıyor.
Neden aylarca fark edilmedi
Çünkü kaynakların neredeyse tamamı 9:16'dan genişti. Yatay bir video geldiğinde ölçekleme yüksekliği düşürüyor, pad de rahatça boşluk ekliyordu. Filtre bu durumda doğru çalışır.
Kaynak 9:16'dan dar olduğunda ise hesap ters yöne kaçıyor. Bu da ancak dikey çekilmiş, biraz fazla uzun bir video geldiğinde oluyor. Aylarca öyle bir dosya gelmedi.
Bunu doğrulamak için küçük bir test yazdım. Farklı oranlarda sentetik videolar üretip filtreden geçirdim:
| kaynak | eski filtre | yeni filtre |
|---|---|---|
| 1078x1920 | hata | 1080x1920 |
| 800x2000 | hata | 1080x1920 |
| 1920x1080 | geçti | 1080x1920 |
| 720x1280 | geçti | 1080x1920 |
| 1080x1080 | geçti | 1080x1920 |
Tablo her şeyi anlatıyor. 9:16'dan dar olan iki kaynak da eski filtrede patlıyor. Bu bir "bazen olan" hata değil, belirli bir en boy oranı sınıfında her zaman olan bir hata.
Doğrusu
scale=1080:1920:force_original_aspect_ratio=decrease,
pad=1080:1920:-1:-1:color=black,
setsar=1
Üç değişiklik var.
İki boyut da açıkça veriliyor, böylece decrease gerçekten devreye giriyor ve ölçekten çıkan görüntü asla 1080x1920'yi aşmıyor. Pad'in konum parametreleri -1:-1 yapıldı, ffmpeg ortalamayı kendi hesaplıyor, elle formül yazmaya gerek kalmıyor. Son olarak setsar=1 piksel oranını sabitliyor, bazı oynatıcıların görüntüyü hafifçe esnetmesini engelliyor.
Kırpma yok. Hiçbir şey kesilmiyor, sadece siyah şerit ekleniyor.
Asıl ders filtre değil
Beni üç gün yakan şey filtre değildi, capture_output eksikliğiydi. ffmpeg cevabı ilk saniyede söylüyordu, kimse dinlemiyordu.
Artık şöyle çağırıyorum:
proc = subprocess.run(komut, capture_output=True, text=True, timeout=1800)
if proc.returncode != 0:
kuyruk = "\n".join(proc.stderr.strip().splitlines()[-15:])
logger.error("ffmpeg basarisiz (kod=%s):\n%s", proc.returncode, kuyruk)
raise subprocess.CalledProcessError(proc.returncode, proc.args,
proc.stdout, proc.stderr)
Son on beş satır yeter. Hata mesajı zaten sondadır ve loga tonlarca gereksiz satır düşmez.
Dış bir programı çağıran her yerde aynı şey geçerli. check=True size sadece "başarısız oldu" der. Programın kendisi genelde tam olarak neden başarısız olduğunu da söyler, ama siz onu yakalamazsanız o bilgi hiç var olmamış gibi olur.
Kendi hattınızda deneyin
Boru hattınızda ffmpeg varsa iki dakikanızı ayırın. Şu komutla 9:16'dan dar bir test dosyası üretin ve kendi filtrenizden geçirin:
ffmpeg -f lavfi -i testsrc=size=1078x1920:rate=25:duration=2 \
-c:v libx264 -preset ultrafast test_dar.mp4
Filtreniz bu dosyada patlıyorsa aynı tuzaktasınız demektir. Patlamıyorsa da güzel, en azından artık bildiğiniz bir şey oldu.
Top comments (0)