Vượt quá hạn mức lưu vào bộ nhớ đệm

Liên khúc Joe
Joe Medley

Nếu đang sử dụng Tiện ích nguồn nội dung đa phương tiện (MSE), thì bạn cần giải quyết một vấn đề là bộ đệm quá đầy. Khi điều này xảy ra, bạn sẽ nhận được QuotaExceededError (được gọi là QuotaExceededError). Trong bài viết này, tôi sẽ đề cập đến một số cách để xử lý vấn đề này.

Hạn mức vượt quáError là gì?

Về cơ bản, QuotaExceededError là chế độ bạn nhận được nếu cố gắng thêm quá nhiều dữ liệu vào đối tượng SourceBuffer. (Việc thêm các đối tượng SourceBuffer khác vào phần tử MediaSource mẹ cũng có thể tạo ra lỗi này. Điều đó nằm ngoài phạm vi của bài viết này.) Nếu SourceBuffer có quá nhiều dữ liệu, việc gọi SourceBuffer.appendBuffer() sẽ kích hoạt thông báo sau trong cửa sổ bảng điều khiển của Chrome.

Lỗi bảng điều khiển hạn mức.

Có một vài điều cần lưu ý về việc này. Trước tiên, hãy lưu ý rằng tên QuotaExceededError không xuất hiện ở vị trí nào trong thông báo. Để thấy được điều đó, hãy đặt một điểm ngắt ở vị trí mà bạn có thể phát hiện lỗi và kiểm tra lỗi đó trong cửa sổ phạm vi hoặc đồng hồ của mình. Tôi cho thấy thông tin này ở bên dưới.

Cửa sổ xem hạn mức.

Thứ hai, không có cách cuối cùng để tìm hiểu lượng dữ liệu mà SourceBuffer có thể xử lý.

Hành vi trong các trình duyệt khác

Tại thời điểm viết, Safari không gửi QuotaExceededError trong nhiều bản dựng của nó. Thay vào đó, công cụ này sẽ xoá các khung hình bằng thuật toán 2 bước và dừng lại nếu có đủ khoảng trống để xử lý appendBuffer(). Thứ nhất, tính năng này giải phóng khung hình từ 0 đến 30 giây trước thời gian hiện tại trong 30 giây. Tiếp theo, công cụ này giải phóng các khung hình trong khoảng thời gian 30 giây từ thời lượng trở về trước đến gần 30 giây sau currentTime. Bạn có thể đọc thêm về thay đổi này trong bộ thay đổi của Bộ công cụ web từ năm 2014.

Rất may là lỗi này cùng với Chrome, Edge và Firefox. Nếu đang sử dụng một trình duyệt khác, bạn cần thực hiện kiểm thử của riêng mình. Mặc dù có thể không phải là nội dung bạn sẽ xây dựng cho trình phát nội dung đa phương tiện thực tế, nhưng ít nhất thì bài kiểm thử giới hạn vùng đệm nguồn của François Beaufort cho phép bạn quan sát hành vi.

Tôi có thể thêm bao nhiêu dữ liệu?

Số điện thoại chính xác sẽ khác nhau tuỳ theo trình duyệt. Vì không thể truy vấn lượng dữ liệu hiện đã được thêm, nên bạn sẽ phải theo dõi số lượng dữ liệu mình đang thêm. Đối với nội dung cần xem, đây là dữ liệu tốt nhất mà tôi có thể thu thập được tại thời điểm viết. Đối với Chrome, các con số này là giới hạn trên, nghĩa là chúng có thể nhỏ hơn khi hệ thống gặp áp lực về bộ nhớ.

Chrome Chromecast* Firefox Safari Edge
Video 150MB 30MB 100MB 290MB Không xác định
Âm thanh 12MB 2MB 15MB 14MB Không xác định
  • Hoặc thiết bị Chrome có bộ nhớ hạn chế khác.

Vậy tôi nên làm gì?

Vì lượng dữ liệu được hỗ trợ rất khác nhau và bạn không thể tìm thấy lượng dữ liệu trong SourceBuffer, nên bạn phải nhận dữ liệu gián tiếp bằng cách xử lý QuotaExceededError. Giờ hãy xem xét một số cách để thực hiện điều đó.

Có một số phương pháp để xử lý QuotaExceededError. Trong thực tế, việc kết hợp một hoặc nhiều phương pháp là tốt nhất. Cách tiếp cận của bạn nên là dựa vào lượng dữ liệu bạn đang tìm nạp và cố gắng thêm ngoài HTMLMediaElement.currentTime và điều chỉnh kích thước đó dựa trên QuotaExceededError. Ngoài ra, việc sử dụng một tệp kê khai dưới dạng tệp mpd (MPEG-DASH) hoặc tệp m3u8 (HLS) có thể giúp bạn theo dõi dữ liệu mà bạn sẽ thêm vào vùng đệm.

Bây giờ, hãy xem một số phương pháp để xử lý QuotaExceededError.

  • Xoá dữ liệu không cần thiết và nối lại.
  • Thêm các mảnh nhỏ hơn.
  • Giảm độ phân giải phát.

Mặc dù có thể sử dụng kết hợp, nhưng tôi sẽ đề cập đến từng phương pháp một.

Xoá dữ liệu không cần thiết và nối lại

Thực sự thì câu lệnh này sẽ được gọi là "Xoá dữ liệu ít có khả năng sẽ được sử dụng lại, sau đó thử thêm lại dữ liệu có khả năng sẽ được sử dụng trong tương lai gần." Tiêu đề quá dài. Bạn chỉ cần nhớ điều tôi thực sự muốn nói.

