Tiện ích nguồn phương tiện cho âm thanh

Dale Curtis
Dale Curtis

Giới thiệu

Tiện ích nguồn phương tiện (MSE) cung cấp khả năng lưu vào bộ đệm và điều khiển phát mở rộng cho các phần tử HTML5 <audio><video>. Mặc dù ban đầu được phát triển để hỗ trợ các trình phát video dựa trên tính năng Phát trực tuyến thích ứng động qua HTTP (DASH), nhưng ở bên dưới, chúng ta sẽ tìm hiểu cách sử dụng tính năng này cho âm thanh, đặc biệt là cho tính năng phát không gián đoạn.

Hẳn bạn đã nghe một đĩa nhạc có các bài hát phát liền mạch giữa các bản nhạc; thậm chí bạn có thể đang nghe một đĩa nhạc ngay lúc này. Các nghệ sĩ tạo ra những trải nghiệm phát lại không gián đoạn này vừa là một tác phẩm nghệ thuật, vừa là một đồ tạo tác từ đĩa nhạcvinylCD, trong đó âm thanh được viết liên tục. Thật không may, do cách thức hoạt động của các bộ mã hoá và giải mã âm thanh hiện đại như MP3AAC, trải nghiệm âm thanh liền mạch này thường bị mất đi ngày nay.

Chúng ta sẽ đi vào chi tiết về lý do ở bên dưới, nhưng bây giờ hãy bắt đầu với phần minh hoạ. Dưới đây là 30 giây đầu tiên của tệp Sintel xuất sắc được cắt thành năm tệp MP3 riêng biệt và tập hợp lại bằng MSE. Các đường màu đỏ biểu thị các khoảng trống được tạo ra trong quá trình tạo (mã hoá) mỗi MP3; bạn sẽ nghe thấy nhiễu ở những điểm này.

Bản minh hoạ

Rất tiếc! Đó không phải là một trải nghiệm tuyệt vời; chúng tôi có thể làm tốt hơn. Với một lượng công việc lớn hơn, sử dụng chính xác cùng các tệp MP3 trong bản minh hoạ ở trên, chúng ta có thể sử dụng MSE để loại bỏ những khoảng trống khó chịu đó. Các đường màu xanh lục trong bản minh hoạ tiếp theo cho biết vị trí các tệp đã được kết hợp và các khoảng trống đã được loại bỏ. Trên Chrome 38 trở lên, nội dung này sẽ phát liền mạch!

Bản minh hoạ

nhiều cách để tạo nội dung không có khoảng trống. Trong bản minh hoạ này, chúng ta sẽ tập trung vào loại tệp mà người dùng bình thường có thể sử dụng. Khi mỗi tệp được mã hoá riêng biệt bất kể các đoạn âm thanh trước hoặc sau tệp đó.

Thiết lập cơ bản

Trước tiên, hãy quay lại và đề cập đến phần thiết lập cơ bản của thực thể MediaSource. Tiện ích nguồn nội dung đa phương tiện, đúng như tên gọi, chỉ là phần mở rộng cho các thành phần nội dung đa phương tiện hiện có. Dưới đây, chúng ta đang gán một Object URL, đại diện cho thực thể MediaSource, cho thuộc tính nguồn của một phần tử âm thanh; giống như cách bạn thiết lập một URL tiêu chuẩn.

var audio = document.createElement('audio');
var mediaSource = new MediaSource();
var SEGMENTS = 5;

mediaSource.addEventListener('sourceopen', function() {
    var sourceBuffer = mediaSource.addSourceBuffer('audio/mpeg');

    function onAudioLoaded(data, index) {
    // Append the ArrayBuffer data into our new SourceBuffer.
    sourceBuffer.appendBuffer(data);
    }

    // Retrieve an audio segment via XHR.  For simplicity, we're retrieving the
    // entire segment at once, but we could also retrieve it in chunks and append
    // each chunk separately.  MSE will take care of assembling the pieces.
    GET('sintel/sintel_0.mp3', function(data) { onAudioLoaded(data, 0); } );
});

audio.src = URL.createObjectURL(mediaSource);

Sau khi được kết nối, đối tượng MediaSource sẽ thực hiện một số hoạt động khởi tạo và cuối cùng sẽ kích hoạt sự kiện sourceopen; tại thời điểm đó, chúng ta có thể tạo SourceBuffer. Trong ví dụ trên, chúng ta sẽ tạo một mã audio/mpeg có thể phân tích cú pháp và giải mã các đoạn MP3; hiện có một số loại khác.

