diff options
author | Yonit Halperin <yhalperi@redhat.com> | 2009-11-29 15:23:03 +0200 |
---|---|---|
committer | Yaniv Kamay <ykamay@redhat.com> | 2009-11-30 18:45:06 +0200 |
commit | 00d5bf8b958462ff68fa59bf4007543893bba9c7 (patch) | |
tree | c0304d72df4da6ec1b93b0171868a672af32ea52 /server | |
parent | 6c5966d8ed8ff248ca21900aaf2350aac87f68e4 (diff) | |
download | spice-00d5bf8b958462ff68fa59bf4007543893bba9c7.tar.gz spice-00d5bf8b958462ff68fa59bf4007543893bba9c7.tar.xz spice-00d5bf8b958462ff68fa59bf4007543893bba9c7.zip |
spice server: heuristic for distinguishing between "real" videos and textual streams
Diffstat (limited to 'server')
-rw-r--r-- | server/red_common.h | 7 | ||||
-rw-r--r-- | server/red_dispatcher.c | 3 | ||||
-rw-r--r-- | server/red_worker.c | 128 | ||||
-rw-r--r-- | server/reds.c | 47 |
4 files changed, 160 insertions, 25 deletions
diff --git a/server/red_common.h b/server/red_common.h index 9d744fbd..fafb2841 100644 --- a/server/red_common.h +++ b/server/red_common.h @@ -88,6 +88,13 @@ typedef enum { IMAGE_COMPRESS_OFF, } image_compression_t; +enum { + STREAM_VIDEO_INVALID, + STREAM_VIDEO_OFF, + STREAM_VIDEO_ALL, + STREAM_VIDEO_FILTER +}; + static inline uint64_t get_time_stamp() { struct timespec time_space; diff --git a/server/red_dispatcher.c b/server/red_dispatcher.c index f98301ac..dae33d87 100644 --- a/server/red_dispatcher.c +++ b/server/red_dispatcher.c @@ -345,7 +345,8 @@ void red_dispatcher_set_mm_time(uint32_t mm_time) static inline int calc_compression_level() { - if (streaming_video || (image_compression != IMAGE_COMPRESS_QUIC)) { + ASSERT(streaming_video != STREAM_VIDEO_INVALID); + if ((streaming_video != STREAM_VIDEO_OFF) || (image_compression != IMAGE_COMPRESS_QUIC)) { return 0; } else { return 1; diff --git a/server/red_worker.c b/server/red_worker.c index 702d5ffd..436bfa2e 100644 --- a/server/red_worker.c +++ b/server/red_worker.c @@ -74,7 +74,9 @@ #define RED_STREAM_DETACTION_MAX_DELTA ((1000 * 1000 * 1000) / 5) // 1/5 sec #define RED_STREAM_CONTINUS_MAX_DELTA ((1000 * 1000 * 1000) / 2) // 1/2 sec #define RED_STREAM_TIMOUT (1000 * 1000 * 1000) -#define RED_STREAM_START_CONDITION 20 +#define RED_STREAM_FRAMES_START_CONDITION 20 +#define RED_STREAM_GRADUAL_FRAMES_START_CONDITION 0.2 +#define RED_STREAM_FRAMES_RESET_CONDITION 100 #define FPS_TEST_INTERVAL 1 #define MAX_FPS 30 @@ -763,6 +765,13 @@ typedef struct DrawItem { Shadow *shadow; } DrawItem; +typedef enum { + BITMAP_GRADUAL_INVALID, + BITMAP_GRADUAL_NOT_AVAIL, + BITMAP_GRADUAL_TRUE, + BITMAP_GRADUAL_FALSE, +} BitmapGradualType; + struct Drawable { uint8_t refs; RingItem list_link; @@ -777,10 +786,13 @@ struct Drawable { red_time_t creation_time; int frames_count; + int gradual_frames_count; + int last_gradual_frame; Stream *stream; #ifdef STREAM_TRACE int streamable; #endif + BitmapGradualType copy_bitmap_graduality; }; typedef struct _Drawable _Drawable; @@ -846,6 +858,8 @@ typedef struct DrawContext { typedef struct ItemTrace { red_time_t time; int frames_count; + int gradual_frames_count; + int last_gradual_frame; int width; int height; Rect dest_area; @@ -987,6 +1001,8 @@ static void red_display_release_stream_clip(DisplayChannel* channel, StreamClipI static int red_display_free_some_independent_glz_drawables(DisplayChannel *channel); static void red_display_free_glz_drawable(DisplayChannel *channel, RedGlzDrawable *drawable); static void reset_rate(StreamAgent *stream_agent); +static int _bitmap_is_gradual(RedWorker *worker, Bitmap *bitmap); +static inline int _stride_is_extra(Bitmap *bitmap); #ifdef DUMP_BITMAP static void dump_bitmap(RedWorker *worker, Bitmap *bitmap); @@ -1514,6 +1530,8 @@ 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->frames_count = item->frames_count; + trace->gradual_frames_count = item->gradual_frames_count; + trace->last_gradual_frame = item->last_gradual_frame; Rect* src_area = &item->qxl_drawable->u.copy.src_area; trace->width = src_area->right - src_area->left; trace->height = src_area->bottom - src_area->top; @@ -2789,6 +2807,70 @@ static inline void pre_stream_item_swap(RedWorker *worker, Stream *stream) agent->drops = 0; } +static inline void red_update_copy_graduality(RedWorker* worker, Drawable *drawable) +{ + QXLImage *qxl_image; + ASSERT(drawable->qxl_drawable->type == QXL_DRAW_COPY); + + if (worker->streaming_video != STREAM_VIDEO_FILTER) { + drawable->copy_bitmap_graduality = BITMAP_GRADUAL_INVALID; + return; + } + + if (drawable->copy_bitmap_graduality != BITMAP_GRADUAL_INVALID) { + return; // already set + } + + qxl_image = (QXLImage *)get_virt(worker, drawable->qxl_drawable->u.copy.src_bitmap, + sizeof(QXLImage)); + + if (!BITMAP_FMT_IS_RGB[qxl_image->bitmap.format] || _stride_is_extra(&qxl_image->bitmap) || + (qxl_image->bitmap.flags & QXL_BITMAP_UNSTABLE)) { + drawable->copy_bitmap_graduality = BITMAP_GRADUAL_NOT_AVAIL; + } else { + if (_bitmap_is_gradual(worker, &qxl_image->bitmap)) { + drawable->copy_bitmap_graduality = BITMAP_GRADUAL_TRUE; + } else { + drawable->copy_bitmap_graduality = BITMAP_GRADUAL_FALSE; + } + } +} + +static inline int red_is_stream_start(Drawable *drawable) +{ + return ((drawable->frames_count >= RED_STREAM_FRAMES_START_CONDITION) && + (drawable->gradual_frames_count >= + (RED_STREAM_GRADUAL_FRAMES_START_CONDITION * drawable->frames_count))); +} + +static void red_stream_add_frame(RedWorker* worker, Drawable *frame_drawable, + int frames_count, + int gradual_frames_count, + int last_gradual_frame) +{ + red_update_copy_graduality(worker, frame_drawable); + frame_drawable->frames_count = frames_count + 1; + frame_drawable->gradual_frames_count = gradual_frames_count; + + if (frame_drawable->copy_bitmap_graduality != BITMAP_GRADUAL_FALSE) { + if ((frame_drawable->frames_count - last_gradual_frame) > + RED_STREAM_FRAMES_RESET_CONDITION) { + frame_drawable->frames_count = 1; + frame_drawable->gradual_frames_count = 1; + } else { + frame_drawable->gradual_frames_count++; + } + + frame_drawable->last_gradual_frame = frame_drawable->frames_count; + } else { + frame_drawable->last_gradual_frame = last_gradual_frame; + } + + if (red_is_stream_start(frame_drawable)) { + red_create_stream(worker, frame_drawable); + } +} + static inline void red_stream_maintenance(RedWorker *worker, Drawable *candidate, Drawable *prev) { Stream *stream; @@ -2802,7 +2884,8 @@ static inline void red_stream_maintenance(RedWorker *worker, Drawable *candidate return; } #else - if (!worker->streaming_video || !red_is_next_stream_frame(worker, candidate, prev) { + if ((worker->streaming_video == STREAM_VIDEO_OFF) || + !red_is_next_stream_frame(worker, candidate, prev) { return; } #endif @@ -2831,9 +2914,11 @@ static inline void red_stream_maintenance(RedWorker *worker, Drawable *candidate } } #endif - } else if ((candidate->frames_count = prev->frames_count + 1) == - RED_STREAM_START_CONDITION) { - red_create_stream(worker, candidate); + } else { + red_stream_add_frame(worker, candidate, + prev->frames_count, + prev->gradual_frames_count, + prev->last_gradual_frame); } } @@ -2937,10 +3022,10 @@ static inline void red_use_stream_trace(RedWorker *worker, Drawable *drawable) for (; trace < trace_end; trace++) { if (__red_is_next_stream_frame(worker, drawable, trace->width, trace->height, &trace->dest_area, trace->time, NULL)) { - if ((drawable->frames_count = trace->frames_count + 1) == RED_STREAM_START_CONDITION) { - red_create_stream(worker, drawable); - } - return; + red_stream_add_frame(worker, drawable, + trace->frames_count, + trace->gradual_frames_count, + trace->last_gradual_frame); } } } @@ -3289,7 +3374,7 @@ static inline void red_update_streamable(RedWorker *worker, Drawable *drawable, { QXLImage *qxl_image; - if (!worker->streaming_video) { + if (worker->streaming_video == STREAM_VIDEO_OFF) { return; } @@ -5610,8 +5695,12 @@ static inline int red_compress_image(DisplayChannel *display_channel, if ((src->x < MIN_DIMENSION_TO_QUIC) || (src->y < MIN_DIMENSION_TO_QUIC)) { quic_compress = FALSE; } else { - quic_compress = BITMAP_FMT_IS_RGB[src->format] && - _bitmap_is_gradual(display_channel->base.worker, src); + if (drawable->copy_bitmap_graduality == BITMAP_GRADUAL_INVALID) { + quic_compress = BITMAP_FMT_IS_RGB[src->format] && + _bitmap_is_gradual(display_channel->base.worker, src); + } else { + quic_compress = (drawable->copy_bitmap_graduality == BITMAP_GRADUAL_TRUE); + } } } else { quic_compress = FALSE; @@ -8484,7 +8573,20 @@ static void handle_dev_input(EventListener *listener, uint32_t events) break; case RED_WORKER_MESSAGE_SET_STREAMING_VIDEO: receive_data(worker->channel, &worker->streaming_video, sizeof(uint32_t)); - red_printf("sv %u", worker->streaming_video); + ASSERT(worker->streaming_video != STREAM_VIDEO_INVALID); + switch(worker->streaming_video) { + case STREAM_VIDEO_ALL: + red_printf("sv all"); + break; + case STREAM_VIDEO_FILTER: + red_printf("sv filter"); + break; + case STREAM_VIDEO_OFF: + red_printf("sv off"); + break; + default: + red_printf("sv invalid"); + } break; case RED_WORKER_MESSAGE_SET_MOUSE_MODE: receive_data(worker->channel, &worker->mouse_mode, sizeof(uint32_t)); diff --git a/server/reds.c b/server/reds.c index 8ea9f56f..c10f0ca3 100644 --- a/server/reds.c +++ b/server/reds.c @@ -81,7 +81,7 @@ static struct in_addr spice_addr = {INADDR_ANY}; static int ticketing_enabled = 1; //Ticketing is enabled by default static pthread_mutex_t *lock_cs; static long *lock_count; -uint32_t streaming_video = TRUE; +uint32_t streaming_video = STREAM_VIDEO_FILTER; image_compression_t image_compression = IMAGE_COMPRESS_AUTO_GLZ; void *red_tunnel = NULL; int agent_mouse = TRUE; @@ -3494,7 +3494,21 @@ static void reds_do_info_spice() core->term_printf(core, " ic=invalid"); } - core->term_printf(core, " sv=%s", streaming_video ? "on" : "off"); + switch (streaming_video) { + case STREAM_VIDEO_ALL: + core->term_printf(core, " sv=all"); + break; + case STREAM_VIDEO_FILTER: + core->term_printf(core, " sv=filter"); + break; + case STREAM_VIDEO_OFF: + core->term_printf(core, " sv=off"); + break; + case STREAM_VIDEO_INVALID: + default: + core->term_printf(core, " sv=invalid"); + + } core->term_printf(core, " playback-compression=%s\n", snd_get_playback_compression() ? "on" : "off"); } @@ -3536,17 +3550,29 @@ static void reds_do_set_image_compression(const char *val) set_image_compression(real_val); } -static void reds_do_set_streaming_video(const char *val) +static int reds_get_streaming_video(const char *val) { - uint32_t new_val; if (strcmp(val, "on") == 0) { - new_val = TRUE; - } else if (strcmp(val, "off") == 0) { - new_val = FALSE; + return STREAM_VIDEO_FILTER; + } else if (strcmp(val, "filter") == 0) { + return STREAM_VIDEO_FILTER; + } else if (strcmp(val, "all") == 0) { + return STREAM_VIDEO_ALL; + } else if (strcmp(val, "off") == 0){ + return STREAM_VIDEO_OFF; } else { + return STREAM_VIDEO_INVALID; + } +} + +static void reds_do_set_streaming_video(const char *val) +{ + uint32_t new_val = reds_get_streaming_video(val); + if (new_val == STREAM_VIDEO_INVALID) { core->term_printf(core, "bad streaming video arg\n"); return; } + if (new_val == streaming_video) { return; } @@ -3884,9 +3910,8 @@ int __attribute__ ((visibility ("default"))) spice_parse_args(const char *in_arg if (!val) { goto error; } - if (strcmp(val, "off") == 0) { - streaming_video = FALSE; - } else if (strcmp(val, "on") != 0) { + streaming_video = reds_get_streaming_video(val); + if (streaming_video == STREAM_VIDEO_INVALID) { goto error; } break; @@ -4583,7 +4608,7 @@ static void add_monitor_action_commands(QTermInterface *mon) mon->add_action_command_handler(mon, "spice", "set_streaming_video", "s", reds_do_set_streaming_video, "", - "<on|off>"); + "<on|filter|all|off>"); mon->add_action_command_handler(mon, "spice", "set_playback_compression", "s", reds_do_set_playback_compression, "", |