[Spice-devel] [PATCH spice 10/11] server/video-streams: adjust mjpeg quality and frame rate according to the current bit rate

Christophe Fergeau cfergeau at redhat.com
Tue Apr 10 05:48:47 PDT 2012


On Sun, Apr 08, 2012 at 06:43:19PM +0300, Yonit Halperin wrote:
> Previously, the mjpeg quality was always 70. The frame rate was tuned
> according to the frames' congestion in the pipe.
> This patch sets the mjpeg quality and frame rate according
> to the compressed size of the frames and the currently available bit
> rate.
> The compression size is estimated for different jpeg qualities,
> and the bit rate is evaluated using qos queries (see red_channel).
> The bit rate and compression size are monitored for major changes, and
> when they occur, the mjpeg settings are re-evaluated.
> In addition, the settings are fine-tuned correspondingly to the frames
> pipe congestion.
> 
> Signed-off-by: Yonit Halperin <yhalperi at redhat.com>
> ---
>  server/red_worker.c |  385 ++++++++++++++++++++++++++++++++++++++++++++++-----
>  1 files changed, 347 insertions(+), 38 deletions(-)

Sorry, but NACK because of the red_worker.c size increase and
$ wc -l red_worker.c
11341 red_worker.c

I'm under the impression that the 'jpeg' struct and the methods
manipulating it could be moved to a separate file.

Christophe