Dạng sóng bất thường

Chút nữa chúng ta sẽ trở lại mã, nhưng bây giờ hãy xem kỹ hơn tệp chúng ta vừa nối thêm, cụ thể là ở phần cuối của tệp. Dưới đây là biểu đồ về 3.000 mẫu gần đây nhất được tính trung bình trên cả hai kênh từ kênh sintel_0.mp3. Mỗi pixel trên đường màu đỏ là một mẫu dấu phẩy động trong phạm vi [-1.0, 1.0].

Kết thúc sintel_0.mp3

Sao mà những mẫu 0 (không thử nghiệm) đó (không hoạt động) đó xảy ra thế!? Thực ra các lỗi này là do cấu phần phần mềm nén xuất hiện trong quá trình mã hoá. Hầu như mọi bộ mã hoá đều có một số loại khoảng đệm. Trong trường hợp này, LAME đã thêm chính xác 576 mẫu khoảng đệm vào cuối tệp.

Ngoài khoảng đệm ở cuối, mỗi tệp cũng có khoảng đệm ở đầu. Nếu xem trước kênh sintel_1.mp3, chúng ta sẽ thấy 576 mẫu khoảng đệm khác ở phía trước. Số lượng khoảng đệm thay đổi tuỳ theo bộ mã hoá và nội dung, nhưng chúng tôi biết chính xác các giá trị dựa trên metadata có trong mỗi tệp.

Tình yêu của [Tên người].mp3

Tình yêu của [Tên người].mp3

Các phần im lặng ở đầu và cuối mỗi tệp là nguyên nhân gây ra sự cố giữa các phân đoạn trong bản minh họa trước. Để đạt được khả năng phát không gián đoạn, chúng ta cần xoá những khoảng im lặng này. Thật may là bạn có thể thực hiện việc này dễ dàng nhờ MediaSource. Dưới đây, chúng ta sẽ sửa đổi phương thức onAudioLoaded() để sử dụng cửa sổ nốigiá trị chênh lệch dấu thời gian nhằm loại bỏ khoảng lặng này.

Mã ví dụ

function onAudioLoaded(data, index) {
    // Parsing gapless metadata is unfortunately non trivial and a bit messy, so
    // we'll glaze over it here; see the appendix for details.
    // ParseGaplessData() will return a dictionary with two elements:
    //
    //    audioDuration: Duration in seconds of all non-padding audio.
    //    frontPaddingDuration: Duration in seconds of the front padding.
    //
    var gaplessMetadata = ParseGaplessData(data);

    // Each appended segment must be appended relative to the next.  To avoid any
    // overlaps, we'll use the end timestamp of the last append as the starting
    // point for our next append or zero if we haven't appended anything yet.
    var appendTime = index > 0 ? sourceBuffer.buffered.end(0) : 0;

    // Simply put, an append window allows you to trim off audio (or video) frames
    // which fall outside of a specified time range.  Here, we'll use the end of
    // our last append as the start of our append window and the end of the real
    // audio data for this segment as the end of our append window.
    sourceBuffer.appendWindowStart = appendTime;
    sourceBuffer.appendWindowEnd = appendTime + gaplessMetadata.audioDuration;

    // The timestampOffset field essentially tells MediaSource where in the media
    // timeline the data given to appendBuffer() should be placed.  I.e., if the
    // timestampOffset is 1 second, the appended data will start 1 second into
    // playback.
    //
    // MediaSource requires that the media timeline starts from time zero, so we
    // need to ensure that the data left after filtering by the append window
    // starts at time zero.  We'll do this by shifting all of the padding we want
    // to discard before our append time (and thus, before our append window).
    sourceBuffer.timestampOffset =
        appendTime - gaplessMetadata.frontPaddingDuration;

    // When appendBuffer() completes, it will fire an updateend event signaling
    // that it's okay to append another segment of media.  Here, we'll chain the
    // append for the next segment to the completion of our current append.
    if (index == 0) {
    sourceBuffer.addEventListener('updateend', function() {
        if (++index < SEGMENTS) {
        GET('sintel/sintel_' + index + '.mp3',
            function(data) { onAudioLoaded(data, index); });
        } else {
        // We've loaded all available segments, so tell MediaSource there are no
        // more buffers which will be appended.
        mediaSource.endOfStream();
        URL.revokeObjectURL(audio.src);
        }
    });
    }

    // appendBuffer() will now use the timestamp offset and append window settings
    // to filter and timestamp the data we're appending.
    //
    // Note: While this demo uses very little memory, more complex use cases need
    // to be careful about memory usage or garbage collection may remove ranges of
    // media in unexpected places.
    sourceBuffer.appendBuffer(data);
}

