deniz.in

Piyasalar

Hava durumu

Hava durumu yükleniyor

· kaynak dev.to (home feed)

iOS Safari, .mov ses dosyalarını container içindeki iki baytlık sürüm alanı yüzünden açamıyor

dev.to'da yayımlanan bir yazı, iOS Safari'deki .mov çözme hatalarının %100'ünü QuickTime'ın ses örnek girdisindeki iki baytlık sürüm alanına bağlıyor; çözüm ise dosyayı yeniden kodlamadan tarayıcıda container'ı yeniden inşa etmek.

iOS Safari, .mov ses dosyalarını container içindeki iki baytlık sürüm alanı yüzünden açamıyor

Görmezden gelemeyeceğiniz kadar temiz bir hata deseni

transformers.js aracılığıyla Whisper'ı yerel olarak çalıştıran tarayıcı tabanlı bir transkripsiyon aracı, analitiğinde tuhaf bir şey fark etti: mobil kullanıcılardan gelen her .mov dosyası çözme aşamasında başarısız olurken, masaüstü oturumlarında tek bir .mov hatası kaydedilmemişti. dev.to'daki bir yazıya göre yazar, sorunu iOS 18.7 ve Safari 26.5 çalıştıran bir iPhone 17 Pro simülatöründe yeniden üretti. Aynı AAC ses parçası, aynı şekilde kodlanmış halde .mp4 olarak sorunsuz çözülürken .mov olarak sarıldığında AudioContext.decodeAudioData'dan EncodingError fırlatıyordu. Chromium ise her iki dosyayı da işledi. Bu, codec'i eler ve şüpheyi doğrudan container'a yönlendirir.

moov içindeki iki bayt

İlk şüpheli — ftyp kutusundaki dört karakterli brand, qt ile isom — suçsuz çıktı. Brand'ı yeniden yazmak hiçbir şeyi değiştirmedi, çünkü Safari ona bakmıyor. Gerçek fark kutut ağacının daha derinlerinde: önce moov, ardından trak, mdia, minf, stbl ve son olarak çözücüye sesin nasıl kodlandığını söyleyen örnek açıklaması stsd'de.

Her iki dosya da bir mp4a girdisi taşıyor ama aynı girdi değil. QuickTime girdisini sürüm 1 olarak işaretliyor, -2 değerinde bir sıkıştırma kimliği yazıyor, 16 baytlık sürüm 1 uzantı verisi ekliyor, esds temel akış tanımlayıcısını bir wave kutusu içine yerleştiriyor ve bir chan kanal düzeni kutusu ekliyor. Standart MP4 ise sürüm 0 yazar, sıkıştırma kimliği 0'dır ve esds'yı doğrudan mp4a altına koyar.

Yazarın sonuçu: iOS Safari'nin decodeAudioData'sı yalnızca sürüm 0 ses örnek girdilerini kabul ediyor, Chromium ise ikisini de kabul ediyor. Sürüm alanı bir uint16 olduğundan, dosyanın çalınıp çalınmayacağına iki bayt karar veriyor — ve masaüstü kullanıcılarının bu hatayı hiç görmemesinin nedenini de açıklıyor.

Yeniden kodlamak yerine container'ı yeniden inşa etmek

AAC bit akışı zaten geçerli olduğu için hiçbir şeyin transcode edilmesi gerekmiyor. Düzeltme, moov'u bulmak için mdat'yı okumadan en üst düzey kutu başlıklarını tarıyor, ses parçasının örnek tablolarını (stsd, stts, stsc, stsz, stco veya co64) ayrıştırıyor, ses örneklerini 8 MB'lık bir kayan pencereyle kopyalıyor ve tarayıcının yerel çözücüsüne vermeden önce örnek açıklaması sürüm 0'a sabitlenmiş, yalnızca ses içeren yeni bir MP4 yazıyor.

Bu, iki ağır alternatifi devre dışı bırakıyor: container düzeyindeki bir sorunu çözmek için çok megabaytlık bir ffmpeg.wasm indirmeye gerek yok ve iOS 17+'taki AudioDecoder sürüm tabanını miras alacak WebCodecs'a da gerek yok.

Ayrıştırmada dikkat edilmesi gereken tuzaklar var. esds araması tüm kardeşleri tarayıp sonra özyineleme yapmalı, yoksa wave içine yerleştirilmiş bir tanımlayıcı istediğinizi gölgeleyebilir. Alt kutu offsetleri de girdi sürümüne göre değişir — sürüm 1 için 16 ekstra bayt, gerçek örnek hızını bir float64 içinde taşıyan sürüm 2 için 36 bayt. Bu offsetleri yanlış hesaplarsanız ayrıştırıcı çöp veriyi kutu başlığı olarak okumaya başlar.

Yol boyunca keşfedilen bellek hatası

Eski kod dosyanın tamamını belleğe okuyordu ve araç kayıtlarındaki mobil yüklemeler ortalama 161,9 MB'idi — bunun yaklaşık %99'u bir transkript için alakasız video kareleriydi. Bunu eşit uzunlukta bir PCM tamponuna çözümlemek, iOS Safari'nin bellek sınırlarını tetikleme riski taşıyordu. Yalnızca başlık taraması ve kayan pencere, en yüksek kullanımı yaklaşık 8 MB artı sesin kendisiyle sınırlıyor.

Bildirilen sayılar: Doğal olarak başarısız olan 158,6 MB'lık, 15 dakikalık bir .mov, 378 ms'de 13,88 MB'lık bir ses parçası üretti ve 476 ms'de çözüldü; uçtan uca toplam 854 ms. Çıktının sessiz olmadığı ve uzunluğunun doğru olduğu doğrulandı (900,023 sn, 900,1 sn ile eşleşti). Daha küçük test dosyaları tek haneli milisaniyelerde çıkarıldı ve .m4a ile .mp4 girdilerinde geri dönüş gözlemlenmedi.

Önce fallback tasarımı

Her adım, gerçekler varsayımlarla eşleşmeyi bıraktığı anda null döndürüyor — parçalı MP4, .mov içinde bir PCM parçası ya da hiç ses parçası olmayan bir .mov — ve çağıran taraf orijinal doğrudan çözme yoluna geri düşüyor. Temel kural: Kesin başarısızlıkları kurtarmak için kurulmuş bir modül, çalışan bir durumu asla kötüleştirmemeli.

Neden önemli

Container toleransı, codec desteğine kıyasla çok daha az belgelenmiştir; bu yüzden bir format bir tarayıcıda çalışıp diğerinde başarısız oluyorsa, codec'ten önce container şüphelenmeyi hak eder. Yazı ayrıca ffmpeg.wasm refleksine karşı yararlı bir denge unsuru: bit akışı zaten geçerliyse iş container cerrahisidir, medya işleme değil. Ve bir dosyayı çözmek için tamamını okumak, bugün çökmesa bile mobilde bir hatadır. Söz konusu araç TranscriptSnap için Whisper tamamen cihaz üzerinde çalışıyor — bir Safari container tuhaflığının neden sunucunun değil uygulamanın sorunu haline geldiği ve herhangi bir tarayıcı yerel ses veya video aracının aynı sınıfta hatalar bekleyebileceği tam da bu yüzden. Düzeltme devreye girdikten sonra ekip, dosya boyutunun artık gerçek bir riskle ilişkili olmadığı için "büyük .mov dosyaları başarısız olabilir" uyarı bandını kaldırdı.

  • #ios-safari
  • #web-audio
  • #mp4
  • #container-format
  • #browser-compatibility