[Spice-devel] [PATCH spice-server 07/28] mjpeg_encoder: update the client with estimations for the required playback latency

Alon Levy alevy at redhat.com
Sun Apr 14 06:20:49 PDT 2013


On Tue, Feb 26, 2013 at 01:03:53PM -0500, Yonit Halperin wrote:
> The required client playback latency is assessed based on the current
> estimation of the bit rate, the network latency, and the encoding size
> of the frames. When the playback delay that is reported by the client
> seems too small, or when the stream parameters change, we send the
> client an updated playback latency estimation.

ACK.

> ---
>  server/mjpeg_encoder.c | 51 ++++++++++++++++++++++++++++++++++++--------------
>  server/mjpeg_encoder.h |  1 +
>  2 files changed, 38 insertions(+), 14 deletions(-)
> 
> diff --git a/server/mjpeg_encoder.c b/server/mjpeg_encoder.c
> index d50a5d1..70b6338 100644
> --- a/server/mjpeg_encoder.c
> +++ b/server/mjpeg_encoder.c
> @@ -51,6 +51,12 @@ static const int mjpeg_quality_samples[MJPEG_QUALITY_SAMPLE_NUM] = {20, 30, 40,
>  #define MJPEG_CLIENT_POSITIVE_REPORT_TIMEOUT 2000
>  #define MJPEG_CLIENT_POSITIVE_REPORT_STRICT_TIMEOUT 3000
>  
> +/*
> + * avoid interrupting the playback when there are temporary
> + * incidents of instability (with respect to server and client drops)
> + */
> +#define MJPEG_MAX_CLIENT_PLAYBACK_DELAY 5000 // 5 sec
> +
>  enum {
>      MJPEG_QUALITY_EVAL_TYPE_SET,
>      MJPEG_QUALITY_EVAL_TYPE_UPGRADE,
> @@ -151,6 +157,9 @@ static inline void mjpeg_encoder_reset_quality(MJpegEncoder *encoder,
>                                                 uint64_t frame_enc_size);
>  static uint32_t get_max_fps(uint64_t frame_size, uint64_t bytes_per_sec, uint32_t latency_ms);
>  static void mjpeg_encoder_process_server_drops(MJpegEncoder *encoder);
> +static uint32_t get_min_required_playback_delay(uint64_t frame_enc_size,
> +                                                uint64_t byte_rate,
> +                                                uint32_t latency);
>  
>  MJpegEncoder *mjpeg_encoder_new(int bit_rate_control, uint64_t starting_bit_rate,
>                                  MJpegEncoderRateControlCbs *cbs, void *opaque)
> @@ -503,6 +512,13 @@ complete_sample:
>  
>      spice_debug("MJpeg quality sample end %p: quality %d fps %d",
>                  encoder, mjpeg_quality_samples[rate_control->quality_id], rate_control->fps);
> +    if (encoder->cbs.update_client_playback_delay) {
> +        uint32_t min_delay = get_min_required_playback_delay(final_quality_enc_size,
> +                                                             rate_control->byte_rate,
> +                                                             latency);
> +
> +        encoder->cbs.update_client_playback_delay(encoder->cbs_opaque, min_delay);
> +    }
>  }
>  
>  static void mjpeg_encoder_quality_eval_set_upgrade(MJpegEncoder *encoder,
> @@ -965,13 +981,15 @@ static uint32_t get_min_required_playback_delay(uint64_t frame_enc_size,
>                                                  uint32_t latency)
>  {
>      uint32_t one_frame_time;
> +    uint32_t min_delay;
>  
>      if (!frame_enc_size || !byte_rate) {
>          return latency;
>      }
>      one_frame_time = (frame_enc_size*1000)/byte_rate;
>  
> -    return one_frame_time*2 + latency;
> +    min_delay = MIN(one_frame_time*2 + latency, MJPEG_MAX_CLIENT_PLAYBACK_DELAY);
> +    return min_delay;
>  }
>  
>  #define MJPEG_PLAYBACK_LATENCY_DECREASE_FACTOR 0.5
> @@ -990,6 +1008,7 @@ void mjpeg_encoder_client_stream_report(MJpegEncoder *encoder,
>      MJpegEncoderClientState *client_state = &rate_control->client_state;
>      uint64_t avg_enc_size = 0;
>      uint32_t min_playback_delay;
> +    int is_video_delay_small = FALSE;
>  
>      spice_debug("client report: #frames %u, #drops %d, duration %u video-delay %d audio-delay %u",
>                  num_frames, num_drops,
> @@ -1017,6 +1036,23 @@ void mjpeg_encoder_client_stream_report(MJpegEncoder *encoder,
>                                                           mjpeg_encoder_get_latency(encoder));
>      spice_debug("min-delay %u client-delay %d", min_playback_delay, end_frame_delay);
>  
> +    if (min_playback_delay > end_frame_delay) {
> +        uint32_t src_fps = encoder->cbs.get_source_fps(encoder->cbs_opaque);
> +        /*
> +        * if the stream is at its highest rate, we can't estimate the "real"
> +        * network bit rate and the min_playback_delay
> +        */
> +        if (rate_control->quality_id != MJPEG_QUALITY_SAMPLE_NUM - 1 ||
> +            rate_control->fps < MIN(src_fps, MJPEG_MAX_FPS) || end_frame_delay < 0) {
> +            is_video_delay_small = TRUE;
> +            if (encoder->cbs.update_client_playback_delay) {
> +                encoder->cbs.update_client_playback_delay(encoder->cbs_opaque,
> +                                                          min_playback_delay);
> +            }
> +        }
> +    }
> +
> +
>      /*
>       * If the audio latency has decreased (since the start of the current
>       * sequence of positive reports), and the video latency is bigger, slow down
> @@ -1036,25 +1072,12 @@ void mjpeg_encoder_client_stream_report(MJpegEncoder *encoder,
>          mjpeg_encoder_handle_negative_client_stream_report(encoder,
>                                                             end_frame_mm_time);
>      } else {
> -        int is_video_delay_small = FALSE;
>          double major_delay_decrease_thresh;
>          double medium_delay_decrease_thresh;
>  
>          client_state->max_video_latency = MAX(end_frame_delay, client_state->max_video_latency);
>          client_state->max_audio_latency = MAX(audio_delay, client_state->max_audio_latency);
>  
> -        if (min_playback_delay > end_frame_delay) {
> -            uint32_t src_fps = encoder->cbs.get_source_fps(encoder->cbs_opaque);
> -            /*
> -             * if the stream is at its highest rate, we can't estimate the "real"
> -             * network bit rate and the min_playback_delay
> -             */
> -            if (rate_control->quality_id != MJPEG_QUALITY_SAMPLE_NUM - 1 ||
> -                rate_control->fps < MIN(src_fps, MJPEG_MAX_FPS)) {
> -                is_video_delay_small = TRUE;
> -            }
> -        }
> -
>          medium_delay_decrease_thresh = client_state->max_video_latency;
>          medium_delay_decrease_thresh *= MJPEG_PLAYBACK_LATENCY_DECREASE_FACTOR;
>  
> diff --git a/server/mjpeg_encoder.h b/server/mjpeg_encoder.h
> index bc7f01c..f9ae43c 100644
> --- a/server/mjpeg_encoder.h
> +++ b/server/mjpeg_encoder.h
> @@ -34,6 +34,7 @@ typedef struct MJpegEncoder MJpegEncoder;
>  typedef struct MJpegEncoderRateControlCbs {
>      uint32_t (*get_roundtrip_ms)(void *opaque);
>      uint32_t (*get_source_fps)(void *opaque);
> +    void (*update_client_playback_delay)(void *opaque, uint32_t delay_ms);
>  } MJpegEncoderRateControlCbs;
>  
>  MJpegEncoder *mjpeg_encoder_new(int bit_rate_control, uint64_t starting_bit_rate,
> -- 
> 1.8.1
> 
> _______________________________________________
> Spice-devel mailing list
> Spice-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/spice-devel


More information about the Spice-devel mailing list