İçeriğe geç / Skip to content / Zum Inhalt
Ahmet Balaman LogoAhmet Balaman

ffmpeg ile Telefonda Video Birleştirme: Farklı Oranlardaki Klipleri Tek Vloga Çevirmek

Ahmet Balaman
ffmpegFlutterVideoVideo İşlemeAnilogMobil GeliştirmeSıkıştırmaDart

Anılog'un ana fikri şu: arkadaş grubu gün içinde belirlediği saatlerde birkaç saniyelik klip çekiyor, gün sonunda hepsi tek bir vloga dönüşüyor.

Kulağa basit geliyor, ama girdi tahmin edilebilir değil. Aynı gün içinde şunların hepsi olabiliyor:

  • Dikey çekilmiş 2 saniyelik video
  • Yatay çekilmiş 10 saniyelik video
  • Tek kare fotoğraf
  • Sesli klip ve sessiz klip

Hepsi tek bir 1920×1080 videoda, düzgün görünecek şekilde buluşmak zorunda. Üstelik bu iş telefonda yapılıyor — sunucuda ffmpeg çalıştırmıyorum.

Neden telefonda?

Sunucu tarafında birleştirmek daha kolay olurdu. Üç sebeple yapmadım:

  1. Maliyet. Paylaşımlı hostingte ffmpeg ya yok ya da bu iş için çok yavaş.
  2. Depolama. Vlog dosyası sunucuya hiç yüklenmiyor. Bir uygulamada en büyük dosya vlog'sa, onu hiç yüklememek en büyük tasarruf.
  3. Gizlilik. "Günlük vlog cihazınızdan çıkmaz" cümlesini yazabilmek, gerçekten öyle olduğu için değerli.

Flutter tarafında ffmpeg_kit_flutter_new paketini kullandım.

Adım 1: Her klibi ortak bir çerçeveye oturtmak

Farklı oranlardaki görüntüleri birleştirmenin klasik yolu, kısa kenarları siyah bantla doldurmak. Sonuç kötü görünüyor.

Bunun yerine bulanık dolgu kullandım: aynı görüntünün büyütülüp bulanıklaştırılmış hâli arka plan oluyor, gerçek görüntü ortasına oturuyor. Instagram ve TikTok'ta gördüğünüz efekt.

Filtre zinciri şöyle:

[0:v]split=2[zemin][on];

[zemin]scale=1920:1080:force_original_aspect_ratio=increase,
       crop=1920:1080,
       gblur=sigma=28,
       eq=brightness=-0.18[bulanik];

[on]scale=1920:1080:force_original_aspect_ratio=decrease[sigan];

[bulanik][sigan]overlay=(W-w)/2:(H-h)/2,
                fps=30,setsar=1,
                format=yuv420p[v]

Okunuşu:

  • split=2 — aynı girdiyi iki kola ayırıyor.
  • Zemin kolu increase ile çerçeveyi taşacak kadar büyüyor, crop ile kesiliyor. Böylece boşluk kalmıyor.
  • gblur=sigma=28 bulanıklaştırıyor, eq=brightness=-0.18 karartıyor. Karartma olmadan arka plan öndeki görüntüyle yarışıyor.
  • Ön kol decrease ile çerçeveye sığacak kadar küçülüyor.
  • overlay ortalıyor.

setsar=1 şart. Bazı telefonlar kare olmayan piksel oranıyla kayıt yapıyor; bunu sıfırlamazsanız birleştirmede görüntü yatay olarak eziliyor.

Fotoğraflar aynı zincirden geçiyor, tek fark girişte -loop 1 -t <saniye> olması.

Adım 2: Yazıları geçirmek — ve Türkçe karakterler

Her klibin üstünde çeken kişinin adı, çekim saati ve varsa açıklaması var. drawtext filtresiyle basılıyor.

Burada erken öğrendiğim bir ders var: metni doğrudan filtre metnine yazmayın.

drawtext=text='öğle molası uzadı'   ← kırılgan

Filtre zinciri bir dizgi; içindeki : ' % \ karakterlerinin hepsi kaçış istiyor. Kullanıcının yazdığı bir açıklamada bunların hepsi olabilir. Bir kesme işareti tüm komutu bozuyor.

