[Spice-devel] Very poor video performance using Virt Viewer compared to RDP

Frediano Ziglio fziglio at redhat.com
Thu Oct 13 15:08:46 UTC 2016


> I have a Windows 7 VM running via Qemu on Gentoo Linux using a product called
> Foss-Cloud.
> I have spice tools and the QXL video driver installed
> Using Virt-Viewer The Vm shows a little lag when typing (always takes a
> second to catch up when typing my password to log in and such). In general
> pulling up folders and text heavy web pages is pretty snappy and doesn’t tax
> the cpu or memory at all. If look at a site that has a lot of pictures I
> start seeing frame loss and the mouse gets a little laggy when scrolling. If
> I pull up a video I see the cpu jump a little and the video is extremely
> laggy and I see about ever 10 th frame of the video, at the same time I lose
> sight of the mouse pointer for a second at a time and it becomes hard to
> control.
> While connecting to this vm using Virt-Viewer I also notice very low
> bandwidth usage, well below 500Kbps which is strange for a remote session
> sending video traffic.
> Using Windows RDP I was able to pull up all the same videos and web pages
> with no problem, the videos were clear and ran smooth and the websites with
> a lot of pictures scrolled normally. I did notice that the network traffic
> using RDP was closer to 10mbps and spiked to 14mbps so it’s understandable
> that I would get a better experience.

I'm not really familiar with the client code and I don't know if this
is really related to your problem but it share the fact of the lag and
the video.

While I was trying to code Virgl remote support I noted that in some
conditions I had EXTREME (like 1/2 seconds) lags. This was worsened
with low bandwidth. I started putting some debug code to understand
if server was queueing too data or was just too slow to handle the
encoding. And if was fast enough to handle all encoded frames and
the code in the streaming to deal with low bandwidth was apparently
doing it's job and the network queue (you can see with netstat) was
low. I then started putting timestamps in the frames trying to
understand where the lag was coming from and how much time take from
the encoding to the final client screen (you can see a video at
https://www.youtube.com/watch?v=D_DCs2sriu0 to understand the
time stamping, the green time in the video was written in the frames
before encoding in the server, not by the client).

I discovered where the main lag came quite by "accident". To test
I used one small utility and this utility don't have a way to change
parameters (like bandwidth) so knowing how the tcp work I stopped
the utility and started again as fast as I can with different
parameters. This of course create packets loss and some delay but
the connection works fine as tcp retransmit the packets lost.
But surprisingly the delay introduced by this accident was maintained
in the video! I then removed all Virgl stuff, tried again with a video
and the lag is still present. Also interrupting the utility and
starting again was increasing the lag (I managed to have about
3 seconds lag!).

Now... I have a patch for the client but as I said I'm not familiar
with the client too much and it's really terrible. It mainly remove
the synchronization with the audio (with still lags) and play the
video as fast as possible. By the way, I think is time to send as
someone could be able to make a sensible version of this patch
(perhaps fixing the sound too)


>From 31364b1b1b1e5041ba64441f18104f7f1e978af5 Mon Sep 17 00:00:00 2001
From: Frediano Ziglio <fziglio at redhat.com>
Date: Thu, 13 Oct 2016 15:40:49 +0100
Subject: [spice-gtk] Try to reduce video lag

---
 src/channel-display-gst.c | 26 ++++++++++++++++----------
 1 file changed, 16 insertions(+), 10 deletions(-)

diff --git a/src/channel-display-gst.c b/src/channel-display-gst.c
index 430bb95..c1ebfeb 100644
--- a/src/channel-display-gst.c
+++ b/src/channel-display-gst.c
@@ -48,6 +48,7 @@ typedef struct SpiceGstDecoder {
     GQueue *decoding_queue;
     GQueue *display_queue;
     guint timer_id;
+    guint unique_id;
 } SpiceGstDecoder;
 
 
@@ -94,13 +95,15 @@ static gboolean display_frame(gpointer video_decoder)
     GstBuffer *buffer;
     GstMapInfo mapinfo;
 
-    decoder->timer_id = 0;
-
+ again:
     g_mutex_lock(&decoder->queues_mutex);
+    decoder->timer_id = 0;
     frame = g_queue_pop_head(decoder->display_queue);
     g_mutex_unlock(&decoder->queues_mutex);
     /* If the queue is empty we don't even need to reschedule */
-    g_return_val_if_fail(frame, G_SOURCE_REMOVE);
+    if (!frame) {
+        return G_SOURCE_REMOVE;
+    }
 
     if (!frame->sample) {
         spice_warning("got a frame without a sample!");
@@ -132,26 +135,28 @@ static gboolean display_frame(gpointer video_decoder)
 
  error:
     free_frame(frame);
-    schedule_frame(decoder);
-    return G_SOURCE_REMOVE;
+    goto again;
 }
 
 /* main loop or GStreamer streaming thread */
 static void schedule_frame(SpiceGstDecoder *decoder)
 {
-    guint32 now = stream_get_time(decoder->base.stream);
+//    guint32 now = stream_get_time(decoder->base.stream);
     g_mutex_lock(&decoder->queues_mutex);
 
+    if (decoder->timer_id)
+        printf("not scheduling, already a timer\n");
     while (!decoder->timer_id) {
         SpiceFrame *frame = g_queue_peek_head(decoder->display_queue);
         if (!frame) {
             break;
         }
 
-        SpiceStreamDataHeader *op = spice_msg_in_parsed(frame->msg);
+//        SpiceStreamDataHeader *op = spice_msg_in_parsed(frame->msg);
+        decoder->timer_id = g_timeout_add(0, display_frame, decoder);
+#if 0
         if (now < op->multi_media_time) {
-            decoder->timer_id = g_timeout_add(op->multi_media_time - now,
-                                              display_frame, decoder);
+            decoder->timer_id = g_timeout_add(0, display_frame, decoder);
         } else if (g_queue_get_length(decoder->display_queue) == 1) {
             /* Still attempt to display the least out of date frame so the
              * video is not completely frozen for an extended period of time.
@@ -165,6 +170,7 @@ static void schedule_frame(SpiceGstDecoder *decoder)
             g_queue_pop_head(decoder->display_queue);
             free_frame(frame);
         }
+#endif
     }
 
     g_mutex_unlock(&decoder->queues_mutex);
@@ -415,7 +421,7 @@ static void spice_gst_decoder_queue_frame(VideoDecoder *video_decoder,
 
     GST_BUFFER_DURATION(buffer) = GST_CLOCK_TIME_NONE;
     GST_BUFFER_DTS(buffer) = GST_CLOCK_TIME_NONE;
-    GST_BUFFER_PTS(buffer) = gst_clock_get_time(decoder->clock) - gst_element_get_base_time(decoder->pipeline) + ((uint64_t)MAX(0, latency)) * 1000 * 1000;
+    GST_BUFFER_PTS(buffer) = ++decoder->unique_id;
 
     g_mutex_lock(&decoder->queues_mutex);
     g_queue_push_tail(decoder->decoding_queue, create_frame(buffer, frame_msg));
-- 
2.7.4


Frediano


More information about the Spice-devel mailing list