1 điểm bởi GN⁺ 2024-09-08 | 1 bình luận | Chia sẻ qua WhatsApp
  • Do GitHub Pages không hỗ trợ Brotli, đây là một thử nghiệm mã hóa HTML thành ảnh WebP không mất dữ liệu rồi khôi phục bằng bộ giải mã ảnh của trình duyệt và JavaScript để giảm lượng dữ liệu truyền tải
  • Bộ giải mã Brotli bằng WASM tạo thêm chi phí 71 KiB~200 KB, còn Compression Streams API chỉ hỗ trợ gzip, deflate, deflate-raw, nên khó trở thành đường vòng để giải mã Brotli
  • WebP không mất dữ liệu VP8L có thể cho kết quả nhỏ hơn gzip ngay cả với dữ liệu dạng văn bản nhờ biến đổi dự đoán, tái sử dụng cây Huffman theo từng khối 16x16 và color cache
  • Tệp HTML thử nghiệm 439,478 byte đã được giảm xuống còn gzip 94,683 byte, WebP 43,182 byte; vẫn lớn hơn Brotli 37 KiB nhưng nhỏ hơn khoảng 2.2 lần so với gzip
  • Do nhiễu anti-fingerprinting của Canvas 2D, thay đổi với readPixels của WebGL, màn hình trắng lúc đầu và vấn đề khôi phục cuộn trang, cách này gần giống một mẹo hack phơi bày giới hạn của trình duyệt hơn là một giải pháp thực tế

Vấn đề không thể dùng Brotli trên GitHub Pages

  • Khi muốn giảm thời gian tải trang, nén HTTP đem lại hiệu quả lớn hơn việc minify HTML
  • HTTP hỗ trợ gzipBrotli qua header Content-Encoding
    • gzip rẻ nên thường được bật mặc định
    • Brotli thường có tỷ lệ nén tốt hơn gzip nhưng chậm hơn nhiều
  • GitHub Pages không hỗ trợ Brotli, nên bài dài nhất của trang là Recovering garbled Bitcoin addresses nếu dùng Brotli có thể chỉ còn 37 KiB, nhưng với gzip lại thành 92 KiB
  • Chênh lệch này khiến thời gian tải tăng 2.5 lần một cách không cần thiết

Những phương án thay thế đầu tiên và các điểm bế tắc

  • Nếu GitHub hỗ trợ tải lên và phục vụ các tệp Brotli đã nén sẵn thì có thể tránh được vấn đề, nhưng không có tính năng đó
  • Phương án giải nén trực tiếp bằng JavaScript ở phía client bị giảm lợi ích vì kích thước bộ giải mã WASM
    • brotli-dec-wasm khoảng 200 KB
    • tiny-brotli-dec-wasm71 KiB
    • Khi đó phép so sánh trở thành gzip 92 KiB với phần thân Brotli 37 KiB + 71 KiB, nên lợi thế biến mất
  • Stack HTTP của trình duyệt có bộ giải mã Brotli, nhưng DecompressionStream của Compression Streams API chỉ nhận gzip, deflate, deflate-raw
  • Ngay cả khi nén sẵn gzip bằng Zopfli thì vẫn là 86 KiB, nên vẫn lớn hơn Brotli

Dùng định dạng ảnh như một container nén

  • Trình duyệt vốn đã có thể giải mã ảnh, nên nếu nhét dữ liệu vào pixel ảnh rồi đọc lại bằng Canvas API thì không cần tự thêm logic giải nén mới
  • GIF trải dữ liệu theo thứ tự row-major rồi áp dụng LZW, nhưng DEFLATE của gzip được thiết kế để thay thế LZW nên khó kỳ vọng có lợi thế
  • PNG dùng DEFLATE, nhưng trước đó còn áp dụng biến đổi dự đoán để nén chênh lệch với các pixel lân cận thay vì nén trực tiếp pixel gốc
    • Ví dụ: nén [a, b, c, d] thay vì [a, b-a, c-b, d-c]
    • Chênh lệch giữa giá trị dự đoán và giá trị thực càng nhỏ thì càng có lợi cho nén Huffman
  • Trọng tâm của thử nghiệm là tận dụng VP8L của WebP không mất dữ liệu để nén dữ liệu byte thông thường

