2-pass loudnorm ses eşitleme + 4sn segment + v2 audio filtreler
Kod değişiklikleri + bağımsız re-encode script
Bu değişiklikler test sunucusunda (mztest.muzibu.com) uygulandı. Production'a git pull ile taşınacak.
ConvertToHLSJob.php
Audio filtreler v1→v2: lowpass/stereotools/treble cut kaldırıldı (hışırtı nedeni). 2-pass loudnorm eklendi — HLSService::buildTwoPassFilter() kullanıyor.
AddHlsVariantsCommand.php
reEncodeHigh() metodu 2-pass loudnorm kullanıyor. --re-encode-high flag ile high playlist'i 4sn segment ile yeniden oluşturuyor.
HLSService.php
buildTwoPassFilter(string $inputPath): string — Merkezi 2-pass loudnorm filtre oluşturucu. Pass 1: FFmpeg ile ses seviyesi ölçümü. Pass 2: Ölçülen değerlerle hassas normalizasyon. Hem job hem command bu metodu kullanır.
hls-streaming.blade.php
Dokümantasyon güncellendi: "EQ + LP Filter" → "Loudnorm v2 + Bass EQ". v2 filtre zinciri yansıtıldı.
loudnorm=I=-16:TP=-1.5:LRA=14:measured_I=X:measured_TP=X:measured_LRA=X:measured_thresh=X:linear=false,equalizer=f=100:t=q:w=1:g=1,alimiter=limit=0.95:attack=5:release=50
| Kontrol | Sonuç | Durum |
|---|---|---|
| master.m3u8 | 237/237 | Tamam |
| enc.bin | 237/237 | Tamam |
| enc.keyinfo | 237/237 | Tamam |
| high (ana playlist) | 237/237 | Tamam |
| ultralow (32k) | 237/237 | Tamam |
| low (64k) | 237/237 | Tamam |
| mid (128k) | 237/237 | Tamam |
| VOD tipi | 237/237 | Tamam |
| enc.keyinfo URI (/hls-key/) | 237/237 | Tamam |
| Segment süresi (≤4.01s) | 237/237 | Tamam |
| MP3 128k | 149/237 | Kısmi* |
* 88 yeni şarkı henüz MP3 128k üretilmemiş — re-encode script bunu da yapacak.
Sorun: Şarkılar arasında ses seviyesi farkı var. Bazıları patlıyor, bazıları çok kısık. Eski filtreler (lowpass, stereotools) hışırtı yapıyordu.
Çözüm: Her şarkıyı iki kere ölçüp (2-pass) aynı ses seviyesine getiren bir script. Yeni şarkı yüklemelerinde de otomatik 2-pass kullanılıyor. Hışırtı yapan filtreler kaldırıldı.
Süre: 3 paralel terminal ile ~15 saat (gece başlatılabilir).
Risk: Sıfır. Orijinal MP3'ler korunuyor. Sorun çıkarsa script'i durdur, eski dosyalar yerinde.
Orijinal (DOKUNULMAZ) storage/tenant1001/app/public/muzibu/songs/song_xxxxx.mp3 Re-encode Edilenler (script bunları üretir) storage/tenant1001/app/public/muzibu/hls/{song_id}/ ├── playlist.m3u8 ← high kalite (orijinal bitrate, 4sn segment, VOD) ├── segment-*.ts ← high segment'ler (AES-128 şifreli) ├── ultralow/playlist.m3u8 ← 32kbps, mono, 22050Hz ├── low/playlist.m3u8 ← 64kbps, mono, 22050Hz ├── mid/playlist.m3u8 ← 128kbps, stereo, 44100Hz ├── master.m3u8 ← 4 varyant referansı ├── enc.bin ← DOKUNULMAZ (encryption key) └── enc.keyinfo ← DOKUNULMAZ (key URI + path + IV) storage/tenant1001/app/public/muzibu/songs/ ├── mp3_128/{song_id}.mp3 ← 128kbps MP3 fallback └── mp3_64/{song_id}.mp3 ← 64kbps MP3 son çare fallback
Önce test sunucusundaki kod değişikliklerini production'a taşı:
cd /var/www/vhosts/muzibu.com/httpdocs/ git pull origin main # Cache temizle php artisan cache:clear php artisan config:clear php artisan view:clear php artisan responsecache:clear
Script zaten git repo'da: re-encode-songs.php. git pull ile gelecek.
Gelmediyse, test sunucusundan kopyala:
scp mztest:/var/www/vhosts/mztest.muzibu.com/httpdocs/re-encode-songs.php \
/var/www/vhosts/muzibu.com/httpdocs/re-encode-songs.php
# Dry-run: Kaç şarkı var? php re-encode-songs.php --dry-run # Tek şarkıyla test et php re-encode-songs.php --song=BİR_ŞARKI_ID
[1/1] Song #XXXXX (ETA: ?dk) 🔄 High re-encode... ✅ 🔄 ultralow... ✅ 🔄 low... ✅ 🔄 mid... ✅ 📋 master.m3u8 ✅ 🔄 MP3 128k... ✅ 🔄 MP3 64k... ✅ ================================================== ✅ Tamamlandı: 1 başarılı, 0 başarısız (X.X dk)
1. Script çalıştı mı? (Evet/Hayır) Varsa hata mesajını yapıştır. 2. Çıktıdaki tüm satırlar ✅ mi? ❌ olan varsa hangisi? 3. Süre ne kadar sürdü? (X.X dk) 4. Sunucu PHP versiyonu: php -v | head -1 5. FFmpeg versiyonu: ffmpeg -version | head -1 6. Toplam HLS'li şarkı sayısı: php re-encode-songs.php --dry-run
php re-encode-songs.php --limit=10
Hepsi ✅ ise devam. ❌ varsa DURMA, hata mesajını paylaş.
Her terminali screen veya tmux içinde aç (SSH kopsa bile devam etsin):
# Terminal 1 screen -S encode1 php re-encode-songs.php --offset=0 --limit=11000 # Terminal 2 screen -S encode2 php re-encode-songs.php --offset=11000 --limit=11000 # Terminal 3 screen -S encode3 php re-encode-songs.php --offset=22000 --limit=11000
screen ipuçları:
Ctrl+A D → Oturumu arkada bırak (detach)
screen -r encode1 → Tekrar bağlan
screen -ls → Tüm oturumları listele
HLSDIR="storage/tenant1001/app/public/muzibu/hls"
SONGDIR="storage/tenant1001/app/public/muzibu/songs"
echo "HLS klasör: $(ls -d $HLSDIR/*/ | wc -l)"
echo "ultralow: $(find $HLSDIR -maxdepth 2 -name ultralow -type d | wc -l)"
echo "low: $(find $HLSDIR -maxdepth 2 -name low -type d | wc -l)"
echo "mid: $(find $HLSDIR -maxdepth 2 -name mid -type d | wc -l)"
echo "master: $(find $HLSDIR -name master.m3u8 | wc -l)"
echo "mp3_128: $(ls $SONGDIR/mp3_128/*.mp3 2>/dev/null | wc -l)"
echo "mp3_64: $(ls $SONGDIR/mp3_64/*.mp3 2>/dev/null | wc -l)"
# Segment süresi doğrulama (rastgele 5 şarkı)
echo ""
echo "Segment süreleri:"
for dir in $(ls -d $HLSDIR/*/ | shuf | head -5); do
ID=$(basename $dir)
MAX=$(grep '#EXTINF:' "$dir/playlist.m3u8" | sed 's/#EXTINF:\([0-9.]*\),.*/\1/' | sort -n | tail -1)
echo " Song #$ID: ${MAX}s"
done
# Script'i sil (güvenlik) rm re-encode-songs.php # Cache temizle php artisan cache:clear php artisan view:clear php artisan responsecache:clear
Bağımsız script — Laravel kodlarını değiştirmeden tüm şarkıları yeniden encode eder.
Raw dosya: re-encode-songs.txt
php re-encode-songs.php # Tüm şarkılar php re-encode-songs.php --limit=100 # İlk 100 şarkı php re-encode-songs.php --offset=100 --limit=100 # 101-200 arası php re-encode-songs.php --dry-run # Sadece say, encode yapma php re-encode-songs.php --skip-high # High re-encode atla php re-encode-songs.php --only-mp3 # Sadece MP3 64k+128k üret php re-encode-songs.php --song=34455 # Tek şarkı test
| Şarkı Sayısı | 1 Terminal | 3 Paralel |
|---|---|---|
| 1 şarkı | ~2 dk | — |
| 10 şarkı | ~20 dk | — |
| 1.000 şarkı | ~33 saat | ~11 saat |
| ~32.000 şarkı | ~44 saat | ~15 saat |
* 2-pass loudnorm olduğu için her şarkı ~2x FFmpeg çalıştırır (ölçüm + encode). Test sunucusu ölçümü: 1 şarkı = ~2 dk.
O şarkının HLS encryption dosyası eksik. --skip-high ile devam edebilirsin, sadece variant ve MP3 üretir.
Orijinal MP3 dosyası silinmiş. O şarkıyı atlar, devam eder.
ffmpeg -version ile versiyon kontrol et. Minimum 4.x gerekli. loudnorm filtresi 3.1+ gerektirir.
2-pass'ın Pass 1'i başarısız olmuş, tek geçiş fallback kullanıldı. Çoğunlukla sorun değil — FFmpeg 4.x'te nadiren olur. Çok sık çıkıyorsa FFmpeg versiyonunu kontrol et.
Sorun yok. Aynı komutu tekrar çalıştır — script mevcut dosyaları siler ve yeniden oluşturur. Kaldığı yerden devam etmek için --offset kullan.
Orijinal MP3'ler yerinde. Eski HLS üzerine yazıldı. Eski haline döndürmek için eski filtreli script ile tekrar encode gerekir (ama genellikle gerekmez).
-map 0:a -c:a aac -b:a {orijinal_bitrate}k -profile:a aac_low -ar 48000 -ac 2
-af "loudnorm=I=-16:TP=-1.5:LRA=14:measured_*=...,equalizer=f=100:t=q:w=1:g=1,alimiter=limit=0.95:attack=5:release=50"
-hls_time 4 -hls_list_size 0 -hls_playlist_type vod -hls_key_info_file {enc.keyinfo}
-c:a aac -b:a 32k -ar 22050 -ac 1 -vn -hls_time 4 -hls_playlist_type vod
-c:a aac -b:a 64k -ar 22050 -ac 1 -vn -hls_time 4 -hls_playlist_type vod
-c:a aac -b:a 128k -ar 44100 -ac 2 -vn -hls_time 4 -hls_playlist_type vod
-b:a 128k -ar 44100 -ac 2 -map_metadata -1 -vn -y
Kod rollback: git revert HEAD ve cache temizle.
Re-encode iptali: Script'i durdur (Ctrl+C). İşlenmiş şarkılar yeni filtrelerle, işlenmemişler eski filtrelerle kalır. Sorun yok — dinleyici fark etmez.
Tamamen eski haline dön: Eski filtrelerle (v1) re-encode script yaz ve tekrar çalıştır. Ama v2 filtreler daha iyi olduğu için bu genellikle gerekmez.