DEV Community

Serdar Tavukçu for Serdar Tavukçu

Posted on

ffmpeg 3 Gün Boyunca Aynı Videoyu Reddetti: Sebebi 2 Pikseldi

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
Enter fullscreen mode Exit fullscreen mode

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)
Enter fullscreen mode Exit fullscreen mode

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!
Enter fullscreen mode Exit fullscreen mode

İş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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Ö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
Enter fullscreen mode Exit fullscreen mode

Üç 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)
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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)