VP8L khác gzip ở điểm nào

  • WebP có cả biến thể mất dữ liệu và không mất dữ liệu; ở đây chỉ nói về định dạng không mất dữ liệu VP8L
  • VP8L dùng biến đổi dự đoán giống PNG, nhưng thay DEFLATE bằng một cơ chế tương tự DEFLATE do Google tạo ra
  • DEFLATE có thể chia tệp thành nhiều đoạn và dùng cây Huffman phù hợp cho từng đoạn
    • Nếu một HTML trộn JavaScript, SVG và markup thì các cây khác nhau có thể sẽ có lợi hơn
  • VP8L cho phép định nghĩa một bảng cây Huffman lớn tùy ý và dùng cây khác nhau cho từng khối pixel 16x16
    • Khi có JavaScript rồi tới CSS rồi lại JavaScript, DEFLATE có thể phải mã hóa các cây tương tự nhiều lần
    • VP8L có thể tái sử dụng cây, nên đổi cây thường xuyên hơn với chi phí thấp hơn
  • Color cache của VP8L cho phép biểu diễn ngắn các giá trị kiểu như sao chép pixel gần đây có một số thuộc tính nhất định

Thử nghiệm nén WebP đầu tiên

  • Tệp thử nghiệm là HTML của Recovering garbled Bitcoin addresses
    • Kích thước gốc: 439,478 byte
    • gzip --best: 94,683 byte
  • Dùng crate webp của Rust để biến các byte thành ảnh RGB grayscale rồi nén thành WebP không mất dữ liệu
  • Lý do dùng grayscale là vì biến đổi subtract green của WebP
    • Với grayscale, nếu trừ kênh G khỏi R/B thì R/B gần như trở thành 0
    • WebP mã hóa ba kênh bằng các cây Huffman riêng, nên các kênh có giá trị cố định sẽ gần như chỉ tốn không gian O(1)
  • Ban đầu định tạo ảnh 1xN, nhưng WebP chỉ hỗ trợ tối đa 16383x16383, nên gặp lỗi VP8_ENC_ERROR_BAD_DIMENSION
  • Sau khi đổi sang dạng 16383xN, kết quả là 45,604 byte, nhỏ hơn gzip 2 lần và còn nhỏ hơn cả bzip2 49,764 byte

Tinh chỉnh chuyên biệt cho WebP

  • Nếu dùng thứ tự row-major với ảnh rộng, trong cùng một khối 16x16 sẽ trộn lẫn các byte ở rất xa nhau trong đầu vào
  • Khi đổi hình dạng ảnh thành kiểu dọc 27x16383, kết quả nén giảm xuống 43,232 byte
  • Đã so sánh thiết lập hiệu năng nén method của cwebp từ 0~6
    • method 0: 48,902
    • method 1: 43,546
    • method 2: 43,442
    • method 3: 43,292
    • method 4: 43,232
    • method 5: 43,182
    • method 6: 43,182
  • method 5 được chọn vì cho cùng kích thước với method 6 nhưng nhanh hơn
  • Ở trạng thái này, WebP nhỏ hơn 2.2 lần so với gzip và lớn hơn 1.2 lần so với Brotli

Benchmark với nhiều tệp

  • Đối tượng so sánh là snappy testdata, Canterbury Corpus và Large Corpus, cùng 2 tệp SVG
  • Các định dạng đem so sánh là gzip --best, brotli --best, bzip2 --best và script nén WebP
  • WebP gần như luôn tốt hơn gzip, trừ vài ngoại lệ như các tệp rất nhỏ grammar.lsp, xargs.1 và một số trường hợp khác
  • Các ngoại lệ là kennedy.xlspaper-100k.pdf
    • paper-100k.pdf19 KB XML trước dữ liệu nén, nên thực tế gần như đang đo trên một lượng dữ liệu nhỏ
    • kennedy.xls cũng cho tương quan hiệu năng Brotli/bzip2 bất thường, và có thể là tệp chứa nhiều dữ liệu khác loại nằm gần nhau khiến bộ nén khó xử lý
  • WebP thường hơi kém hơn bzip2, nhưng trong một số trường hợp lại vượt lên
  • WebP luôn kém hơn Brotli, trừ những ngoại lệ như fireworks.jpeg vốn gần như là một blob ngẫu nhiên khá đồng đều
  • Với dữ liệu plain-text lớn, nó vẫn cho mức cải thiện đo được so với gzip
    • Cả tệp SVG cũng có cải thiện
    • Với html_x_4, WebP đạt tỷ lệ nén 3.3%, kém hơn Brotli 2.8% nhưng tốt hơn rất nhiều so với gzip 13%