Dạng sóng liền mạch

Hãy xem mã mới nổi bật của chúng ta đã hoàn thành những gì bằng cách xem lại dạng sóng sau khi áp dụng các cửa sổ nối. Dưới đây, bạn có thể thấy rằng phần im lặng ở cuối sintel_0.mp3 (màu đỏ) và phần im lặng ở đầu sintel_1.mp3 (màu xanh dương) đã bị xóa; để lại cho chúng ta quá trình chuyển đổi liền mạch giữa các phân đoạn.

Tham gia của sintel_0.mp3 và sintel_1.mp3

Kết luận

Bây giờ, chúng tôi đã ghép toàn bộ 5 phân đoạn thành một và cuối cùng bản minh hoạ của chúng tôi cũng kết thúc. Trước khi tiếp tục, có thể bạn đã nhận thấy phương thức onAudioLoaded() không xem xét vùng chứa hoặc bộ mã hoá và giải mã. Điều đó có nghĩa là tất cả các kỹ thuật này sẽ hoạt động hiệu quả bất kể loại vùng chứa hay bộ mã hoá và giải mã. Dưới đây, bạn có thể phát lại bản minh hoạ MP4 phân mảnh sẵn sàng cho DASH thay vì MP3.

Bản minh hoạ

Nếu bạn muốn tìm hiểu thêm, hãy xem phụ lục bên dưới để tìm hiểu kỹ hơn về việc tạo nội dung không có khoảng trống và phân tích cú pháp siêu dữ liệu. Bạn cũng có thể khám phá gapless.js để tìm hiểu kỹ hơn về đoạn mã cung cấp bản minh hoạ này.

Cảm ơn bạn đã đọc!

Phụ lục A: Tạo nội dung không có khoảng trống

Việc tạo nội dung không có khoảng trống có thể khó thành công. Dưới đây, chúng ta sẽ cùng tìm hiểu cách tạo nội dung nghe nhìn Sintel được dùng trong bản minh hoạ này. Để bắt đầu, bạn cần có một bản sao bản nhạc FLAC không tổn hao của Sintel. Để sau này, thuật toán SHA1 được cung cấp ở bên dưới. Đối với các công cụ, bạn cần có FFmpeg, MP4Box, LAME và cài đặt OSX có afconvert.

unzip Jan_Morgenstern-Sintel-FLAC.zip
sha1sum 1-Snow_Fight.flac
# 0535ca207ccba70d538f7324916a3f1a3d550194  1-Snow_Fight.flac

Trước tiên, chúng ta sẽ tách riêng 31,5 giây đầu tiên của bản nhạc 1-Snow_Fight.flac. Chúng tôi cũng muốn thêm độ mờ 2,5 giây bắt đầu từ 28 giây để tránh bất kỳ nhấp chuột nào sau khi phát xong. Bằng cách dùng dòng lệnh FFmpeg bên dưới, chúng ta có thể thực hiện tất cả những việc này và đưa kết quả vào sintel.flac.

ffmpeg -i 1-Snow_Fight.flac -t 31.5 -af "afade=t=out:st=28:d=2.5" sintel.flac

Tiếp theo, chúng ta sẽ chia tệp đó thành 5 tệp wave (mỗi tệp 6,5 giây). Cách này dễ sử dụng nhất vì hầu hết mọi bộ mã hoá đều hỗ trợ việc truyền dẫn tệp này. Xin nhắc lại rằng chúng ta có thể thực hiện việc này chính xác bằng FFmpeg, sau đó chúng ta sẽ có: sintel_0.wav, sintel_1.wav, sintel_2.wav, sintel_3.wavsintel_4.wav.

ffmpeg -i sintel.flac -acodec pcm_f32le -map 0 -f segment \
        -segment_list out.list -segment_time 6.5 sintel_%d.wav

Tiếp theo, hãy tạo tệp MP3. LAME có nhiều cách để tạo nội dung không có khoảng trống. Nếu có quyền kiểm soát nội dung, bạn có thể cân nhắc sử dụng --nogap với phương thức mã hoá hàng loạt cho tất cả các tệp để tránh hoàn toàn khoảng đệm giữa các phân đoạn. Tuy nhiên, vì mục đích của bản minh hoạ này, chúng ta sẽ sử dụng phần đệm đó, vì vậy chúng ta sẽ sử dụng mã hoá VBR chất lượng cao tiêu chuẩn của các tệp sóng.

