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.
7 /** @suppress {duplicate} */
8 var remoting
= remoting
|| {};
11 * @param {HTMLMediaElement} videoTag <video> tag to render to.
14 remoting
.MediaSourceRenderer = function(videoTag
) {
15 /** @type {HTMLMediaElement} */
16 this.video_
= videoTag
;
18 /** @type {MediaSource} */
19 this.mediaSource_
= null;
21 /** @type {SourceBuffer} */
22 this.sourceBuffer_
= null;
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. */
29 this.lastKeyFramePos_
= 0;
33 * @param {string} format Format of the stream.
35 remoting
.MediaSourceRenderer
.prototype.reset = function(format
) {
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.");
47 this.mediaSource_
.addEventListener('sourceended', function(e
) {
48 console
.error("MediaSource ended unexpectedly.");
51 // Start playback from new MediaSource.
53 /** @type {string} */(
54 window
.URL
.createObjectURL(/** @type {!Blob} */(this.mediaSource_
)));
59 * @param {string} format
62 remoting
.MediaSourceRenderer
.prototype.onSourceOpen_ = function(format
) {
64 this.mediaSource_
.addSourceBuffer(format
);
66 this.sourceBuffer_
.addEventListener(
67 'updateend', this.processPendingData_
.bind(this));
68 this.processPendingData_();
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();
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
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_
);
91 this.lastKeyFramePos_
= this.sourceBuffer_
.buffered
.end(
92 this.sourceBuffer_
.buffered
.length
- 1);
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
);
104 * @param {ArrayBuffer} data
105 * @param {boolean} keyframe
107 remoting
.MediaSourceRenderer
.prototype.onIncomingData
=
108 function(data
, keyframe
) {
110 // Queue SourceBuffer reset request.
111 this.buffers_
.push(null);
113 this.buffers_
.push(data
);
114 this.processPendingData_();