> 
> diff --git a/server/red_worker.c b/server/red_worker.c
> index a9942cf..92e1197 100644
> --- a/server/red_worker.c
> +++ b/server/red_worker.c
> @@ -114,7 +114,8 @@
>  #define RED_STREAM_MIN_SIZE (96 * 96)
>  
>  #define FPS_TEST_INTERVAL 1
> -#define MAX_FPS 30
> +#define STREAM_MAX_FPS 30
> +#define STREAM_MIN_FPS 1
>  
>  //best bit rate per pixel base on 13000000 bps for frame size 720x576 pixels and 25 fps
>  #define BEST_BIT_RATE_PER_PIXEL 38
> @@ -396,6 +397,13 @@ struct Stream {
>      int bit_rate;
>  };
>  
> +#define STREAM_JPEG_QUALITY_SAMPLE_NUM 4
> +static const int stream_jpeg_quality_samples[STREAM_JPEG_QUALITY_SAMPLE_NUM] = {15, 25, 50, 70};
> +
> +#define STREAM_FRAME_SIZE_CHANGE_TH 1.5
> +#define STREAM_BIT_RATE_CHANGE_TH 1.25
> +#define STREAM_AVERAGE_SIZE_WINDOW 3
> +
>  typedef struct StreamAgent {
>      QRegion vis_region;
>      PipeItem create_item;
> @@ -403,6 +411,34 @@ typedef struct StreamAgent {
>      Stream *stream;
>      uint64_t last_send_time;
>  
> +    /*
> +      Adjusting the stream jpeg quality and frame rate (fps):
> +      When during_sampling=TRUE, we compress different frames with different
> +      jpeg quality. By using (1) the resulting compression ratio, (2) the current
> +      channel bandwidth, and (3) the existance of other streams,
> +      we evaulate the max frame frequency for the stream with the given quality,
> +      and we choose the highest quality that will allow a reasonable frame rate.
> +      during_sampling is set for new streams and also when the bandwidth and/or
> +      average frame size significantly change.
> +    */
> +    struct {
> +        int quality_id;
> +        uint64_t quality_sample_size[STREAM_JPEG_QUALITY_SAMPLE_NUM];
> +        int during_sampling;
> +        /* low limit for the the current sampling */
> +        int min_sample_quality_id;
> +        int min_sample_quality_fps; // min fps for the given quality
> +        /* tracking the best sampled fps so far */
> +        int max_sampled_fps;
> +        int max_sampled_fps_quality_id;
> +        int byte_rate;
> +        /* tracking the average frame size with the current jpeg quality */
> +        uint64_t size_sum;
> +        int size_summed_count;
> +        uint64_t recent_size_sum;
> +        int recent_size_summed_count;
> +    } jpeg;
> +
>      int frames;
>      int drops;
>      int fps;
> @@ -938,6 +974,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;
> @@ -2512,6 +2549,7 @@ static void red_attach_stream(RedWorker *worker, Drawable *drawable, Stream *str
>              region_clone(&agent->vis_region, &drawable->tree_item.base.rgn);
>              push_stream_clip_by_drawable(dcc, agent, drawable);
>          }
> +        agent->frames++;
>      }
>  }
>  
> @@ -2522,6 +2560,7 @@ static void red_stop_stream(RedWorker *worker, Stream *stream)
>  
>      spice_assert(ring_item_is_linked(&stream->link));
>      spice_assert(!stream->current);
> +    spice_debug("id %ld", stream - worker->streams_buf);
>      WORKER_FOREACH_DCC(worker, item, dcc) {
>          StreamAgent *stream_agent;
>          stream_agent = &dcc->stream_agents[stream - worker->streams_buf];
> @@ -2530,6 +2569,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);
>  }
> @@ -2741,11 +2781,10 @@ static int get_minimal_bit_rate(RedWorker *worker, int width, int height)
>      return ret;
>  }
>  
> -static void red_display_create_stream(DisplayChannelClient *dcc, Stream *stream)
> +static void red_stream_agent_init(DisplayChannelClient *dcc, Stream *stream)
>  {
>      StreamAgent *agent = &dcc->stream_agents[stream - dcc->common.worker->streams_buf];
>  
> -    stream->refs++;
>      spice_assert(region_is_empty(&agent->vis_region));
>      if (stream->current) {
>          agent->frames = 1;
> @@ -2754,8 +2793,36 @@ static void red_display_create_stream(DisplayChannelClient *dcc, Stream *stream)
>          agent->frames = 0;
>      }
>      agent->drops = 0;
> -    agent->fps = MAX_FPS;
> +    agent->fps = STREAM_MAX_FPS;
>      reset_rate(dcc, agent);
> +    agent->jpeg.quality_id = STREAM_JPEG_QUALITY_SAMPLE_NUM / 2;
> +    memset(agent->jpeg.quality_sample_size, 0,
> +           sizeof(agent->jpeg.quality_sample_size[0]) * STREAM_JPEG_QUALITY_SAMPLE_NUM);
> +    agent->jpeg.byte_rate = 0;
> +    agent->jpeg.max_sampled_fps = 0;
> +    agent->jpeg.max_sampled_fps_quality_id = 0;
> +    agent->jpeg.min_sample_quality_id = 0;
> +    agent->jpeg.min_sample_quality_fps = 0;
> +    agent->jpeg.size_sum = 0;
> +    agent->jpeg.size_summed_count = 0;
> +    agent->jpeg.recent_size_sum = 0;
> +    agent->jpeg.recent_size_summed_count = 0;
> +    agent->jpeg.during_sampling = FALSE;
> +}
> +
> +static void red_display_create_stream(DisplayChannelClient *dcc, Stream *stream)
> +{
> +    StreamAgent *agent = &dcc->stream_agents[stream - dcc->common.worker->streams_buf];
> +
> +    stream->refs++;
> +
> +    spice_debug("id %ld %dx%d dest (%d,%d), (%d, %d)",
> +                stream - dcc->common.worker->streams_buf,
> +                stream->width, stream->height,
> +                stream->dest_area.left, stream->dest_area.top,
> +                stream->dest_area.right, stream->dest_area.bottom);
> +    red_stream_agent_init(dcc, stream);
> +
>      red_channel_client_pipe_add(&dcc->common.base, &agent->create_item);
>  }
>  
> @@ -2794,6 +2861,7 @@ 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;
> +    worker->streams_size_total += stream->width * stream->height;
>  
>      WORKER_FOREACH_DCC(worker, dcc_ring_item, dcc) {
>          red_display_create_stream(dcc, stream);
> @@ -2945,16 +3013,9 @@ static void reset_rate(DisplayChannelClient *dcc, StreamAgent *stream_agent)
>      /* 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(
> -        red_client_get_main(red_channel_client_get_client(&dcc->common.base)));
> -}
> -
>  static inline void pre_stream_item_swap(RedWorker *worker, Stream *stream)
>  {
>      DrawablePipeItem *dpi;
> -    DisplayChannelClient *dcc;
>      int index;
>      StreamAgent *agent;
>      RingItem *ring_item;
> @@ -2967,35 +3028,10 @@ static inline void pre_stream_item_swap(RedWorker *worker, Stream *stream)
>  
>      index = stream - worker->streams_buf;
>      DRAWABLE_FOREACH_DPI(stream->current, ring_item, dpi) {
> -        dcc = dpi->dcc;
> -        if (!display_channel_client_is_low_bandwidth(dcc)) {
> -            continue;
> -        }
> -        agent = &dcc->stream_agents[index];
> -
> +        agent = &dpi->dcc->stream_agents[index];
>          if (pipe_item_is_linked(&dpi->dpi_pipe_item)) {
>              ++agent->drops;
>          }
> -
> -        if (agent->frames / agent->fps < FPS_TEST_INTERVAL) {
> -            agent->frames++;
> -            return;
> -        }
> -
> -        double drop_factor = ((double)agent->frames - (double)agent->drops) /
> -                             (double)agent->frames;
> -
> -        if (drop_factor == 1) {
> -            if (agent->fps < MAX_FPS) {
> -                agent->fps++;
> -            }
> -        } else if (drop_factor < 0.9) {
> -            if (agent->fps > 1) {
> -                agent->fps--;
> -            }
> -        }
> -        agent->frames = 1;
> -        agent->drops = 0;
>      }
>  }
>  
> @@ -8078,6 +8114,274 @@ static int encode_frame (RedWorker *worker, const SpiceRect *src,
>      return TRUE;
>  }
>  
> +static inline void red_stream_agent_jpeg_quality_set(StreamAgent *agent, int quality_id)
> +{
> +    if (!agent->jpeg.during_sampling) {
> +        agent->jpeg.quality_sample_size[agent->jpeg.quality_id] = 0;
> +    }
> +    agent->jpeg.size_sum = 0;
> +    agent->jpeg.size_summed_count = 0;
> +    agent->jpeg.recent_size_sum = 0;
> +    agent->jpeg.recent_size_summed_count = 0;
> +    agent->jpeg.quality_id = quality_id;
> +}
> +
> +/*
> +    Adjust the stream's jpeg quality and frame rate.
> +    We evaluate the compression ratio of different jpeg qualities;
> +    We compress successive frames with different qualities,
> +    and then we estimate the stream frame rate with the current jpeg quality
> +    and availalbe bit rate.
> +*/
> +static inline void red_stream_do_quality_size_sampling(DisplayChannelClient *dcc, StreamAgent *agent)
> +{
> +    int fps;
> +    int stream_id = agent - dcc->stream_agents;
> +
> +    spice_assert(agent->jpeg.during_sampling);
> +    if (agent->jpeg.quality_sample_size[agent->jpeg.quality_id] == 0) {
> +        return;
> +    }
> +
> +    fps = agent->jpeg.byte_rate / agent->jpeg.quality_sample_size[agent->jpeg.quality_id];
> +    spice_debug("stream %d: jpeg %d: %.2f (KB) fps %d",
> +                stream_id,
> +                stream_jpeg_quality_samples[agent->jpeg.quality_id],
> +                agent->jpeg.quality_sample_size[agent->jpeg.quality_id]/1000.0,
> +                fps);
> +
> +    if (fps > agent->jpeg.max_sampled_fps ||
> +        (fps == agent->jpeg.max_sampled_fps &&
> +         agent->jpeg.quality_id > agent->jpeg.max_sampled_fps_quality_id)) {
> +        agent->jpeg.max_sampled_fps = fps;
> +        agent->jpeg.max_sampled_fps_quality_id = agent->jpeg.quality_id;
> +    }
> +
> +    // assuming monotonicity
> +    if (fps > 5 && fps >= 0.75 * agent->jpeg.min_sample_quality_fps) {
> +        if (agent->jpeg.quality_id + 1 == STREAM_JPEG_QUALITY_SAMPLE_NUM ||
> +            agent->jpeg.quality_sample_size[agent->jpeg.quality_id + 1] != 0) {
> +            /* best quality has been reached, or the next better quality was
> +             * already sampled and didn't pass the fps threshold */
> +            goto complete_sample;
> +        } else {
> +            agent->jpeg.quality_id++;
> +        }
> +    } else {
> +        if (agent->jpeg.quality_id == 0 ||
> +            agent->jpeg.quality_id <= agent->jpeg.min_sample_quality_id) {
> +            goto complete_sample;
> +        } else if (agent->jpeg.quality_sample_size[agent->jpeg.quality_id - 1] != 0) {
> +            agent->jpeg.quality_id--;
> +            goto complete_sample;
> +        } else {
> +            agent->jpeg.quality_id--;
> +        }
> +    }
> +    return;
> +complete_sample:
> +    agent->jpeg.quality_id = MAX(agent->jpeg.quality_id,
> +                                 agent->jpeg.max_sampled_fps_quality_id);
> +    agent->fps = agent->jpeg.byte_rate /
> +                 agent->jpeg.quality_sample_size[agent->jpeg.quality_id];
> +    if (agent->jpeg.quality_id == agent->jpeg.min_sample_quality_id) {
> +        agent->fps = MAX(agent->fps, agent->jpeg.min_sample_quality_fps);
> +    }
> +    agent->fps = MIN(STREAM_MAX_FPS, agent->fps);
> +    agent->fps = MAX(STREAM_MIN_FPS, agent->fps);
> +    agent->jpeg.during_sampling = FALSE;
> +    agent->frames = 1;
> +    agent->drops = 0;
> +    agent->jpeg.max_sampled_fps = 0;
> +    agent->jpeg.max_sampled_fps_quality_id = 0;
> +    agent->jpeg.min_sample_quality_id = 0;
> +    agent->jpeg.min_sample_quality_fps = 0;
> +    agent->jpeg.size_sum = 0;
> +    agent->jpeg.size_summed_count = 0;
> +    agent->jpeg.recent_size_sum = agent->jpeg.quality_sample_size[agent->jpeg.quality_id];
> +    agent->jpeg.recent_size_summed_count = 1;
> +    memset(agent->jpeg.quality_sample_size, 0,
> +           sizeof(agent->jpeg.quality_sample_size[0]) * STREAM_JPEG_QUALITY_SAMPLE_NUM);
> +    spice_debug("STREAM QUALITY SAMPLE END %d: quality %d fps %d",
> +                 stream_id, stream_jpeg_quality_samples[agent->jpeg.quality_id], agent->fps);
> +}
> +
> +/*
> +    Fine tuning of the stream's frame rate and quality using
> +    the frames congestion in the pipe.
> +*/
> +static inline void red_stream_update_quality_by_drops(DisplayChannelClient *dcc,
> +                                                      StreamAgent *agent)
> +{
> +    int stream_id = agent - dcc->stream_agents;
> +
> +    if (agent->drops) {
> +        if (agent->frames / agent->fps >= FPS_TEST_INTERVAL) {
> +            double drop_factor = ((double)agent->frames - (double)agent->drops) /
> +                                  (double)agent->frames;
> +            if (drop_factor <= 0.9) {
> +                if (agent->fps <= 10 && agent->jpeg.quality_id > 0 ) {
> +                    red_stream_agent_jpeg_quality_set(agent, agent->jpeg.quality_id - 1);
> +                    spice_debug("stream %d quality--: jpeg %d fps %d", stream_id,
> +                                stream_jpeg_quality_samples[agent->jpeg.quality_id],
> +                                agent->fps);
> +                } else {
> +                    agent->fps--;
> +                    agent->fps = MAX(STREAM_MIN_FPS, agent->fps);
> +                    spice_debug("stream %d fps--: jpeg %d fps %d", stream_id,
> +                                stream_jpeg_quality_samples[agent->jpeg.quality_id],
> +                                agent->fps);
> +                }
> +            }
> +            agent->frames = 1;
> +            agent->drops = 0;
> +        }
> +    } else {
> +        if (agent->frames / agent->fps >= FPS_TEST_INTERVAL) {
> +            if (agent->fps >= 15 && agent->jpeg.quality_id < STREAM_JPEG_QUALITY_SAMPLE_NUM - 1) {
> +                /* being more strict when we want to increase quality */
> +                if (agent->frames / agent->fps >= 2 * FPS_TEST_INTERVAL) {
> +                    agent->jpeg.min_sample_quality_id = agent->jpeg.quality_id;
> +                    agent->jpeg.min_sample_quality_fps = agent->fps;
> +                    agent->jpeg.during_sampling = TRUE;
> +                    red_stream_do_quality_size_sampling(dcc, agent);
> +                    spice_debug("stream %d quality resampling: jpeg %d fps %d", stream_id,
> +                                stream_jpeg_quality_samples[agent->jpeg.quality_id],
> +                                agent->fps);
> +                    agent->frames = 1;
> +                    agent->drops = 0;
> +                } else {
> +                    agent->fps++;
> +                    agent->fps = MIN(STREAM_MAX_FPS, agent->fps);
> +                    spice_debug("stream %d fps++: jpeg %d fps %d", stream_id,
> +                               stream_jpeg_quality_samples[agent->jpeg.quality_id],
> +                               agent->fps);
> +                }
> +            } else {
> +                agent->fps++;
> +                agent->fps = MIN(STREAM_MAX_FPS, agent->fps);
> +                spice_debug("stream %d fps++: jpeg %d fps %d", stream_id,
> +                            stream_jpeg_quality_samples[agent->jpeg.quality_id],
> +                            agent->fps);
> +                agent->frames = 1;
> +                agent->drops = 0;
> +            }
> +        }
> +    }
> +}
> +
> +/*
> +    Monitor changes in the available byte rate for the stream,
> +    and/or in the stream's compressed frames size. If the changes
> +    pass a predefined threshold, we re-evaluate the stream's jpeg
> +    quality and frame rate.
> +*/
> +static void red_stream_update_quality(RedChannelClient *rcc, StreamAgent *agent)
> +{
> +    DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
> +    RedWorker *worker = dcc->common.worker;
> +    int stream_id = agent->stream - dcc->common.worker->streams_buf;
> +    int channel_bit_rate;
> +    int stream_byte_rate;
> +    float byte_rate_change;
> +    float size_change = 1;
> +    double size_avg_old = 0.0;
> +    double size_avg_new = 0.0;
> +
> +    channel_bit_rate = red_channel_client_get_qos_bit_rate(rcc);
> +
> +    if (channel_bit_rate == 0) {
> +        spice_assert(agent->jpeg.byte_rate == 0);
> +        red_stream_update_quality_by_drops(dcc, agent);
> +        return;
> +    }
> +
> +    stream_byte_rate = 0.8 * channel_bit_rate * (agent->stream->width * agent->stream->height) /
> +                       worker->streams_size_total / 8;
> +    if (agent->jpeg.byte_rate == 0) { // new stream
> +        agent->jpeg.byte_rate = stream_byte_rate;
> +        agent->jpeg.during_sampling = TRUE;
> +        agent->jpeg.min_sample_quality_id = 0;
> +        agent->jpeg.min_sample_quality_fps = 0;
> +    }
> +
> +    if (agent->jpeg.during_sampling) {
> +        red_stream_do_quality_size_sampling(dcc, agent);
> +        return;
> +    }
> +    spice_assert(agent->jpeg.quality_sample_size[agent->jpeg.quality_id]);
> +    byte_rate_change = (stream_byte_rate + 0.0) / agent->jpeg.byte_rate;
> +
> +    agent->jpeg.recent_size_sum += agent->jpeg.quality_sample_size[agent->jpeg.quality_id];
> +    agent->jpeg.recent_size_summed_count++;
> +    size_avg_new = (agent->jpeg.recent_size_sum + 0.0) / agent->jpeg.recent_size_summed_count;
> +    if (agent->jpeg.recent_size_summed_count >= STREAM_AVERAGE_SIZE_WINDOW &&
> +        agent->jpeg.size_summed_count > 0) {
> +        size_avg_old = (agent->jpeg.size_sum + 0.0) / agent->jpeg.size_summed_count;
> +        size_change = size_avg_new / size_avg_old;
> +    }
> +
> +    if (byte_rate_change > STREAM_BIT_RATE_CHANGE_TH) {
> +        spice_debug("stream %d BYTE RATE CHANGE >>: %.2f (%d-->%d prev-quality %d prev-fps %d",
> +                    stream_id, byte_rate_change, agent->jpeg.byte_rate, stream_byte_rate,
> +                    stream_jpeg_quality_samples[agent->jpeg.quality_id],
> +                    agent->fps);
> +        agent->jpeg.during_sampling = TRUE;
> +        /* byte rate has improved --> don't allow stream to deteriorate */
> +        agent->jpeg.min_sample_quality_id = agent->jpeg.quality_id;
> +        agent->jpeg.min_sample_quality_fps = agent->fps;
> +    } else if (1.0 / byte_rate_change > STREAM_BIT_RATE_CHANGE_TH) {
> +        spice_debug("stream %d BYTE RATE CHANGE <<: %.2f (%d-->%d) prev-quality %d prev-fps %d",
> +                    stream_id, byte_rate_change, agent->jpeg.byte_rate, stream_byte_rate,
> +                    stream_jpeg_quality_samples[agent->jpeg.quality_id],
> +                    agent->fps);
> +        if (agent->fps * size_avg_new > stream_byte_rate) {
> +            agent->jpeg.during_sampling = TRUE;
> +            agent->jpeg.min_sample_quality_id = 0;
> +            agent->jpeg.min_sample_quality_fps = 0;
> +        } else {
> +            spice_debug("stream byte rate is not limiting the current setting");
> +        }
> +    }
> +
> +    if (size_change > STREAM_FRAME_SIZE_CHANGE_TH) {
> +        spice_debug("stream %d SIZE CHANGE >>: %.2f (%.2f-->%.2f) prev-quality %d prev-fps %d",
> +                    stream_id, size_change, size_avg_old, size_avg_new,
> +                    stream_jpeg_quality_samples[agent->jpeg.quality_id],
> +                    agent->fps);
> +        if (agent->fps * size_avg_new > stream_byte_rate) {
> +            agent->jpeg.during_sampling = TRUE;
> +            agent->jpeg.min_sample_quality_id = 0;
> +            agent->jpeg.min_sample_quality_fps = 0;
> +        } else {
> +            spice_debug("stream frame size is not limiting current setting");
> +        }
> +    } else if (1.0 / size_change > STREAM_FRAME_SIZE_CHANGE_TH) {
> +        spice_debug("stream %d SIZE CHANGE <<: %.2f (%.2f-->%.2f) prev-quality %d prev-fps %d",
> +                    stream_id, size_change, size_avg_old, size_avg_new,
> +                    stream_jpeg_quality_samples[agent->jpeg.quality_id],
> +                    agent->fps);
> +        agent->jpeg.during_sampling = TRUE;
> +        /* compression ratio has improved --> don't allow stream to deteriorate */
> +        agent->jpeg.min_sample_quality_id = agent->jpeg.quality_id;
> +        agent->jpeg.min_sample_quality_fps = agent->fps;
> +    }
> +    agent->jpeg.byte_rate = stream_byte_rate;
> +
> +    if (agent->jpeg.recent_size_summed_count >= STREAM_AVERAGE_SIZE_WINDOW) {
> +        agent->jpeg.size_sum += agent->jpeg.recent_size_sum;
> +        agent->jpeg.size_summed_count += agent->jpeg.recent_size_summed_count;
> +        agent->jpeg.recent_size_sum = 0;
> +        agent->jpeg.recent_size_summed_count = 0;
> +    }
> +    if (agent->jpeg.during_sampling) {
> +        agent->jpeg.quality_sample_size[agent->jpeg.quality_id] = size_avg_new;
> +        red_stream_do_quality_size_sampling(dcc, agent);
> +    } else {
> +        red_stream_update_quality_by_drops(dcc, agent);
> +    }
> +}
> +
>  static inline int red_marshall_stream_data(RedChannelClient *rcc,
>                    SpiceMarshaller *base_marshaller, Drawable *drawable)
>  {
> @@ -8124,21 +8428,26 @@ static inline int red_marshall_stream_data(RedChannelClient *rcc,
>          return TRUE;
>      }
>  
> +    red_stream_update_quality(rcc, agent);
>      outbuf_size = dcc->send_data.stream_outbuf_size;
>      if (!mjpeg_encoder_start_frame(stream->mjpeg_encoder, image->u.bitmap.format,
> -                                   70,
> +                                   stream_jpeg_quality_samples[agent->jpeg.quality_id],
>                                     width, height,
>                                     &dcc->send_data.stream_outbuf,
>                                     &outbuf_size)) {
> +        spice_debug("start frame failed");
>          return FALSE;
>      }
>      if (!encode_frame(worker, &drawable->red_drawable->u.copy.src_area,
>                        &image->u.bitmap, stream)) {
> +        spice_debug("encode frame failed");
>          return FALSE;
>      }
>      n = mjpeg_encoder_end_frame(stream->mjpeg_encoder);
>      dcc->send_data.stream_outbuf_size = outbuf_size;
>  
> +    agent->jpeg.quality_sample_size[agent->jpeg.quality_id] = n;
> +
>      if (!drawable->sized_stream) {
>          SpiceMsgDisplayStreamData stream_data;
>  
> -- 
> 1.7.7.6
> 
> _______________________________________________
> Spice-devel mailing list
> Spice-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/spice-devel
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 198 bytes
Desc: not available
URL: <http://lists.freedesktop.org/archives/spice-devel/attachments/20120410/1305b621/attachment-0001.pgp>


More information about the Spice-devel mailing list