lame -V=2 sintel_0.wav sintel_0.mp3
lame -V=2 sintel_1.wav sintel_1.mp3
lame -V=2 sintel_2.wav sintel_2.mp3
lame -V=2 sintel_3.wav sintel_3.mp3
lame -V=2 sintel_4.wav sintel_4.mp3

Đó là tất cả những gì cần thiết để tạo tệp MP3. Bây giờ, chúng ta hãy cùng tạo các tệp MP4 được phân đoạn. Chúng tôi sẽ làm theo hướng dẫn của Apple về cách tạo nội dung nghe nhìn thành thạo cho iTunes. Dưới đây, chúng tôi sẽ chuyển đổi các tệp wave thành tệp CAF trung gian theo hướng dẫn, trước khi mã hoá các tệp này dưới dạng AAC trong vùng chứa MP4 bằng các thông số được đề xuất.

afconvert sintel_0.wav sintel_0_intermediate.caf -d 0 -f caff \
            --soundcheck-generate
afconvert sintel_1.wav sintel_1_intermediate.caf -d 0 -f caff \
            --soundcheck-generate
afconvert sintel_2.wav sintel_2_intermediate.caf -d 0 -f caff \
            --soundcheck-generate
afconvert sintel_3.wav sintel_3_intermediate.caf -d 0 -f caff \
            --soundcheck-generate
afconvert sintel_4.wav sintel_4_intermediate.caf -d 0 -f caff \
            --soundcheck-generate
afconvert sintel_0_intermediate.caf -d aac -f m4af -u pgcm 2 --soundcheck-read \
            -b 256000 -q 127 -s 2 sintel_0.m4a
afconvert sintel_1_intermediate.caf -d aac -f m4af -u pgcm 2 --soundcheck-read \
            -b 256000 -q 127 -s 2 sintel_1.m4a
afconvert sintel_2_intermediate.caf -d aac -f m4af -u pgcm 2 --soundcheck-read \
            -b 256000 -q 127 -s 2 sintel_2.m4a
afconvert sintel_3_intermediate.caf -d aac -f m4af -u pgcm 2 --soundcheck-read \
            -b 256000 -q 127 -s 2 sintel_3.m4a
afconvert sintel_4_intermediate.caf -d aac -f m4af -u pgcm 2 --soundcheck-read \
            -b 256000 -q 127 -s 2 sintel_4.m4a

Chúng ta hiện có một số tệp M4A mà chúng ta cần phân mảnh một cách thích hợp trước khi có thể sử dụng với MediaSource. Để đạt được mục đích của mình, chúng ta sẽ sử dụng kích thước mảnh là 1 giây. MP4Box sẽ ghi lại từng MP4 phân mảnh dưới dạng sintel_#_dashinit.mp4 cùng với một tệp kê khai MPEG-DASH (sintel_#_dash.mpd) có thể bị loại bỏ.

MP4Box -dash 1000 sintel_0.m4a && mv sintel_0_dashinit.mp4 sintel_0.mp4
MP4Box -dash 1000 sintel_1.m4a && mv sintel_1_dashinit.mp4 sintel_1.mp4
MP4Box -dash 1000 sintel_2.m4a && mv sintel_2_dashinit.mp4 sintel_2.mp4
MP4Box -dash 1000 sintel_3.m4a && mv sintel_3_dashinit.mp4 sintel_3.mp4
MP4Box -dash 1000 sintel_4.m4a && mv sintel_4_dashinit.mp4 sintel_4.mp4
rm sintel_{0,1,2,3,4}_dash.mpd

Vậy là xong! Chúng tôi hiện có các tệp MP4 và MP3 được phân mảnh với siêu dữ liệu chính xác cần thiết để phát lại liên tục. Xem Phụ lục B để biết thêm chi tiết về định dạng của siêu dữ liệu.

Phụ lục B: Phân tích cú pháp siêu dữ liệu không có khoảng trống

Cũng giống như tạo nội dung không có khoảng trống, việc phân tích cú pháp siêu dữ liệu không có dấu cách có thể khó khăn vì không có phương pháp chuẩn để lưu trữ. Dưới đây là cách hai bộ mã hoá phổ biến nhất là LAME và iTunes lưu trữ siêu dữ liệu không có dấu cách. Hãy bắt đầu bằng cách thiết lập một số phương thức trợ giúp và đường viền cho ParseGaplessData() đã dùng ở trên.