Khôi phục bằng JavaScript

  • Việc giải mã WebP có thể triển khai bằng fetch, createImageBitmap, OffscreenCanvas, getImageData, TextDecoder
  • Cấu trúc là lấy kênh R của pixel làm byte HTML gốc, giải mã UTF-8 rồi gán vào document.documentElement.innerHTML
  • Canvas API thường bị dùng cho fingerprinting nên một số trình duyệt thêm nhiễu vào kết quả getImageData
    • Trong strict tracking protection của Firefox, dưới 1% pixel có thể bị ảnh hưởng
    • Với HTML, nhiễu đó sẽ hiện ra như lỗi gõ chữ
  • Dùng readPixels của WebGL thì vào thời điểm đó vẫn hoạt động mà không có nhiễu
    • WebGL chỉ hỗ trợ ổn định texture tối đa khoảng 2048x2048, nên lại phải điều chỉnh giới hạn kích thước
    • Mã khôi phục này sau khi minify có kích thước khoảng 550 byte
  • Tính cả WebP và đoạn mã thì tổng là 44 KiB, để so với gzip 92 KiB và Brotli 37 KiB
  • Sau ngày 15 tháng 4 năm 2026, Firefox đã thêm anti-fingerprinting cả cho readPixels, nên cách này không còn hoạt động nguyên trạng nữa

Hiện tượng nhấp nháy màn hình và vấn đề cuộn trang

  • await xử lý theo promise, nên trước khi tải xong WebP, trình duyệt sẽ cho rằng việc thực thi script đã kết thúc
  • Vì DOM vẫn còn trống, người dùng sẽ thấy một màn hình trắng trống trong thời gian ngắn
  • Để giảm bớt, có thể giữ lại CSS và khoảng 8 KiB phần đầu trang trong HTML gzip, rồi chỉ nén nội dung bên dưới viewport bằng WebP
  • Việc khôi phục vị trí cuộn khi refresh cũng gặp vấn đề
    • Ví dụ đang refresh ở vị trí Y = 5000px nhưng chiều cao trang là 0px thì vị trí sẽ bị reset
    • Thêm một div tạm rất lớn có thể giúp ích
  • Cần gán vào document.documentElement.innerHTML thay vì document.write để cập nhật tài liệu hiện tại mà không thay thế nó bằng một tài liệu mới

Nhúng WebP trực tiếp vào JavaScript

  • Để giảm thêm một chút độ trễ, có thể nhúng trực tiếp WebP vào trong JavaScript
  • Cách đơn giản nhất là base64 data URL
  • Base64 làm kích thước gốc tăng 1.33 lần, nhưng gzip gần như bù lại phần tăng đó
    • Nếu biến compressed.webp thành base64 thì được 57,576 byte
    • Nếu tiếp tục nén bằng gzip --best thì còn 43,519 byte
  • Một blob nén như WebP gần như là dữ liệu ngẫu nhiên khá đồng đều, và phép biến đổi 8-bit sang 6-bit của base64 khiến cây Huffman của gzip gần như hoạt động như một phép đảo ngược
  • Cũng có thể dùng Unicode và UTF-16, nhưng base64 vẫn là lời giải đầu tiên đủ tốt

Ứng dụng thực tế và tình trạng sau đó

  • Vào thời điểm bài viết được viết, chính trang này, nếu không phải trên trình duyệt cũ hoặc môi trường tắt JavaScript, thì đã được nén bằng WebP начиная từ phần “Fool me twice”
  • Ảnh WebP của trang trong mã thực tế có dạng cao và hẹp, nhưng bài cũng cung cấp ví dụ WebP hình vuông để dễ nhìn hơn
  • Trong ảnh, phần sáng ở trên và dưới là văn bản cùng mã, vùng gạch chéo khoảng ở mốc 1/5 là sơ đồ, còn phần lớn vùng tối là văn bản bên trong sơ đồ
  • Mức tiết kiệm thực tế là khá hạn chế
    • Trang gzip ban đầu: 88 KiB
    • Trang gzip sau khi áp dụng WebP: 83 KiB
    • Ước tính Brotli: 69 KiB
  • Sau ngày 15 tháng 4 năm 2026, để khách truy cập Firefox không thấy nội dung bị hỏng, hiện trang đã quay lại bản không nén kiểu này
  • Mã Rust, corpus và các tệp khác được công khai trên GitHub

