Add support for stream reports.

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.
This commit is contained in:
Jeremy White 2015-06-03 15:21:06 -05:00
parent 84562db7e4
commit b76c734d16
5 changed files with 117 additions and 13 deletions

View File

@ -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;
}
if (this.streams[m.base.id].codec_type === SPICE_VIDEO_CODEC_TYPE_MJPEG)
{
process_mjpeg_stream_data(this, m);
}
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, 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;
}
}

View File

@ -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;

View File

@ -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);

View File

@ -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();

View File

@ -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;