// Since most MP3 encoders store the gapless metadata in binary, we'll need a
// method for turning bytes into integers.  Note: This doesn't work for values
// larger than 2^30 since we'll overflow the signed integer type when shifting.
function ReadInt(buffer) {
    var result = buffer.charCodeAt(0);
    for (var i = 1; i < buffer.length; ++i) {
    result <<../= 8;
    result += buffer.charCodeAt(i);
    }
    return result;
}

function ParseGaplessData(arrayBuffer) {
    // Gapless data is generally within the first 512 bytes, so limit parsing.
    var byteStr = new TextDecoder().decode(arrayBuffer.slice(0, 512));

    var frontPadding = 0, endPadding = 0, realSamples = 0;

    // ... we'll fill this in as we go below.

Trước tiên, chúng ta sẽ đề cập đến định dạng siêu dữ liệu iTunes của Apple vì đây là định dạng dễ phân tích và giải thích nhất. Trong tệp MP3 và M4A iTunes (và afConvert) viết một phần ngắn trong ASCII như sau:

iTunSMPB[ 26 bytes ]0000000 00000840 000001C0 0000000000046E00

Mã này được viết bên trong thẻ ID3 trong vùng chứa MP3 và trong một nguyên tử siêu dữ liệu bên trong vùng chứa MP4. Do vậy, chúng ta có thể bỏ qua mã thông báo 0000000 đầu tiên. Ba mã thông báo tiếp theo là khoảng đệm trước, khoảng đệm cuối và tổng số lượng mẫu không phải khoảng đệm. Việc chia mỗi giá trị này cho tốc độ lấy mẫu âm thanh sẽ cho ra thời lượng của mỗi giá trị.

// iTunes encodes the gapless data as hex strings like so:
//
//    'iTunSMPB[ 26 bytes ]0000000 00000840 000001C0 0000000000046E00'
//    'iTunSMPB[ 26 bytes ]####### frontpad  endpad    real samples'
//
// The approach here elides the complexity of actually parsing MP4 atoms. It
// may not work for all files without some tweaks.
var iTunesDataIndex = byteStr.indexOf('iTunSMPB');
if (iTunesDataIndex != -1) {
    var frontPaddingIndex = iTunesDataIndex + 34;
    frontPadding = parseInt(byteStr.substr(frontPaddingIndex, 8), 16);

    var endPaddingIndex = frontPaddingIndex + 9;
    endPadding = parseInt(byteStr.substr(endPaddingIndex, 8), 16);

    var sampleCountIndex = endPaddingIndex + 9;
    realSamples = parseInt(byteStr.substr(sampleCountIndex, 16), 16);
}

Mặt khác, hầu hết các bộ mã hoá MP3 nguồn mở sẽ lưu trữ siêu dữ liệu không có khoảng trống trong một tiêu đề Xing đặc biệt được đặt bên trong một khung MPEG tĩnh (hoạt động này ở chế độ im lặng nên những bộ giải mã không hiểu được tiêu đề Xing sẽ chỉ phát im lặng). Tiếc là thẻ này không phải lúc nào cũng xuất hiện và có một số trường không bắt buộc. Trong bản minh hoạ này, chúng ta có quyền kiểm soát nội dung nghe nhìn, nhưng trên thực tế, chúng ta sẽ cần phải kiểm tra thêm để biết thời điểm thực sự có siêu dữ liệu không ngắt quãng.

Trước tiên, chúng ta sẽ phân tích cú pháp tổng số mẫu. Để đơn giản, chúng tôi sẽ đọc đoạn mã này từ tiêu đề Xing, nhưng bạn có thể tạo tệp này từ tiêu đề âm thanh MPEG thông thường. Bạn có thể đánh dấu tiêu đề Xing bằng thẻ Xing hoặc Info. Chính xác 4 byte sau thẻ này có 32 bit đại diện cho tổng số khung trong tệp; nhân giá trị này với số mẫu trên mỗi khung sẽ cho chúng ta tổng số mẫu trong tệp.

// Xing padding is encoded as 24bits within the header.  Note: This code will
// only work for Layer3 Version 1 and Layer2 MP3 files with XING frame counts
// and gapless information.  See the following document for more details:
// http://www.codeproject.com/Articles/8295/MPEG-Audio-Frame-Header
var xingDataIndex = byteStr.indexOf('Xing');
if (xingDataIndex == -1) xingDataIndex = byteStr.indexOf('Info');
if (xingDataIndex != -1) {
    // See section 2.3.1 in the link above for the specifics on parsing the Xing
    // frame count.
    var frameCountIndex = xingDataIndex + 8;
    var frameCount = ReadInt(byteStr.substr(frameCountIndex, 4));

    // For Layer3 Version 1 and Layer2 there are 1152 samples per frame.  See
    // section 2.1.5 in the link above for more details.
    var paddedSamples = frameCount * 1152;

    // ... we'll cover this below.

Giờ đây, khi đã có tổng số mẫu, chúng ta có thể chuyển sang đọc số lượng mẫu khoảng đệm. Tuỳ vào bộ mã hoá của bạn, nội dung này có thể được viết bên dưới một thẻ LAME hoặc Lavf lồng trong tiêu đề Xing. Chính xác 17 byte sau tiêu đề này, có 3 byte đại diện cho khoảng đệm trước và cuối tương ứng với 12 bit.

xingDataIndex = byteStr.indexOf('LAME');
if (xingDataIndex == -1) xingDataIndex = byteStr.indexOf('Lavf');
if (xingDataIndex != -1) {
    // See http://gabriel.mp3-tech.org/mp3infotag.html#delays for details of
    // how this information is encoded and parsed.
    var gaplessDataIndex = xingDataIndex + 21;
    var gaplessBits = ReadInt(byteStr.substr(gaplessDataIndex, 3));

    // Upper 12 bits are the front padding, lower are the end padding.
    frontPadding = gaplessBits >> 12;
    endPadding = gaplessBits & 0xFFF;
}

realSamples = paddedSamples - (frontPadding + endPadding);
}

return {
audioDuration: realSamples * SECONDS_PER_SAMPLE,
frontPaddingDuration: frontPadding * SECONDS_PER_SAMPLE
};
}

