[Spice-devel,2/2] server: Provide a framerate estimate based on the frames that lead to the stream creation.

Submitted by Francois Gouget on June 11, 2015, 5:39 p.m.

Details

Message ID alpine.DEB.2.20.1506111925500.21679@amboise
State New
Headers show

Not browsing as part of any series.

Commit Message

Francois Gouget June 11, 2015, 5:39 p.m.
This way the video encoder can actually count on a real estimate when it is initializing.

Signed-off-by: Francois Gouget <fgouget@codeweavers.com>
---

Initialisation time is when video encoders need an fps most since they 
have no other information at that point. Yet, all they were getting is 
MAX_FPS (30).

This patch takes advantage of the fact that Spice needs to keep track of 
the related drawables in order to determine whether creating a video 
stream makes sense. So it stores the time of the first drawable and then 
propagates it. So when the time comes to create the stream we can 
provide a framerate estimate based on the first 20 frames. In my tests 
the result falls within one 1 fps of the later estimates and thus is 
much more useful than MAX_FPS.

 server/red_worker.c | 20 ++++++++++++++++----
 1 file changed, 16 insertions(+), 4 deletions(-)

Patch hide | download patch | download mbox

diff --git a/server/red_worker.c b/server/red_worker.c
index a07a78a..8374f54 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -844,6 +844,7 @@  struct Drawable {
     Ring glz_ring;
 
     red_time_t creation_time;
+    red_time_t first_frame_time;
     int frames_count;
     int gradual_frames_count;
     int last_gradual_frame;
@@ -915,6 +916,7 @@  typedef struct RedSurface {
 
 typedef struct ItemTrace {
     red_time_t time;
+    red_time_t first_frame_time;
     int frames_count;
     int gradual_frames_count;
     int last_gradual_frame;
@@ -1926,6 +1928,7 @@  static inline void red_add_item_trace(RedWorker *worker, Drawable *item)
 
     trace = &worker->items_trace[worker->next_item_trace++ & ITEMS_TRACE_MASK];
     trace->time = item->creation_time;
+    trace->first_frame_time = item->first_frame_time;
     trace->frames_count = item->frames_count;
     trace->gradual_frames_count = item->gradual_frames_count;
     trace->last_gradual_frame = item->last_gradual_frame;
@@ -3155,7 +3158,12 @@  static void red_create_stream(RedWorker *worker, Drawable *drawable)
     SpiceBitmap *bitmap = &drawable->red_drawable->u.copy.src_bitmap->u.bitmap;
     stream->top_down = !!(bitmap->flags & SPICE_BITMAP_FLAGS_TOP_DOWN);
     drawable->stream = stream;
-    stream->input_fps = MAX_FPS;
+    /* Provide an fps estimate the video encoder can use when initializing
+     * based on the frames that lead to the creation of the stream. Round to
+     * the nearest integer, for instance 24 for 23.976.
+     */
+    uint64_t duration = drawable->creation_time - drawable->first_frame_time;
+    stream->input_fps = ((uint64_t)drawable->frames_count * 1000 * 1000 * 1000 + duration / 2) / duration;
     stream->num_input_frames = 0;
     stream->input_fps_start_time = drawable->creation_time;
     worker->streams_size_total += stream->width * stream->height;
@@ -3163,9 +3171,9 @@  static void red_create_stream(RedWorker *worker, Drawable *drawable)
     WORKER_FOREACH_DCC_SAFE(worker, dcc_ring_item, next, dcc) {
         red_display_create_stream(dcc, stream);
     }
-    spice_debug("stream %d %dx%d (%d, %d) (%d, %d)", (int)(stream - worker->streams_buf), stream->width,
+    spice_debug("stream %d %dx%d (%d, %d) (%d, %d) %u fps", (int)(stream - worker->streams_buf), stream->width,
                 stream->height, stream->dest_area.left, stream->dest_area.top,
-                stream->dest_area.right, stream->dest_area.bottom);
+                stream->dest_area.right, stream->dest_area.bottom, stream->input_fps);
     return;
 }
 
@@ -3419,11 +3427,13 @@  static inline int red_is_stream_start(Drawable *drawable)
 // returns whether a stream was created
 static int red_stream_add_frame(RedWorker *worker,
                                 Drawable *frame_drawable,
+                                red_time_t first_frame_time,
                                 int frames_count,
                                 int gradual_frames_count,
                                 int last_gradual_frame)
 {
     red_update_copy_graduality(worker, frame_drawable);
+    frame_drawable->first_frame_time = first_frame_time;
     frame_drawable->frames_count = frames_count + 1;
     frame_drawable->gradual_frames_count  = gradual_frames_count;
 
@@ -3477,6 +3487,7 @@  static inline void red_stream_maintenance(RedWorker *worker, Drawable *candidate
     } else {
         if (red_is_next_stream_frame(worker, candidate, prev) != STREAM_FRAME_NONE) {
             red_stream_add_frame(worker, candidate,
+                                 prev->first_frame_time,
                                  prev->frames_count,
                                  prev->gradual_frames_count,
                                  prev->last_gradual_frame);
@@ -3638,6 +3649,7 @@  static inline void red_use_stream_trace(RedWorker *worker, Drawable *drawable)
                                        &trace->dest_area, trace->time, NULL, FALSE) !=
                                        STREAM_FRAME_NONE) {
             if (red_stream_add_frame(worker, drawable,
+                                     trace->first_frame_time,
                                      trace->frames_count,
                                      trace->gradual_frames_count,
                                      trace->last_gradual_frame)) {
@@ -4099,7 +4111,7 @@  static Drawable *get_drawable(RedWorker *worker, uint8_t effect, RedDrawable *re
     memset(drawable, 0, sizeof(Drawable));
     drawable->refs = 1;
     clock_gettime(CLOCK_MONOTONIC, &time);
-    drawable->creation_time = timespec_to_red_time(&time);
+    drawable->creation_time = drawable->first_frame_time = timespec_to_red_time(&time);
 #ifdef PIPE_DEBUG
     drawable->tree_item.base.id = ++worker->last_id;
 #endif