On Tue, Feb 26, 2013 at 01:04:02PM -0500, Yonit Halperin wrote: > This patch only employs setting the stream parameters based on > the initial given bit-rate, the latency, and the encoding size. > Later patches will also employ mjpeg_encoder response to client reports, > and its control over frame drops. > > The patch also removes old stream bit rate calculations that weren't > used. ACK > --- > server/main_channel.c | 5 +++ > server/main_channel.h | 1 + > server/red_worker.c | 121 ++++++++++++++++++++++++++------------------------ > 3 files changed, 68 insertions(+), 59 deletions(-) > > diff --git a/server/main_channel.c b/server/main_channel.c > index 4fdd869..8cc7555 100644 > --- a/server/main_channel.c > +++ b/server/main_channel.c > @@ -1152,6 +1152,11 @@ uint64_t main_channel_client_get_bitrate_per_sec(MainChannelClient *mcc) > return mcc->bitrate_per_sec; > } > > +uint64_t main_channel_client_get_roundtrip_ms(MainChannelClient *mcc) > +{ > + return mcc->latency / 1000; > +} > + > static void main_channel_client_migrate(RedChannelClient *rcc) > { > reds_on_main_channel_migrate(SPICE_CONTAINEROF(rcc, MainChannelClient, base)); > diff --git a/server/main_channel.h b/server/main_channel.h > index 285a009..08f919c 100644 > --- a/server/main_channel.h > +++ b/server/main_channel.h > @@ -68,6 +68,7 @@ uint32_t main_channel_client_get_link_id(MainChannelClient *mcc); > > int main_channel_client_is_low_bandwidth(MainChannelClient *mcc); > uint64_t main_channel_client_get_bitrate_per_sec(MainChannelClient *mcc); > +uint64_t main_channel_client_get_roundtrip_ms(MainChannelClient *mcc); > int main_channel_is_connected(MainChannel *main_chan); > RedChannelClient* main_channel_client_get_base(MainChannelClient* mcc); > > diff --git a/server/red_worker.c b/server/red_worker.c > index 5043c10..470ad7a 100644 > --- a/server/red_worker.c > +++ b/server/red_worker.c > @@ -116,14 +116,11 @@ > #define RED_STREAM_FRAMES_RESET_CONDITION 100 > #define RED_STREAM_MIN_SIZE (96 * 96) > #define RED_STREAM_INPUT_FPS_TIMEOUT (5 * 1000) // 5 sec > +#define RED_STREAM_CHANNEL_CAPACITY 0.8 > > #define FPS_TEST_INTERVAL 1 > #define MAX_FPS 30 > > -//best bit rate per pixel base on 13000000 bps for frame size 720x576 pixels and 25 fps > -#define BEST_BIT_RATE_PER_PIXEL 38 > -#define WORST_BIT_RATE_PER_PIXEL 4 > - > #define RED_COMPRESS_BUF_SIZE (1024 * 64) > > #define ZLIB_DEFAULT_COMPRESSION_LEVEL 3 > @@ -415,6 +412,9 @@ typedef struct ImageItem { > > typedef struct Drawable Drawable; > > +typedef struct DisplayChannel DisplayChannel; > +typedef struct DisplayChannelClient DisplayChannelClient; > + > enum { > STREAM_FRAME_NONE, > STREAM_FRAME_NATIVE, > @@ -432,7 +432,6 @@ struct Stream { > int top_down; > Stream *next; > RingItem link; > - int bit_rate; > > SpiceTimer *input_fps_timer; > uint32_t num_input_frames; > @@ -455,6 +454,7 @@ typedef struct StreamAgent { > Stream *stream; > uint64_t last_send_time; > MJpegEncoder *mjpeg_encoder; > + DisplayChannelClient *dcc; > > int frames; > int drops; > @@ -526,9 +526,6 @@ typedef struct FreeList { > WaitForChannels wait; > } FreeList; > > -typedef struct DisplayChannel DisplayChannel; > -typedef struct DisplayChannelClient DisplayChannelClient; > - > typedef struct { > DisplayChannelClient *dcc; > RedCompressBuf *bufs_head; > @@ -681,6 +678,7 @@ struct DisplayChannelClient { > QRegion surface_client_lossy_region[NUM_SURFACES]; > > StreamAgent stream_agents[NUM_STREAMS]; > + int use_mjpeg_encoder_rate_control; > }; > > struct DisplayChannel { > @@ -974,6 +972,7 @@ typedef struct RedWorker { > Ring streams; > ItemTrace items_trace[NUM_TRACE_ITEMS]; > uint32_t next_item_trace; > + uint64_t streams_size_total; > > QuicData quic_data; > QuicContext *quic; > @@ -1049,7 +1048,6 @@ static int red_display_free_some_independent_glz_drawables(DisplayChannelClient > static void red_display_free_glz_drawable(DisplayChannelClient *dcc, RedGlzDrawable *drawable); > static ImageItem *red_add_surface_area_image(DisplayChannelClient *dcc, int surface_id, > SpiceRect *area, PipeItem *pos, int can_lossy); > -static void reset_rate(DisplayChannelClient *dcc, StreamAgent *stream_agent); > static BitmapGradualType _get_bitmap_graduality_level(RedWorker *worker, SpiceBitmap *bitmap, > uint32_t group_id); > static inline int _stride_is_extra(SpiceBitmap *bitmap); > @@ -2604,6 +2602,7 @@ static void red_stop_stream(RedWorker *worker, Stream *stream) > stream->refs++; > red_channel_client_pipe_add(&dcc->common.base, &stream_agent->destroy_item); > } > + worker->streams_size_total -= stream->width * stream->height; > ring_remove(&stream->link); > red_release_stream(worker, stream); > } > @@ -2849,38 +2848,43 @@ static inline Stream *red_alloc_stream(RedWorker *worker) > return stream; > } > > -static int get_bit_rate(DisplayChannelClient *dcc, > - int width, int height) > +static uint64_t red_stream_get_initial_bit_rate(DisplayChannelClient *dcc, > + Stream *stream) > { > - uint64_t bit_rate = width * height * BEST_BIT_RATE_PER_PIXEL; > + uint64_t max_bit_rate; > MainChannelClient *mcc; > - int is_low_bandwidth = 0; > > - if (dcc) { > - mcc = red_client_get_main(dcc->common.base.client); > - is_low_bandwidth = main_channel_client_is_low_bandwidth(mcc); > - } > + mcc = red_client_get_main(dcc->common.base.client); > + max_bit_rate = main_channel_client_get_bitrate_per_sec(mcc); > > - if (is_low_bandwidth) { > - bit_rate = MIN(main_channel_client_get_bitrate_per_sec(mcc) * 70 / 100, bit_rate); > - bit_rate = MAX(bit_rate, width * height * WORST_BIT_RATE_PER_PIXEL); > - } > - return bit_rate; > + > + /* dividing the available bandwidth among the active streams, and saving > + * (1-RED_STREAM_CHANNEL_CAPACITY) of it for other messages */ > + return (RED_STREAM_CHANNEL_CAPACITY * max_bit_rate * > + stream->width * stream->height) / dcc->common.worker->streams_size_total; > } > > -static int get_minimal_bit_rate(RedWorker *worker, int width, int height) > +static uint32_t red_stream_mjpeg_encoder_get_roundtrip(void *opaque) > { > - RingItem *item; > - DisplayChannelClient *dcc; > - int ret = INT_MAX; > + StreamAgent *agent = opaque; > + int roundtrip; > > - WORKER_FOREACH_DCC(worker, item, dcc) { > - int bit_rate = get_bit_rate(dcc, width, height); > - if (bit_rate < ret) { > - ret = bit_rate; > - } > + spice_assert(agent); > + roundtrip = red_channel_client_get_roundtrip_ms(&agent->dcc->common.base); > + if (roundtrip < 0) { > + MainChannelClient *mcc = red_client_get_main(agent->dcc->common.base.client); > + roundtrip = main_channel_client_get_roundtrip_ms(mcc); > } > - return ret; > + > + return roundtrip; > +} > + > +static uint32_t red_stream_mjpeg_encoder_get_source_fps(void *opaque) > +{ > + StreamAgent *agent = opaque; > + > + spice_assert(agent); > + return agent->stream->input_fps; > } > > static void red_display_create_stream(DisplayChannelClient *dcc, Stream *stream) > @@ -2898,8 +2902,20 @@ static void red_display_create_stream(DisplayChannelClient *dcc, Stream *stream) > } > agent->drops = 0; > agent->fps = MAX_FPS; > - reset_rate(dcc, agent); > - agent->mjpeg_encoder = mjpeg_encoder_new(FALSE, 0, NULL, NULL); > + agent->dcc = dcc; > + > + if (dcc->use_mjpeg_encoder_rate_control) { > + MJpegEncoderRateControlCbs mjpeg_cbs; > + uint64_t initial_bit_rate; > + > + mjpeg_cbs.get_roundtrip_ms = red_stream_mjpeg_encoder_get_roundtrip; > + mjpeg_cbs.get_source_fps = red_stream_mjpeg_encoder_get_source_fps; > + > + initial_bit_rate = red_stream_get_initial_bit_rate(dcc, stream); > + agent->mjpeg_encoder = mjpeg_encoder_new(TRUE, initial_bit_rate, &mjpeg_cbs, agent); > + } else { > + agent->mjpeg_encoder = mjpeg_encoder_new(FALSE, 0, NULL, NULL); > + } > red_channel_client_pipe_add(&dcc->common.base, &agent->create_item); > } > > @@ -2929,8 +2945,6 @@ static void red_create_stream(RedWorker *worker, Drawable *drawable) > RingItem *dcc_ring_item; > Stream *stream; > SpiceRect* src_rect; > - int stream_width; > - int stream_height; > > spice_assert(!drawable->stream); > > @@ -2940,8 +2954,6 @@ static void red_create_stream(RedWorker *worker, Drawable *drawable) > > spice_assert(drawable->red_drawable->type == QXL_DRAW_COPY); > src_rect = &drawable->red_drawable->u.copy.src_area; > - stream_width = src_rect->right - src_rect->left; > - stream_height = src_rect->bottom - src_rect->top; > > ring_add(&worker->streams, &stream->link); > stream->current = drawable; > @@ -2950,7 +2962,6 @@ static void red_create_stream(RedWorker *worker, Drawable *drawable) > stream->height = src_rect->bottom - src_rect->top; > stream->dest_area = drawable->red_drawable->bbox; > stream->refs = 1; > - stream->bit_rate = get_minimal_bit_rate(worker, stream_width, stream_height); > SpiceBitmap *bitmap = &drawable->red_drawable->u.copy.src_bitmap->u.bitmap; > stream->top_down = !!(bitmap->flags & SPICE_BITMAP_FLAGS_TOP_DOWN); > drawable->stream = stream; > @@ -2960,13 +2971,14 @@ static void red_create_stream(RedWorker *worker, Drawable *drawable) > stream->num_input_frames = 0; > stream->input_fps_timer_start = red_now(); > stream->input_fps = MAX_FPS; > + worker->streams_size_total += stream->width * stream->height; > + worker->stream_count++; > WORKER_FOREACH_DCC(worker, dcc_ring_item, dcc) { > red_display_create_stream(dcc, stream); > } > - worker->stream_count++; > spice_debug("stream %d %dx%d (%d, %d) (%d, %d)", (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->height, stream->dest_area.left, stream->dest_area.top, > + stream->dest_area.right, stream->dest_area.bottom); > return; > } > > @@ -2995,6 +3007,7 @@ static void red_display_client_init_streams(DisplayChannelClient *dcc) > red_channel_pipe_item_init(channel, &agent->create_item, PIPE_ITEM_TYPE_STREAM_CREATE); > red_channel_pipe_item_init(channel, &agent->destroy_item, PIPE_ITEM_TYPE_STREAM_DESTROY); > } > + dcc->use_mjpeg_encoder_rate_control = TRUE; > } > > static void red_display_destroy_streams(DisplayChannelClient *dcc) > @@ -3110,19 +3123,6 @@ static inline int red_is_next_stream_frame(RedWorker *worker, const Drawable *ca > FALSE); > } > > -static void reset_rate(DisplayChannelClient *dcc, StreamAgent *stream_agent) > -{ > - Stream *stream = stream_agent->stream; > - int rate; > - > - rate = get_bit_rate(dcc, stream->width, stream->height); > - if (rate == stream->bit_rate) { > - return; > - } > - > - /* MJpeg has no rate limiting anyway, so do nothing */ > -} > - > static int display_channel_client_is_low_bandwidth(DisplayChannelClient *dcc) > { > return main_channel_client_is_low_bandwidth( > @@ -8419,9 +8419,12 @@ static inline int red_marshall_stream_data(RedChannelClient *rcc, > StreamAgent *agent = &dcc->stream_agents[get_stream_id(worker, stream)]; > uint64_t time_now = red_now(); > size_t outbuf_size; > - if (time_now - agent->last_send_time < (1000 * 1000 * 1000) / agent->fps) { > - agent->frames--; > - return TRUE; > + > + if (!dcc->use_mjpeg_encoder_rate_control) { > + if (time_now - agent->last_send_time < (1000 * 1000 * 1000) / agent->fps) { > + agent->frames--; > + return TRUE; > + } > } > > outbuf_size = dcc->send_data.stream_outbuf_size; > @@ -8432,7 +8435,7 @@ static inline int red_marshall_stream_data(RedChannelClient *rcc, > drawable->red_drawable->mm_time); > switch (ret) { > case MJPEG_ENCODER_FRAME_DROP: > - spice_warning("mjpeg rate control is not supported yet"); > + spice_assert(dcc->use_mjpeg_encoder_rate_control); > return TRUE; > case MJPEG_ENCODER_FRAME_UNSUPPORTED: > return FALSE; > -- > 1.8.1 > > _______________________________________________ > Spice-devel mailing list > Spice-devel@xxxxxxxxxxxxxxxxxxxxx > http://lists.freedesktop.org/mailman/listinfo/spice-devel _______________________________________________ Spice-devel mailing list Spice-devel@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/spice-devel