Nhờ đó, chúng ta có chức năng hoàn chỉnh để phân tích cú pháp phần lớn nội dung không có khoảng trống. Tuy nhiên, có rất nhiều trường hợp hiếm gặp, vì vậy, bạn nên thận trọng trước khi sử dụng mã tương tự trong môi trường thực tế.

Phụ lục C: Về việc thu gom rác

Bộ nhớ thuộc các thực thể SourceBuffer đang chủ động thu gom rác theo loại nội dung, giới hạn dành riêng cho nền tảng và vị trí phát hiện tại. Trong Chrome, bộ nhớ trước tiên sẽ được lấy lại từ vùng đệm đã phát. Tuy nhiên, nếu mức sử dụng bộ nhớ vượt quá giới hạn dành riêng cho nền tảng, thì hệ thống sẽ xoá bộ nhớ khỏi các vùng đệm chưa phát.

Khi việc phát đạt đến một khoảng trống trong dòng thời gian do bộ nhớ được thu hồi, thì nội dung phát có thể bị sự cố nếu khoảng cách này đủ nhỏ hoặc bị dừng hoàn toàn nếu khoảng cách này quá lớn. Cả hai đều không mang lại trải nghiệm tốt cho người dùng, vì vậy, điều quan trọng là tránh thêm quá nhiều dữ liệu cùng một lúc và xóa thủ công các phạm vi khỏi dòng thời gian của nội dung nghe nhìn không còn cần thiết.

Bạn có thể xoá phạm vi bằng phương thức remove() trên mỗi SourceBuffer; quá trình này mất phạm vi [start, end] tính bằng giây. Tương tự như appendBuffer(), mỗi remove() sẽ kích hoạt một sự kiện updateend sau khi hoàn tất. Không được phép thực hiện thao tác xoá hoặc thêm nội dung khác cho đến khi sự kiện kích hoạt.

Trên Chrome dành cho máy tính để bàn, bạn có thể lưu trữ khoảng 12 megabyte nội dung âm thanh và 150 megabyte nội dung video trong bộ nhớ cùng một lúc. Bạn không nên dựa vào các giá trị này trên trình duyệt hoặc nền tảng; ví dụ: các giá trị này chắc chắn không đại diện cho thiết bị di động.

Việc thu gom rác chỉ ảnh hưởng đến dữ liệu được thêm vào SourceBuffers; không có giới hạn về lượng dữ liệu bạn có thể lưu vào vùng đệm trong các biến JavaScript. Bạn cũng có thể nối lại cùng một dữ liệu ở cùng vị trí nếu cần.