| OLD | NEW |
| (Empty) |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 'use strict'; | |
| 6 | |
| 7 /** @suppress {duplicate} */ | |
| 8 var remoting = remoting || {}; | |
| 9 | |
| 10 /** | |
| 11 * @param {HTMLMediaElement} videoTag <video> tag to render to. | |
| 12 * @constructor | |
| 13 */ | |
| 14 remoting.MediaSourceRenderer = function(videoTag) { | |
| 15 /** @type {HTMLMediaElement} */ | |
| 16 this.video_ = videoTag; | |
| 17 | |
| 18 /** @type {MediaSource} */ | |
| 19 this.mediaSource_ = null; | |
| 20 | |
| 21 /** @type {SourceBuffer} */ | |
| 22 this.sourceBuffer_ = null; | |
| 23 | |
| 24 /** @type {!Array.<ArrayBuffer>} Queue of pending buffers that haven't been | |
| 25 * processed. A null element indicates that the SourceBuffer can be reset | |
| 26 * because the following buffer contains a keyframe. */ | |
| 27 this.buffers_ = []; | |
| 28 | |
| 29 this.lastKeyFramePos_ = 0; | |
| 30 } | |
| 31 | |
| 32 /** | |
| 33 * @param {string} format Format of the stream. | |
| 34 */ | |
| 35 remoting.MediaSourceRenderer.prototype.reset = function(format) { | |
| 36 // Reset the queue. | |
| 37 this.buffers_ = []; | |
| 38 | |
| 39 // Create a new MediaSource instance. | |
| 40 this.sourceBuffer_ = null; | |
| 41 this.mediaSource_ = new MediaSource(); | |
| 42 this.mediaSource_.addEventListener('sourceopen', | |
| 43 this.onSourceOpen_.bind(this, format)); | |
| 44 this.mediaSource_.addEventListener('sourceclose', function(e) { | |
| 45 console.error("MediaSource closed unexpectedly."); | |
| 46 }); | |
| 47 this.mediaSource_.addEventListener('sourceended', function(e) { | |
| 48 console.error("MediaSource ended unexpectedly."); | |
| 49 }); | |
| 50 | |
| 51 // Start playback from new MediaSource. | |
| 52 this.video_.src = | |
| 53 /** @type {string} */( | |
| 54 window.URL.createObjectURL(/** @type {!Blob} */(this.mediaSource_))); | |
| 55 this.video_.play(); | |
| 56 } | |
| 57 | |
| 58 /** | |
| 59 * @param {string} format | |
| 60 * @private | |
| 61 */ | |
| 62 remoting.MediaSourceRenderer.prototype.onSourceOpen_ = function(format) { | |
| 63 this.sourceBuffer_ = | |
| 64 this.mediaSource_.addSourceBuffer(format); | |
| 65 | |
| 66 this.sourceBuffer_.addEventListener( | |
| 67 'updateend', this.processPendingData_.bind(this)); | |
| 68 this.processPendingData_(); | |
| 69 } | |
| 70 | |
| 71 /** | |
| 72 * @private | |
| 73 */ | |
| 74 remoting.MediaSourceRenderer.prototype.processPendingData_ = function() { | |
| 75 if (this.sourceBuffer_) { | |
| 76 while (this.buffers_.length > 0 && !this.sourceBuffer_.updating) { | |
| 77 var buffer = /** @type {ArrayBuffer} */ this.buffers_.shift(); | |
| 78 if (buffer == null) { | |
| 79 // Remove data from the SourceBuffer from the beginning to the previous | |
| 80 // key frame. By default Chrome buffers up to 150MB of data. We never | |
| 81 // need to seek the stream, so it doesn't make sense to keep any of that | |
| 82 // data. | |
| 83 if (this.sourceBuffer_.buffered.length > 0) { | |
| 84 // TODO(sergeyu): Check currentTime to make sure that the current | |
| 85 // playback position is not being removed. crbug.com/398290 . | |
| 86 if (this.lastKeyFramePos_ > this.sourceBuffer_.buffered.start(0)) { | |
| 87 this.sourceBuffer_.remove(this.sourceBuffer_.buffered.start(0), | |
| 88 this.lastKeyFramePos_); | |
| 89 } | |
| 90 | |
| 91 this.lastKeyFramePos_ = this.sourceBuffer_.buffered.end( | |
| 92 this.sourceBuffer_.buffered.length - 1); | |
| 93 } | |
| 94 } else { | |
| 95 // TODO(sergeyu): Figure out the way to determine when a frame is | |
| 96 // rendered and use it to report performance statistics. | |
| 97 this.sourceBuffer_.appendBuffer(buffer); | |
| 98 } | |
| 99 } | |
| 100 } | |
| 101 } | |
| 102 | |
| 103 /** | |
| 104 * @param {ArrayBuffer} data | |
| 105 * @param {boolean} keyframe | |
| 106 */ | |
| 107 remoting.MediaSourceRenderer.prototype.onIncomingData = | |
| 108 function(data, keyframe) { | |
| 109 if (keyframe) { | |
| 110 // Queue SourceBuffer reset request. | |
| 111 this.buffers_.push(null); | |
| 112 } | |
| 113 this.buffers_.push(data); | |
| 114 this.processPendingData_(); | |
| 115 } | |
| 116 | |
| OLD | NEW |