Việc xoá dữ liệu gần đây không đơn giản như việc gọi SourceBuffer.remove(). Để xoá dữ liệu khỏi SourceBuffer, cờ cập nhật phải là false. Nếu không, hãy gọi SourceBuffer.abort() trước khi xoá bất kỳ dữ liệu nào.

Có một vài điều cần lưu ý khi gọi SourceBuffer.remove().

  • Điều này có thể gây ảnh hưởng tiêu cực đến việc phát video. Ví dụ: nếu bạn muốn video sớm phát lại hoặc lặp lại, có thể bạn không muốn xoá phần đầu video. Tương tự, nếu bạn hoặc người dùng tìm kiếm một phần video mà bạn đã xoá dữ liệu, thì bạn sẽ phải nối lại dữ liệu đó một lần nữa để đáp ứng yêu cầu tìm kiếm đó.
  • Hãy thận trọng khi xoá. Hãy lưu ý khi xoá nhóm khung hình hiện đang phát bắt đầu tại khung hình chính tại hoặc trước currentTime, vì làm như vậy có thể gây gián đoạn quá trình phát. Thông tin như vậy có thể cần được ứng dụng web phân tích cú pháp từ luồng byte nếu không có trong tệp kê khai. Tệp kê khai nội dung đa phương tiện hoặc kiến thức ứng dụng về các khoảng thời gian khung hình chính trong nội dung đa phương tiện có thể giúp hướng dẫn ứng dụng của bạn lựa chọn phạm vi xoá để ngăn việc xoá nội dung đa phương tiện hiện đang phát. Bất kể bạn xoá nội dung gì, không xoá nhóm hình ảnh hiện đang phát hoặc thậm chí là một vài hình ảnh đầu tiên ngoài nhóm ảnh đó. Nhìn chung, đừng xoá vượt quá thời gian hiện tại trừ phi bạn chắc chắn rằng nội dung nghe nhìn không còn cần thiết nữa. Nếu xoá gần con trỏ phát, bạn có thể gây ra lỗi.
  • Safari 9 và Safari 10 không triển khai chính xác SourceBuffer.abort(). Trên thực tế, các trình phát này sẽ gửi các lỗi khiến quá trình phát bị dừng lại. Thật may là có các trình theo dõi lỗi đang mở tại đâytại đây. Trong thời gian chờ đợi, bạn sẽ phải xử lý vấn đề này bằng cách nào đó. Shaka Player thực hiện việc này bằng cách loại bỏ hàm abort() trống trên các phiên bản Safari đó.

Thêm các mảnh nhỏ hơn

Tôi đã xem quy trình dưới đây. Phương thức này có thể không hiệu quả trong mọi trường hợp, nhưng có một ưu điểm là bạn có thể điều chỉnh kích thước của các đoạn nhỏ hơn cho phù hợp với nhu cầu của mình. Tính năng này cũng không yêu cầu quay lại mạng, do đó có thể làm phát sinh thêm phí dữ liệu đối với một số người dùng.

const pieces = new Uint8Array([data]);
(function appendFragments(pieces) {
    if (sourceBuffer.updating) {
    return;
    }
    pieces.forEach(piece => {
    try {
        sourceBuffer.appendBuffer(piece);
    }
    catch e {
        if (e.name !== 'QuotaExceededError') {
        throw e;
        }

        // Reduction schedule: 80%, 60%, 40%, 20%, 16%, 12%, 8%, 4%, fail.
        const reduction = pieces[0].byteLength * 0.8;
        if (reduction / data.byteLength < 0.04) {
        throw new Error('MediaSource threw QuotaExceededError too many times');
        }
        const newPieces = [
        pieces[0].slice(0, reduction),
        pieces[0].slice(reduction, pieces[0].byteLength)
        ];
        pieces.splice(0, 1, newPieces[0], newPieces[1]);
        appendBuffer(pieces);  
    }
    });
})(pieces);

Giảm độ phân giải phát

Điều này tương tự như việc xoá dữ liệu gần đây và thêm lại. Trên thực tế, hai cách này có thể được thực hiện cùng nhau, mặc dù ví dụ bên dưới chỉ cho thấy việc giảm độ phân giải.

Có một vài điều cần lưu ý khi sử dụng kỹ thuật này:

  • Bạn phải thêm một phân đoạn khởi động mới. Bạn phải thực hiện việc này bất cứ khi nào thay đổi đại diện. Phân đoạn khởi động mới phải dành cho các phân đoạn nội dung đa phương tiện theo sau.
  • Dấu thời gian trình bày của nội dung nghe nhìn được nối phải khớp với dấu thời gian của dữ liệu trong vùng đệm càng chính xác càng tốt, nhưng không được vượt quá. Việc chồng chéo dữ liệu được lưu vào vùng đệm có thể gây ra tình trạng kết nối hoặc gián đoạn ngắn tuỳ thuộc vào trình duyệt. Bất kể nội dung bạn thêm vào là gì, đừng chồng chéo con trỏ vị trí vì thao tác này sẽ tạo ra lỗi.
  • Việc tìm kiếm có thể làm gián đoạn quá trình phát video. Có thể bạn sẽ muốn tìm một vị trí cụ thể và tiếp tục phát từ đó. Xin lưu ý rằng việc này sẽ khiến việc phát nội dung bị gián đoạn cho đến khi hoàn tất tìm kiếm.