This helps video playback do a slightly better job of keeping up in the browser. It's not a dramatic effect, but enough to start making video playback almost tolerable. Signed-off-by: Jeremy White <jwhite@xxxxxxxxxxxxxxx> --- display.js | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++---------- enums.js | 1 + main.js | 3 +++ spiceconn.js | 3 ++- spicemsg.js | 54 ++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 116 insertions(+), 12 deletions(-) diff --git a/display.js b/display.js index 7027230..7938527 100644 --- a/display.js +++ b/display.js @@ -477,31 +477,48 @@ SpiceDisplayConn.prototype.process_channel_message = function(msg) return true; } - if (msg.type == SPICE_MSG_DISPLAY_STREAM_DATA) + if (msg.type == SPICE_MSG_DISPLAY_STREAM_DATA || + msg.type == SPICE_MSG_DISPLAY_STREAM_DATA_SIZED) { - var m = new SpiceMsgDisplayStreamData(msg.data); + var m; + if (msg.type == SPICE_MSG_DISPLAY_STREAM_DATA_SIZED) + m = new SpiceMsgDisplayStreamDataSized(msg.data); + else + m = new SpiceMsgDisplayStreamData(msg.data); + if (!this.streams[m.base.id]) { console.log("no stream for data"); return false; } + + var mmtime = (Date.now() - this.parent.our_mm_time) + this.parent.mm_time; + var latency = m.base.multi_media_time - mmtime; + if (this.streams[m.base.id].codec_type === SPICE_VIDEO_CODEC_TYPE_MJPEG) - { - process_mjpeg_stream_data(this, m); + process_mjpeg_stream_data(this, m, latency); + + if ("report" in this.streams[m.base.id]) + process_stream_data_report(this, m, mmtime, latency); - } return true; } - if (msg.type == SPICE_MSG_DISPLAY_STREAM_DATA_SIZED) + if (msg.type == SPICE_MSG_DISPLAY_STREAM_ACTIVATE_REPORT) { - var m = new SpiceMsgDisplayStreamDataSized(msg.data); - if (this.streams[m.base.id].codec_type === SPICE_VIDEO_CODEC_TYPE_MJPEG) - process_mjpeg_stream_data(this, m); + var m = new SpiceMsgDisplayStreamActivateReport(msg.data); + + var report = new SpiceMsgcDisplayStreamReport(m.stream_id, m.unique_id); + if (this.streams[m.stream_id]) + { + this.streams[m.stream_id].report = report; + this.streams[m.stream_id].max_window_size = m.max_window_size; + this.streams[m.stream_id].timeout_ms = m.timeout_ms + } + return true; } - if (msg.type == SPICE_MSG_DISPLAY_STREAM_CLIP) { var m = new SpiceMsgDisplayStreamClip(msg.data); @@ -811,8 +828,15 @@ function handle_draw_jpeg_onload() } } -function process_mjpeg_stream_data(sc, m) +function process_mjpeg_stream_data(sc, m, latency) { + if (latency < 0) + { + if ("report" in sc.streams[m.base.id]) + sc.streams[m.base.id].report.num_drops++; + return; + } + var tmpstr = "data:image/jpeg,"; var img = new Image; var i; @@ -837,3 +861,24 @@ function process_mjpeg_stream_data(sc, m) img.src = tmpstr; } +function process_stream_data_report(sc, m, mmtime, latency) +{ + sc.streams[m.base.id].report.num_frames++; + if (sc.streams[m.base.id].report.start_frame_mm_time == 0) + sc.streams[m.base.id].report.start_frame_mm_time = m.base.multi_media_time; + + if (sc.streams[m.base.id].report.num_frames > sc.streams[m.base.id].max_window_size || + (m.base.multi_media_time - sc.streams[m.base.id].report.start_frame_mm_time) > sc.streams[m.base.id].timeout_ms) + { + sc.streams[m.base.id].report.end_frame_mm_time = m.base.multi_media_time; + sc.streams[m.base.id].report.last_frame_delay = latency; + + var msg = new SpiceMiniData(); + msg.build_msg(SPICE_MSGC_DISPLAY_STREAM_REPORT, sc.streams[m.base.id].report); + sc.send_msg(msg); + + sc.streams[m.base.id].report.start_frame_mm_time = 0; + sc.streams[m.base.id].report.num_frames = 0; + sc.streams[m.base.id].report.num_drops = 0; + } +} diff --git a/enums.js b/enums.js index 7f55e46..6e94025 100644 --- a/enums.js +++ b/enums.js @@ -133,6 +133,7 @@ var SPICE_MSG_DISPLAY_DRAW_COMPOSITE = 318; var SPICE_MSG_DISPLAY_STREAM_ACTIVATE_REPORT = 319; var SPICE_MSGC_DISPLAY_INIT = 101; +var SPICE_MSGC_DISPLAY_STREAM_REPORT = 102; var SPICE_MSG_INPUTS_INIT = 101; var SPICE_MSG_INPUTS_KEY_MODIFIERS = 102; diff --git a/main.js b/main.js index bfc102a..99b2274 100644 --- a/main.js +++ b/main.js @@ -86,6 +86,9 @@ SpiceMainConn.prototype.process_channel_message = function(msg) " ; ram_hint " + this.main_init.ram_hint); } + this.our_mm_time = Date.now(); + this.mm_time = this.main_init.multi_media_time; + this.handle_mouse_mode(this.main_init.current_mouse_mode, this.main_init.supported_mouse_modes); diff --git a/spiceconn.js b/spiceconn.js index b7043c0..f19b109 100644 --- a/spiceconn.js +++ b/spiceconn.js @@ -135,7 +135,8 @@ SpiceConn.prototype = ); else if (msg.channel_type == SPICE_CHANNEL_DISPLAY) msg.channel_caps.push( - (1 << SPICE_DISPLAY_CAP_SIZED_STREAM) + (1 << SPICE_DISPLAY_CAP_SIZED_STREAM) | + (1 << SPICE_DISPLAY_CAP_STREAM_REPORT) ); hdr.size = msg.buffer_size(); diff --git a/spicemsg.js b/spicemsg.js index 4b78d94..db6625a 100644 --- a/spicemsg.js +++ b/spicemsg.js @@ -1201,6 +1201,60 @@ SpiceMsgDisplayStreamDestroy.prototype = }, } +function SpiceMsgDisplayStreamActivateReport(a, at) +{ + this.from_buffer(a, at); +} + +SpiceMsgDisplayStreamActivateReport.prototype = +{ + from_buffer: function(a, at) + { + at = at || 0; + var dv = new SpiceDataView(a); + this.stream_id = dv.getUint32(at, true); at += 4; + this.unique_id = dv.getUint32(at, true); at += 4; + this.max_window_size = dv.getUint32(at, true); at += 4; + this.timeout_ms = dv.getUint32(at, true); at += 4; + }, +} + +function SpiceMsgcDisplayStreamReport(stream_id, unique_id) +{ + this.stream_id = stream_id; + this.unique_id = unique_id; + this.start_frame_mm_time = 0; + this.end_frame_mm_time = 0; + this.num_frames = 0; + this.num_drops = 0; + this.last_frame_delay = 0; + + // TODO - Implement audio delay + this.audio_delay = -1; +} + +SpiceMsgcDisplayStreamReport.prototype = +{ + to_buffer: function(a, at) + { + at = at || 0; + var dv = new SpiceDataView(a); + dv.setUint32(at, this.stream_id, true); at += 4; + dv.setUint32(at, this.unique_id, true); at += 4; + dv.setUint32(at, this.start_frame_mm_time, true); at += 4; + dv.setUint32(at, this.end_frame_mm_time, true); at += 4; + dv.setUint32(at, this.num_frames, true); at += 4; + dv.setUint32(at, this.num_drops, true); at += 4; + dv.setUint32(at, this.last_frame_delay, true); at += 4; + dv.setUint32(at, this.audio_delay, true); at += 4; + return at; + }, + buffer_size: function() + { + return 8 * 4; + } +} + function SpiceMsgDisplayInvalList(a, at) { this.count = 0; -- 2.1.4 _______________________________________________ Spice-devel mailing list Spice-devel@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/spice-devel