1 bình luận

 
GN⁺ 2024-09-08
Ý kiến trên Hacker News
  • Nếu bỏ qua độ trễ thì có lẽ đúng, nhưng trong thực tế có vẻ thời gian tải chỉ tăng khoảng 0,001%
    Phần dung lượng tăng thêm không đáng kể so với độ trễ khứ hồi, và thời gian tiết kiệm được nhờ truyền ít hơn 55KiB thậm chí có thể nhỏ hơn thời gian dùng để giải nén
    Đây là một thử nghiệm thú vị, nhưng trong trường hợp này trải nghiệm người dùng có khả năng còn tệ hơn, và có lẽ chỉ giảm tính tương thích trong khi tốc độ thì gần như giữ nguyên

    • Điều đó đúng nếu chỉ tối ưu thời gian tải và giả định tốc độ dữ liệu của ai cũng như nhau, nhưng nhiều khi tôi không muốn người viết website hay ứng dụng quá dễ dàng quyết định thay tôi về đánh đổi giữa tốc độ và dữ liệu
      Vấn đề là, trong khi có những người như tác giả TFA cố gắng giảm 100KB xuống 50KB, thì cũng có những nơi thản nhiên gửi cho tôi hàng chục MB hình ảnh chỉ để xem giờ mở cửa của một nhà hàng khi tôi đang dùng dữ liệu roaming
      Ý thức về tài nguyên là có tồn tại, nhưng đáng tiếc là phân bố cực kỳ không đồng đều
    • Không chỉ là vấn đề thời gian giải nén. Chỉ sau khi tải toàn bộ xong mới có thể giải nén, trong khi trình duyệt có thể giải nén và render HTML đang được stream từ máy chủ ngay lập tức
      Nếu kết nối bị ngắt thì mất sạch, và cũng không thể đọc được dù chỉ phần đã tải xuống
      Trên kết nối thông thường thì khác biệt không đáng kể, còn trên kết nối rất chậm hoặc không ổn định đến mức 50KB là quan trọng thì cách này chắc chắn còn tệ hơn. Là một thử nghiệm vui, nhưng mong là đừng áp dụng lên website
    • Nếu chưa có trong cache thì còn có tệp Symbols-2048-em%20Nerd%20Font%20Complete.woff2 dung lượng 850K, gần như xóa nhòa khác biệt đó
    • Mức chênh lệch kích thước như vậy đủ lớn để ảnh hưởng tới số vòng khứ hồi cần thiết. Với giá trị initial congestion window hiện đại hợp lý thì ít nhất cũng phải giảm được khoảng 1 vòng khứ hồi
      Có thể không phải chênh 2,5 lần, nhưng cũng không phải 0,001%
    • Nếu mức tiết kiệm còn chưa bằng một cửa sổ nhận TCP thì sẽ không có khác biệt về độ trễ
      Trên mạng có mất gói thì có thể sẽ khác, nhưng tôi không dám chắc
  • Tôi không hiểu vì sao readPixels lại không thuộc diện chống fingerprinting. Vì nó không rải các lỗi gõ gần như không nhìn thấy lên toàn bộ trang nên với tôi thế là ổn
    Đoạn nói rằng HTML nén bằng gzip chỉ chứa style và khoảng 8KiB đầu trang, còn nội dung bên dưới viewport thì được nén bằng WebP đã giải thích vì sao bài viết lại đột ngột bị cắt giữa chừng sau một câu bất kỳ và sau đó là một trang trống
    Tôi dùng LibreWolf nên WebGL bị tắt, còn các game web ngẫu nhiên cần WebGL thì tôi dùng Chromium. Khi bật WebGL thì bài viết hoạt động tốt, và nói thật là đây là một kỹ thuật khá gọn gàng

    • Nếu nó không hoạt động trên mọi trình duyệt web hiện đại, ngay cả khi bật bảo vệ fingerprinting, và cũng không có fallback cho trình duyệt cũ, thì khó mà gọi là gọn gàng được
      WWW nên có khả năng truy cập phổ quát, bắt đầu từ HTML thông thường rồi nâng cấp dần dần
  • Cũng có thể dùng trực tiếp Brotli trong trình duyệt web, nhưng hiển nhiên là có giới hạn
    Tôi nghĩ bài dự thi JS1024 năm 2022 [1] là màn trình diễn đầu tiên của ý tưởng này, và cũng có mã proof-of-concept cho nén tùy ý. Đáng tiếc là nó không phù hợp với mục tiêu ban đầu là mã hóa độ dài
    Giới hạn cốt lõi là trên thực tế nó gần như bị giới hạn ở ký tự ASCII, và vì những lý do khá hiển nhiên, nó cực kỳ nhạy với rendering stack. Hiện tại có vẻ nó không còn hoạt động trên Firefox

    [1] https://js1024.fun/demos/2022/18/readme

    [2] https://gist.github.com/lifthrasiir/1c7f9c5a421ad39c1af19a9c...

    • Điểm mấu chốt để hiểu cách tiếp cận này là phần sau, ngay cả khi không cần đào sâu tới mức họ thực sự đã nhét dữ liệu vào như thế nào
      Chỉ có thể dùng định dạng tệp phông chữ WOFF2 mà Brotli vốn được thiết kế cho, nhưng để tận dụng điều đó thì phải tạo ra cả một tệp font hoàn chỉnh
      Các trình duyệt gần đây thường dọn dẹp font bằng OpenType Sanitizer (OTS), vì đưa trực tiếp các tệp font không đáng tin vào hệ thống là cực kỳ nguy hiểm, nên phải tạo được một tệp WOFF2 vừa đủ hợp lệ để OTS chấp nhận, vừa có thể chứa chuỗi byte mong muốn bên trong rồi trích xuất ra
      Ý tưởng chốt lại ở độ rộng glyph, tức advance, được mã hóa thành dãy số nguyên có dấu 2 byte với hầu như không có ràng buộc sau rất nhiều lần thất bại, thật sự quá xuất sắc
    • Nói chính xác hơn thì nó vẫn hoạt động trên Firefox. Chỉ là tôi quên mất rằng trên Firefox thì tỷ lệ thu phóng phải chính xác 100%
    • Kỹ thuật này thực sự đáng kinh ngạc và còn ngầu hơn nhiều so với bài viết của tôi. Xin gửi lời tán dương
  • Phía Chromium đã chặn khá lâu, nhưng zstd giờ cũng đang vào web. Cuối cùng nó đã vào Chrome, giờ chỉ còn chờ Safari theo kịp

    • Tôi muốn mọi thứ đều chuyển sang Zstandard, nhưng trong trường hợp cụ thể này thì theo tôi biết, khi mức dùng bộ nhớ của bộ giải nén như nhau thì Brotli và Zstandard gần như tương đương
    • Ít nhất có vẻ nó đã nằm trong danh sách việc cần làm: https://webkit.org/standards-positions/#position-168
  • Tôi đang làm Batch Compress(https://batchcompress.com/en) và không lâu sau khi thêm hỗ trợ WebP thì đã chuyển nó thành mặc định
    Theo tôi biết thì công cụ này vốn đã tạo ra JPEG nhỏ nhất trong số các công cụ nén web, nhưng WebP lại chỉ có kích thước bằng khoảng 50% JPEG. Vì vậy, việc đổi nó thành mặc định ngay sau khi thêm hỗ trợ là một quyết định dễ dàng
    Trang có khá nhiều người dùng, nên tôi cũng nghĩ sẽ có chút phàn nàn sau khi đổi mặc định sang WebP, nhưng đến nay sau khoảng một tháng thì chỉ có đúng một câu hỏi hay phàn nàn liên quan tới WebP
    Giờ có vẻ gần như mọi công cụ và trình duyệt đều hỗ trợ WebP. Gần đây tôi chỉ thấy đúng một website không xử lý chuẩn việc tải ảnh WebP lên nên bị chặn ở bước tiếp theo, còn dạo này thì hầu như đâu cũng hỗ trợ tốt

    • Nếu WebP giúp giảm hơn 15~20% kích thước tệp so với JPEG, thì phần tiết kiệm đó đến từ suy giảm chất lượng chứ không phải cải thiện nén
      Nếu JPEG được nén và tối ưu tốt thì không nên thua WebP quá nhiều
      Lúc nào cũng có thể tạo ra WebP trông gần như y hệt JPEG để giảm kích thước tệp, nhưng nếu nén lại thành JPEG trông gần như y hệt thì cũng vậy thôi
      Đây là đặc tính của mọi codec nén mất dữ liệu; khi chất lượng tăng lên thì kích thước tệp tăng theo hàm mũ, nên mọi người luôn ngạc nhiên khi chỉ một mức giảm chất lượng rất nhỏ, gần như không nhìn ra, lại có thể làm dung lượng thay đổi đáng kể
    • Tôi thắc mắc con số WebP chỉ bằng khoảng 50% kích thước của JPEG dựa trên chỉ số so sánh chất lượng nào
      WebP từng nổi tiếng với các giá trị mặc định tệ hại làm hỏng chi tiết ở vùng tối
  • Khi xem mã nguồn, tôi thấy khai báo doctype bị thiếu khoảng trắng. Dạng hiện tại là sai và cần có khoảng trắng

  • Tôi từng dùng mẹo này trước đây. Lạ là tôi không nhớ mình đã dùng cho việc gì, nhưng có lẽ chỉ để xem liệu nó có khả thi không, và tôi cũng từng để lại bình luận ở đây: https://gist.github.com/gasman/2560551?permalink_comment_id=...
    Tôi còn tìm lại được một nguyên mẫu cũ, có lẽ đúng là chỉ để thử nghiệm: https://retr0.id/stuff/bee_movie.webp.html

    • Trang đó làm hỏng tiện ích cử chỉ chuột của tôi
      Giờ thì mấy thứ kiểu chèn script như vậy được gọi là extension chứ không còn là addon nữa, nhưng dù sao thì cách tiếp cận ban đầu — truyền vào “rác” rồi nối JS ở phía sau để quay lại thành trang — vẫn khá thú vị
      Phần con người mê bảo mật trong tôi tự hỏi liệu điều này có thể mở ra khả năng tấn công khi có dữ liệu do người dùng cung cấp, như biểu mẫu bình luận, hay không
      Tôi tự hỏi liệu ai đó có thể tìm ra một chuỗi byte để nhét vào bình luận, rồi sau khi nén nó biến thành thẻ script nằm trước script của tôi và được thực thi hay không
    • Theo kinh nghiệm của tôi, WebP không hợp lắm với trường hợp phổ biến mà kỹ thuật này thực sự hữu ích, tức là dữ liệu dưới 10KB
      Phần lớn lợi thế của WebP không mất dữ liệu so với PNG nằm ở mô hình hóa chứ không phải mã hóa, trong khi kiểu nén văn bản này chỉ tận dụng phần mã hóa của WebP
  • Nếu bỏ Google Fonts thì thời gian tải trang cũng sẽ cải thiện đôi chút, vì nó được tải từ máy chủ từ xa và cần thêm một lần bắt tay kết nối

    • Nhưng nếu đủ nhiều website khác cũng dùng phông chữ đó thì có thể nó đã có sẵn cục bộ rồi
  • Trang này bị lỗi, ít nhất là trên trình duyệt Sailfish OS. Có một khoảng trắng dài sau đoạn sau
    “Alright, so we’re dealing with 92 KiB for gzip vs 37 + 71 KiB for Brotli. Umm…”
    Dù vậy, phần overhead của nén HTML bằng gzip và Brotli chẳng đáng là bao so với lượng JS, hình ảnh và video mà website ngày nay sử dụng

    • Orion, Safari và LibreWolf cũng bị như vậy. Đây là trang chỉ dành cho Chrome à?
    • Mull cũng vậy
  • Cá nhân tôi không thích định dạng này lắm. Khi lưu ảnh mà nó thành WebP, ngoài trình duyệt web ra thì gần như chẳng có chỗ nào hỗ trợ, nên trước khi chỉnh sửa hay dùng cho ra hồn tôi lại phải chuyển đổi nó
    Cảm giác như bị ép thêm một bước không cần thiết

    • Trớ trêu là ngay cả Slides của Google cũng không hỗ trợ ảnh WebP
      Nhưng nếu mức hỗ trợ tăng thêm thì chắc cũng ổn. Cứ 20 năm mới có một định dạng mới thì vẫn chịu được
      .webm thì có biến mất cũng được
    • Chuyển đổi mất có 2 giây. Trên macOS thì nó nằm ngay trong menu chuột phải theo đúng nghĩa đen, mà dung lượng lại còn nhỏ hơn, nên chẳng có gì đáng ngại cả