1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 | 10x 10x 10x 9x 15x 5x 5x 13x 13x 12x 12x 20x 8x 5x 8x 8x 8x 8x 8x 8x 16x 16x 8x 8x 8x 8x 8x 16x 16x 16x 5x 5x 5x 11x 3x 3x 8x | /** * @module BufferHelper * * Providing methods dealing with buffer length retrieval for example. * * In general, a helper around HTML5 MediaElement TimeRanges gathered from `buffered` property. * * Also @see https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/buffered */ export class BufferHelper { /** * Return true if `media`'s buffered include `position` * @param {HTMLMediaElement|SourceBuffer} media * @param {number} position * @returns {boolean} */ static isBuffered (media, position) { try { Eif (media) { let buffered = media.buffered; for (let i = 0; i < buffered.length; i++) { if (position >= buffered.start(i) && position <= buffered.end(i)) { return true; } } } } catch (error) { // this is to catch // InvalidStateError: Failed to read the 'buffered' property from 'SourceBuffer': // This SourceBuffer has been removed from the parent media source } return false; } static bufferInfo (media, pos, maxHoleDuration) { try { if (media) { let vbuffered = media.buffered, buffered = [], i; for (i = 0; i < vbuffered.length; i++) { buffered.push({ start: vbuffered.start(i), end: vbuffered.end(i) }); } return this.bufferedInfo(buffered, pos, maxHoleDuration); } } catch (error) { // this is to catch // InvalidStateError: Failed to read the 'buffered' property from 'SourceBuffer': // This SourceBuffer has been removed from the parent media source } return { len: 0, start: pos, end: pos, nextStart: undefined }; } static bufferedInfo (buffered, pos, maxHoleDuration) { let buffered2 = [], // bufferStart and bufferEnd are buffer boundaries around current video position bufferLen, bufferStart, bufferEnd, bufferStartNext, i; // sort on buffer.start/smaller end (IE does not always return sorted buffered range) buffered.sort(function (a, b) { let diff = a.start - b.start; Eif (diff) { return diff; } else { return b.end - a.end; } }); // there might be some small holes between buffer time range // consider that holes smaller than maxHoleDuration are irrelevant and build another // buffer time range representations that discards those holes for (i = 0; i < buffered.length; i++) { let buf2len = buffered2.length; if (buf2len) { let buf2end = buffered2[buf2len - 1].end; // if small hole (value between 0 or maxHoleDuration ) or overlapping (negative) Iif ((buffered[i].start - buf2end) < maxHoleDuration) { // merge overlapping time ranges // update lastRange.end only if smaller than item.end // e.g. [ 1, 15] with [ 2,8] => [ 1,15] (no need to modify lastRange.end) // whereas [ 1, 8] with [ 2,15] => [ 1,15] ( lastRange should switch from [1,8] to [1,15]) if (buffered[i].end > buf2end) { buffered2[buf2len - 1].end = buffered[i].end; } } else { // big hole buffered2.push(buffered[i]); } } else { // first value buffered2.push(buffered[i]); } } for (i = 0, bufferLen = 0, bufferStart = bufferEnd = pos; i < buffered2.length; i++) { let start = buffered2[i].start, end = buffered2[i].end; // logger.log('buf start/end:' + buffered.start(i) + '/' + buffered.end(i)); if ((pos + maxHoleDuration) >= start && pos < end) { // play position is inside this buffer TimeRange, retrieve end of buffer position and buffer length bufferStart = start; bufferEnd = end; bufferLen = bufferEnd - pos; } else if ((pos + maxHoleDuration) < start) { bufferStartNext = start; break; } } return { len: bufferLen, start: bufferStart, end: bufferEnd, nextStart: bufferStartNext }; } } |