Çözüm textfile:

drawtext=fontfile=/.../Manrope.ttf:textfile=/.../aciklama.txt:x=76:y=h-th-64

Metin geçici bir dosyaya UTF-8 olarak yazılıyor, ffmpeg oradan okuyor. Kaçış sorunu tamamen ortadan kalkıyor.

İkinci nokta: fontfile vermezseniz ffmpeg sistemin varsayılan fontunu kullanıyor ve Türkçe karakterler kutu olarak çıkıyor. Uygulamanın kendi fontunu (Manrope, Fredoka) uygulama paketinden geçici klasöre kopyalayıp yolunu veriyorum.

Adım 3: Klipleri uç uca eklemek

Tüm klipler aynı çözünürlük, aynı kare hızı ve aynı ses formatına normalize edildikten sonra birleştirme ucuz:

-f concat -safe 0 -i liste.txt -c copy cikti.mp4

concat demuxer, -c copy ile yeniden kodlama yapmadan çalışıyor — saniyeler sürüyor. Ama yalnızca girdiler gerçekten aynıysa. Tek bir klip farklı kare hızındaysa ses ile görüntü kayıyor. Normalizasyon adımını atlamayın.

Alternatif olan concat filtresi her şeyi yeniden kodluyor ve telefonda çok daha yavaş.

Adım 4: Müzik eklemek

Kullanıcı dosyadan bir müzik seçebiliyor, kliplerin sesiyle müziğin dengesini ayrı ayrı ayarlayabiliyor. Üç sorun var:

Müzik vlogtan kısa olabilir. Girişte döngüye alınıyor:

-stream_loop -1 -i muzik.mp3

Ani başlama ve bitme kulağı rahatsız ediyor. Girişte 1 saniye, çıkışta 2 saniye yumuşama:

afade=t=in:st=0:d=1,
afade=t=out:st=<bitiş-2>:d=2

İki ses kanalı birleşmeli:

[k][m]amix=inputs=2:duration=first:dropout_transition=0[a]

duration=first önemli: müzik döngüde olduğu için süresi sonsuz sayılıyor; first demezseniz çıktı bitmiyor. dropout_transition=0 ise bir kanal sustuğunda diğerinin ani yükselmesini engelliyor.

Adım 5: Sıkıştırma — ve ölçmek

Depolama sınırlı olduğu için yüklenen klipler sıkıştırılıyor. Buradaki soru şu: kalite ne kadar düşüyor?

"Gözüme iyi göründü" bir ölçüm değil. ffmpeg'in kendi araçlarıyla ölçtüm:

ffmpeg -i orijinal.mp4 -i sikistirilmis.mp4 \
  -lavfi "psnr;[0:v][1:v]ssim" -f null -

CRF 23 ve 720p'ye ölçekleme ile gerçek bir kullanıcı klibinde çıkan sonuç:

Ölçüt Sonuç Yorum
PSNR 43,35 dB 40 dB üstü genelde "gözle ayırt edilemez" kabul edilir
SSIM 0,974 1,0 mükemmel benzerlik

Bu sayılar kararı kolaylaştırdı. Dosya boyutu ciddi biçimde düştü, kalite kaybı ölçülebilir biçimde ihmal edilebilir seviyede kaldı.

Öneri: sıkıştırma ayarını "iyi görünüyor" diyerek seçmeyin. İki komut, iki sayı, ve elinizde savunulabilir bir karar oluyor.

Kaçınılması gereken beş şey

  1. Siyah bantla doldurmak. Bulanık dolgu neredeyse aynı maliyette ve çok daha iyi görünüyor.
  2. drawtext=text= ile kullanıcı metni basmak. textfile kullanın.
  3. fontfile vermemek. Türkçe karakterler kutuya dönüyor.
  4. Normalize etmeden concat -c copy yapmak. Ses görüntüden kayıyor.
  5. setsar=1 yazmamak. Bazı cihazlarda görüntü eziliyor.

Anılog'un mimarisinin tamamı ve bu kararların bağlamı ayrı bir yazıda.

Yorumlar