Re: [spice v8 02/24] server: Enable adding alternative MJPEG video encoders

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi,

On Tue, 2016-01-12 at 11:58 +0100, Francois Gouget wrote:
> This replaces the original mjpeg_encoder API with a VideoEncoder base
> class which can be reimplemented by other encoders.
> This also renames the members and enums from mjpeg_* to video_*.
> 
> Signed-off-by: Francois Gouget <fgouget@xxxxxxxxxxxxxxx>
> ---
>  server/Makefile.am     |   2 +-
>  server/dcc-send.c      |  24 ++++----
>  server/dcc.c           |  24 ++++----
>  server/dcc.h           |   2 +-
>  server/mjpeg-encoder.c |  84 +++++++++++++++-----------
>  server/stream.c        |  40 ++++++-------
>  server/stream.h        |   4 +-
>  server/video-encoder.h | 160
> +++++++++++++++++++++++++++++++++++++++++++++++++
>  8 files changed, 258 insertions(+), 82 deletions(-)
>  create mode 100644 server/video-encoder.h
> 
> diff --git a/server/Makefile.am b/server/Makefile.am
> index 32ab8eb..e2c4e55 100644
> --- a/server/Makefile.am
> +++ b/server/Makefile.am
> @@ -83,7 +83,6 @@ libspice_server_la_SOURCES =			
> \
>  	main-channel.c				\
>  	main-channel.h				\
>  	mjpeg-encoder.c				\
> -	mjpeg-encoder.h				\
>  	red-channel.c				\
>  	red-channel.h				\
>  	red-common.h				\
> @@ -121,6 +120,7 @@ libspice_server_la_SOURCES =			
> \
>  	spicevmc.c				\
>  	spice_timer_queue.c			\
>  	spice_timer_queue.h			\
> +	video-encoder.h				\

mjpeg-encoder.h is not used after this patch. Does it make a sense to
rename it to video-encoder.h and do the changes on top of it?

Reviewed-by: Pavel Grunt <pgrunt@xxxxxxxxxx>

Pavel

>  	zlib-encoder.c				\
>  	zlib-encoder.h				\
>  	image-cache.h			\
> diff --git a/server/dcc-send.c b/server/dcc-send.c
> index c3f79ef..fd11b09 100644
> --- a/server/dcc-send.c
> +++ b/server/dcc-send.c
> @@ -1691,7 +1691,7 @@ static int
> red_marshall_stream_data(RedChannelClient *rcc,
>      uint64_t time_now = spice_get_monotonic_time_ns();
>      size_t outbuf_size;
>  
> -    if (!dcc->use_mjpeg_encoder_rate_control) {
> +    if (!dcc->use_video_encoder_rate_control) {
>          if (time_now - agent->last_send_time < (1000 * 1000 * 1000)
> / agent->fps) {
>              agent->frames--;
>  #ifdef STREAM_STATS
> @@ -1706,25 +1706,25 @@ static int
> red_marshall_stream_data(RedChannelClient *rcc,
>                          drawable->red_drawable->mm_time :
>                          reds_get_mm_time();
>      outbuf_size = dcc->send_data.stream_outbuf_size;
> -    ret = mjpeg_encoder_encode_frame(agent->mjpeg_encoder,
> -                                     &image->u.bitmap, width,
> height,
> -                                     &drawable->red_drawable-
> >u.copy.src_area,
> -                                     stream->top_down,
> frame_mm_time,
> -                                    &dcc->send_data.stream_outbuf,
> -                                     &outbuf_size, &n);
> +    ret = agent->video_encoder->encode_frame(agent->video_encoder,
> +                                             &image->u.bitmap,
> width, height,
> +                                             &drawable-
> >red_drawable->u.copy.src_area,
> +                                             stream->top_down,
> frame_mm_time,
> +                                             &dcc-
> >send_data.stream_outbuf,
> +                                             &outbuf_size, &n);
>      switch (ret) {
> -    case MJPEG_ENCODER_FRAME_DROP:
> -        spice_assert(dcc->use_mjpeg_encoder_rate_control);
> +    case VIDEO_ENCODER_FRAME_DROP:
> +        spice_assert(dcc->use_video_encoder_rate_control);
>  #ifdef STREAM_STATS
>          agent->stats.num_drops_fps++;
>  #endif
>          return TRUE;
> -    case MJPEG_ENCODER_FRAME_UNSUPPORTED:
> +    case VIDEO_ENCODER_FRAME_UNSUPPORTED:
>          return FALSE;
> -    case MJPEG_ENCODER_FRAME_ENCODE_DONE:
> +    case VIDEO_ENCODER_FRAME_ENCODE_DONE:
>          break;
>      default:
> -        spice_error("bad return value (%d) from
> mjpeg_encoder_encode_frame", ret);
> +        spice_error("bad return value (%d) from
> VideoEncoder::encode_frame", ret);
>          return FALSE;
>      }
>      dcc->send_data.stream_outbuf_size = outbuf_size;
> diff --git a/server/dcc.c b/server/dcc.c
> index eb5e4d1..25c18d8 100644
> --- a/server/dcc.c
> +++ b/server/dcc.c
> @@ -350,7 +350,7 @@ static void
> dcc_init_stream_agents(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 =
> +    dcc->use_video_encoder_rate_control =
>          red_channel_client_test_remote_cap(RED_CHANNEL_CLIENT(dcc),
> SPICE_DISPLAY_CAP_STREAM_REPORT);
>  }
>  
> @@ -474,9 +474,9 @@ static void
> dcc_destroy_stream_agents(DisplayChannelClient *dcc)
>          StreamAgent *agent = &dcc->stream_agents[i];
>          region_destroy(&agent->vis_region);
>          region_destroy(&agent->clip);
> -        if (agent->mjpeg_encoder) {
> -            mjpeg_encoder_destroy(agent->mjpeg_encoder);
> -            agent->mjpeg_encoder = NULL;
> +        if (agent->video_encoder) {
> +            agent->video_encoder->destroy(agent->video_encoder);
> +            agent->video_encoder = NULL;
>          }
>      }
>  }
> @@ -1319,19 +1319,19 @@ static int
> dcc_handle_stream_report(DisplayChannelClient *dcc,
>      }
>  
>      agent = &dcc->stream_agents[report->stream_id];
> -    if (!agent->mjpeg_encoder) {
> +    if (!agent->video_encoder) {
>          return TRUE;
>      }
>  
>      spice_return_val_if_fail(report->unique_id == agent->report_id,
> TRUE);
>  
> -    mjpeg_encoder_client_stream_report(agent->mjpeg_encoder,
> -                                       report->num_frames,
> -                                       report->num_drops,
> -                                       report->start_frame_mm_time,
> -                                       report->end_frame_mm_time,
> -                                       report->last_frame_delay,
> -                                       report->audio_delay);
> +    agent->video_encoder->client_stream_report(agent->video_encoder,
> +                                               report->num_frames,
> +                                               report->num_drops,
> +                                               report-
> >start_frame_mm_time,
> +                                               report-
> >end_frame_mm_time,
> +                                               report-
> >last_frame_delay,
> +                                               report->audio_delay);
>      return TRUE;
>  }
>  
> diff --git a/server/dcc.h b/server/dcc.h
> index 2a12226..b510254 100644
> --- a/server/dcc.h
> +++ b/server/dcc.h
> @@ -108,7 +108,7 @@ struct DisplayChannelClient {
>      QRegion surface_client_lossy_region[NUM_SURFACES];
>  
>      StreamAgent stream_agents[NUM_STREAMS];
> -    int use_mjpeg_encoder_rate_control;
> +    int use_video_encoder_rate_control;
>      uint32_t streams_max_latency;
>      uint64_t streams_max_bit_rate;
>  };
> diff --git a/server/mjpeg-encoder.c b/server/mjpeg-encoder.c
> index 3bd1a04..eb1a333 100644
> --- a/server/mjpeg-encoder.c
> +++ b/server/mjpeg-encoder.c
> @@ -20,7 +20,7 @@
>  #endif
>  
>  #include "red-common.h"
> -#include "mjpeg-encoder.h"
> +#include "video-encoder.h"
>  #include "utils.h"
>  #include <jerror.h>
>  #include <jpeglib.h>
> @@ -154,7 +154,8 @@ typedef struct MJpegEncoderRateControl {
>      uint64_t warmup_start_time;
>  } MJpegEncoderRateControl;
>  
> -struct MJpegEncoder {
> +typedef struct MJpegEncoder {
> +    VideoEncoder base;
>      uint8_t *row;
>      uint32_t row_size;
>      int first_frame;
> @@ -166,14 +167,14 @@ struct MJpegEncoder {
>      void (*pixel_converter)(void *src, uint8_t *dest);
>  
>      MJpegEncoderRateControl rate_control;
> -    MJpegEncoderRateControlCbs cbs;
> +    VideoEncoderRateControlCbs cbs;
>      void *cbs_opaque;
>  
>      /* stats */
>      uint64_t starting_bit_rate;
>      uint64_t avg_quality;
>      uint32_t num_frames;
> -};
> +} MJpegEncoder;
>  
>  static void mjpeg_encoder_process_server_drops(MJpegEncoder
> *encoder);
>  static uint32_t get_min_required_playback_delay(uint64_t
> frame_enc_size,
> @@ -185,8 +186,9 @@ static inline int
> rate_control_is_active(MJpegEncoder* encoder)
>      return encoder->cbs.get_roundtrip_ms != NULL;
>  }
>  
> -void mjpeg_encoder_destroy(MJpegEncoder *encoder)
> +static void mjpeg_encoder_destroy(VideoEncoder *video_encoder)
>  {
> +    MJpegEncoder *encoder = (MJpegEncoder*)video_encoder;
>      free(encoder->cinfo.dest);
>      jpeg_destroy_compress(&encoder->cinfo);
>      free(encoder->row);
> @@ -725,7 +727,7 @@ static int mjpeg_encoder_start_frame(MJpegEncoder
> *encoder,
>          interval = (now - rate_control-
> >bit_rate_info.last_frame_time);
>  
>          if (interval < NSEC_PER_SEC / rate_control->adjusted_fps) {
> -            return MJPEG_ENCODER_FRAME_DROP;
> +            return VIDEO_ENCODER_FRAME_DROP;
>          }
>  
>          mjpeg_encoder_adjust_params_to_bit_rate(encoder);
> @@ -773,14 +775,14 @@ static int
> mjpeg_encoder_start_frame(MJpegEncoder *encoder,
>          break;
>      default:
>          spice_debug("unsupported format %d", format);
> -        return MJPEG_ENCODER_FRAME_UNSUPPORTED;
> +        return VIDEO_ENCODER_FRAME_UNSUPPORTED;
>      }
>  
>      if (encoder->pixel_converter != NULL) {
>          unsigned int stride = width * 3;
>          /* check for integer overflow */
>          if (stride < width) {
> -            return MJPEG_ENCODER_FRAME_UNSUPPORTED;
> +            return VIDEO_ENCODER_FRAME_UNSUPPORTED;
>          }
>          if (encoder->row_size < stride) {
>              encoder->row = spice_realloc(encoder->row, stride);
> @@ -800,7 +802,7 @@ static int mjpeg_encoder_start_frame(MJpegEncoder
> *encoder,
>  
>      encoder->num_frames++;
>      encoder->avg_quality += quality;
> -    return MJPEG_ENCODER_FRAME_ENCODE_DONE;
> +    return VIDEO_ENCODER_FRAME_ENCODE_DONE;
>  }
>  
>  static int mjpeg_encoder_encode_scanline(MJpegEncoder *encoder,
> @@ -924,27 +926,30 @@ static int encode_frame(MJpegEncoder *encoder,
> const SpiceRect *src,
>      return TRUE;
>  }
>  
> -int mjpeg_encoder_encode_frame(MJpegEncoder *encoder,
> -                               const SpiceBitmap *bitmap, int width,
> int height,
> -                               const SpiceRect *src,
> -                               int top_down, uint32_t frame_mm_time,
> -                               uint8_t **outbuf, size_t
> *outbuf_size,
> -                               int *data_size)
> +static int mjpeg_encoder_encode_frame(VideoEncoder *video_encoder,
> +                                      const SpiceBitmap *bitmap,
> +                                      int width, int height,
> +                                      const SpiceRect *src,
> +                                      int top_down, uint32_t
> frame_mm_time,
> +                                      uint8_t **outbuf, size_t
> *outbuf_size,
> +                                      int *data_size)
>  {
> +    MJpegEncoder *encoder = (MJpegEncoder*)video_encoder;
> +
>      int ret = mjpeg_encoder_start_frame(encoder, bitmap->format,
> -                                    width, height, outbuf,
> outbuf_size,
> -                                    frame_mm_time);
> -    if (ret != MJPEG_ENCODER_FRAME_ENCODE_DONE) {
> +                                        width, height, outbuf,
> outbuf_size,
> +                                        frame_mm_time);
> +    if (ret != VIDEO_ENCODER_FRAME_ENCODE_DONE) {
>          return ret;
>      }
>  
>      if (!encode_frame(encoder, src, bitmap, top_down)) {
> -        return MJPEG_ENCODER_FRAME_UNSUPPORTED;
> +        return VIDEO_ENCODER_FRAME_UNSUPPORTED;
>      }
>  
>      *data_size = mjpeg_encoder_end_frame(encoder);
>  
> -    return MJPEG_ENCODER_FRAME_ENCODE_DONE;
> +    return VIDEO_ENCODER_FRAME_ENCODE_DONE;
>  }
>  
>  
> @@ -1175,14 +1180,15 @@ static uint32_t
> get_min_required_playback_delay(uint64_t frame_enc_size,
>  #define MJPEG_VIDEO_VS_AUDIO_LATENCY_FACTOR 1.25
>  #define MJPEG_VIDEO_DELAY_TH -15
>  
> -void mjpeg_encoder_client_stream_report(MJpegEncoder *encoder,
> -                                        uint32_t num_frames,
> -                                        uint32_t num_drops,
> -                                        uint32_t
> start_frame_mm_time,
> -                                        uint32_t end_frame_mm_time,
> -                                        int32_t end_frame_delay,
> -                                        uint32_t audio_delay)
> +static void mjpeg_encoder_client_stream_report(VideoEncoder
> *video_encoder,
> +                                               uint32_t num_frames,
> +                                               uint32_t num_drops,
> +                                               uint32_t
> start_frame_mm_time,
> +                                               uint32_t
> end_frame_mm_time,
> +                                               int32_t
> end_frame_delay,
> +                                               uint32_t audio_delay)
>  {
> +    MJpegEncoder *encoder = (MJpegEncoder*)video_encoder;
>      MJpegEncoderRateControl *rate_control = &encoder->rate_control;
>      MJpegEncoderClientState *client_state = &rate_control-
> >client_state;
>      uint64_t avg_enc_size = 0;
> @@ -1283,8 +1289,9 @@ void
> mjpeg_encoder_client_stream_report(MJpegEncoder *encoder,
>      }
>  }
>  
> -void mjpeg_encoder_notify_server_frame_drop(MJpegEncoder *encoder)
> +static void mjpeg_encoder_notify_server_frame_drop(VideoEncoder
> *video_encoder)
>  {
> +    MJpegEncoder *encoder = (MJpegEncoder*)video_encoder;
>      encoder->rate_control.server_state.num_frames_dropped++;
>      mjpeg_encoder_process_server_drops(encoder);
>  }
> @@ -1321,25 +1328,34 @@ static void
> mjpeg_encoder_process_server_drops(MJpegEncoder *encoder)
>      server_state->num_frames_dropped = 0;
>  }
>  
> -uint64_t mjpeg_encoder_get_bit_rate(MJpegEncoder *encoder)
> +static uint64_t mjpeg_encoder_get_bit_rate(VideoEncoder
> *video_encoder)
>  {
> +    MJpegEncoder *encoder = (MJpegEncoder*)video_encoder;
>      return encoder->rate_control.byte_rate * 8;
>  }
>  
> -void mjpeg_encoder_get_stats(MJpegEncoder *encoder,
> MJpegEncoderStats *stats)
> +static void mjpeg_encoder_get_stats(VideoEncoder *video_encoder,
> +                                    VideoEncoderStats *stats)
>  {
> +    MJpegEncoder *encoder = (MJpegEncoder*)video_encoder;
>      spice_assert(encoder != NULL && stats != NULL);
>      stats->starting_bit_rate = encoder->starting_bit_rate;
> -    stats->cur_bit_rate = mjpeg_encoder_get_bit_rate(encoder);
> +    stats->cur_bit_rate = mjpeg_encoder_get_bit_rate(video_encoder);
>      stats->avg_quality = (double)encoder->avg_quality / encoder-
> >num_frames;
>  }
>  
> -MJpegEncoder *mjpeg_encoder_new(uint64_t starting_bit_rate,
> -                                MJpegEncoderRateControlCbs *cbs,
> +VideoEncoder *mjpeg_encoder_new(uint64_t starting_bit_rate,
> +                                VideoEncoderRateControlCbs *cbs,
>                                  void *cbs_opaque)
>  {
>      MJpegEncoder *encoder = spice_new0(MJpegEncoder, 1);
>  
> +    encoder->base.destroy = &mjpeg_encoder_destroy;
> +    encoder->base.encode_frame = &mjpeg_encoder_encode_frame;
> +    encoder->base.client_stream_report =
> &mjpeg_encoder_client_stream_report;
> +    encoder->base.notify_server_frame_drop =
> &mjpeg_encoder_notify_server_frame_drop;
> +    encoder->base.get_bit_rate = &mjpeg_encoder_get_bit_rate;
> +    encoder->base.get_stats = &mjpeg_encoder_get_stats;
>      encoder->first_frame = TRUE;
>      encoder->rate_control.byte_rate = starting_bit_rate / 8;
>      encoder->starting_bit_rate = starting_bit_rate;
> @@ -1360,5 +1376,5 @@ MJpegEncoder *mjpeg_encoder_new(uint64_t
> starting_bit_rate,
>      encoder->cinfo.err = jpeg_std_error(&encoder->jerr);
>      jpeg_create_compress(&encoder->cinfo);
>  
> -    return encoder;
> +    return (VideoEncoder*)encoder;
>  }
> diff --git a/server/stream.c b/server/stream.c
> index 3120860..2bfa3a5 100644
> --- a/server/stream.c
> +++ b/server/stream.c
> @@ -32,10 +32,10 @@ void stream_agent_stats_print(StreamAgent *agent)
>  #ifdef STREAM_STATS
>      StreamStats *stats = &agent->stats;
>      double passed_mm_time = (stats->end - stats->start) / 1000.0;
> -    MJpegEncoderStats encoder_stats = {0};
> +    VideoEncoderStats encoder_stats = {0};
>  
> -    if (agent->mjpeg_encoder) {
> -        mjpeg_encoder_get_stats(agent->mjpeg_encoder,
> &encoder_stats);
> +    if (agent->video_encoder) {
> +        agent->video_encoder->get_stats(agent->video_encoder,
> &encoder_stats);
>      }
>  
>      spice_debug("stream=%p dim=(%dx%d) #in-frames=%"PRIu64" #in-avg-
> fps=%.2f #out-frames=%"PRIu64" "
> @@ -79,8 +79,8 @@ void stream_stop(DisplayChannel *display, Stream
> *stream)
>          region_clear(&stream_agent->vis_region);
>          region_clear(&stream_agent->clip);
>          spice_assert(!pipe_item_is_linked(&stream_agent-
> >destroy_item));
> -        if (stream_agent->mjpeg_encoder && dcc-
> >use_mjpeg_encoder_rate_control) {
> -            uint64_t stream_bit_rate =
> mjpeg_encoder_get_bit_rate(stream_agent->mjpeg_encoder);
> +        if (stream_agent->video_encoder && dcc-
> >use_video_encoder_rate_control) {
> +            uint64_t stream_bit_rate = stream_agent->video_encoder-
> >get_bit_rate(stream_agent->video_encoder);
>  
>              if (stream_bit_rate > dcc->streams_max_bit_rate) {
>                  spice_debug("old max-bit-rate=%.2f new=%.2f",
> @@ -339,7 +339,7 @@ static void before_reattach_stream(DisplayChannel
> *display,
>          dcc = dpi->dcc;
>          agent = &dcc->stream_agents[index];
>  
> -        if (!dcc->use_mjpeg_encoder_rate_control &&
> +        if (!dcc->use_video_encoder_rate_control &&
>              !dcc->common.is_low_bandwidth) {
>              continue;
>          }
> @@ -348,8 +348,8 @@ static void before_reattach_stream(DisplayChannel
> *display,
>  #ifdef STREAM_STATS
>              agent->stats.num_drops_pipe++;
>  #endif
> -            if (dcc->use_mjpeg_encoder_rate_control) {
> -                mjpeg_encoder_notify_server_frame_drop(agent-
> >mjpeg_encoder);
> +            if (dcc->use_video_encoder_rate_control) {
> +                agent->video_encoder-
> >notify_server_frame_drop(agent->video_encoder);
>              } else {
>                  ++agent->drops;
>              }
> @@ -362,7 +362,7 @@ static void before_reattach_stream(DisplayChannel
> *display,
>  
>          agent = &dcc->stream_agents[index];
>  
> -        if (dcc->use_mjpeg_encoder_rate_control) {
> +        if (dcc->use_video_encoder_rate_control) {
>              continue;
>          }
>          if (agent->frames / agent->fps < FPS_TEST_INTERVAL) {
> @@ -595,7 +595,7 @@ static void
> dcc_update_streams_max_latency(DisplayChannelClient *dcc, StreamAgen
>      }
>      for (i = 0; i < NUM_STREAMS; i++) {
>          StreamAgent *other_agent = &dcc->stream_agents[i];
> -        if (other_agent == remove_agent || !other_agent-
> >mjpeg_encoder) {
> +        if (other_agent == remove_agent || !other_agent-
> >video_encoder) {
>              continue;
>          }
>          if (other_agent->client_required_latency > new_max_latency)
> {
> @@ -712,18 +712,18 @@ void dcc_create_stream(DisplayChannelClient
> *dcc, Stream *stream)
>      agent->fps = MAX_FPS;
>      agent->dcc = dcc;
>  
> -    if (dcc->use_mjpeg_encoder_rate_control) {
> -        MJpegEncoderRateControlCbs mjpeg_cbs;
> +    if (dcc->use_video_encoder_rate_control) {
> +        VideoEncoderRateControlCbs video_cbs;
>          uint64_t initial_bit_rate;
>  
> -        mjpeg_cbs.get_roundtrip_ms = get_roundtrip_ms;
> -        mjpeg_cbs.get_source_fps = get_source_fps;
> -        mjpeg_cbs.update_client_playback_delay =
> update_client_playback_delay;
> +        video_cbs.get_roundtrip_ms = get_roundtrip_ms;
> +        video_cbs.get_source_fps = get_source_fps;
> +        video_cbs.update_client_playback_delay =
> update_client_playback_delay;
>  
>          initial_bit_rate = get_initial_bit_rate(dcc, stream);
> -        agent->mjpeg_encoder = mjpeg_encoder_new(initial_bit_rate,
> &mjpeg_cbs, agent);
> +        agent->video_encoder = mjpeg_encoder_new(initial_bit_rate,
> &video_cbs, agent);
>      } else {
> -        agent->mjpeg_encoder = mjpeg_encoder_new(0, NULL, NULL);
> +        agent->video_encoder = mjpeg_encoder_new(0, NULL, NULL);
>      }
>      red_channel_client_pipe_add(RED_CHANNEL_CLIENT(dcc), &agent-
> >create_item);
>  
> @@ -749,9 +749,9 @@ void stream_agent_stop(StreamAgent *agent)
>      DisplayChannelClient *dcc = agent->dcc;
>  
>      dcc_update_streams_max_latency(dcc, agent);
> -    if (agent->mjpeg_encoder) {
> -        mjpeg_encoder_destroy(agent->mjpeg_encoder);
> -        agent->mjpeg_encoder = NULL;
> +    if (agent->video_encoder) {
> +        agent->video_encoder->destroy(agent->video_encoder);
> +        agent->video_encoder = NULL;
>      }
>  }
>  
> diff --git a/server/stream.h b/server/stream.h
> index a3e84ed..59df9bd 100644
> --- a/server/stream.h
> +++ b/server/stream.h
> @@ -20,7 +20,7 @@
>  
>  #include <glib.h>
>  #include "utils.h"
> -#include "mjpeg-encoder.h"
> +#include "video-encoder.h"
>  #include "common/region.h"
>  #include "red-channel.h"
>  #include "image-cache.h"
> @@ -85,7 +85,7 @@ typedef struct StreamAgent {
>      PipeItem destroy_item;
>      Stream *stream;
>      uint64_t last_send_time;
> -    MJpegEncoder *mjpeg_encoder;
> +    VideoEncoder *video_encoder;
>      DisplayChannelClient *dcc;
>  
>      int frames;
> diff --git a/server/video-encoder.h b/server/video-encoder.h
> new file mode 100644
> index 0000000..3b1d541
> --- /dev/null
> +++ b/server/video-encoder.h
> @@ -0,0 +1,160 @@
> +/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
> +/*
> +   Copyright (C) 2009 Red Hat, Inc.
> +   Copyright (C) 2015 Jeremy White
> +   Copyright (C) 2015 Francois Gouget
> +
> +   This library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later
> version.
> +
> +   This library is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with this library; if not, see <http://www.gnu.org/
> licenses/>.
> +*/
> +
> +#ifndef _H_VIDEO_ENCODER
> +#define _H_VIDEO_ENCODER
> +
> +enum {
> +    VIDEO_ENCODER_FRAME_UNSUPPORTED = -1,
> +    VIDEO_ENCODER_FRAME_DROP,
> +    VIDEO_ENCODER_FRAME_ENCODE_DONE,
> +};
> +
> +typedef struct VideoEncoderStats {
> +    uint64_t starting_bit_rate;
> +    uint64_t cur_bit_rate;
> +    double avg_quality;
> +} VideoEncoderStats;
> +
> +typedef struct VideoEncoder VideoEncoder;
> +
> +struct VideoEncoder {
> +    /* Releases the video encoder's resources */
> +    void (*destroy)(VideoEncoder *encoder);
> +
> +    /* Compresses the specified src image area into the outbuf
> buffer.
> +     *
> +     * @encoder:   The video encoder.
> +     * @bitmap:    The Spice screen.
> +     * @width:     The width of the video area. This always matches
> src.
> +     * @height:    The height of the video area. This always matches
> src.
> +     * @src:       A rectangle specifying the area occupied by the
> video.
> +     * @top_down:  If true the first video line is specified by
> src.top.
> +     * @outbuf:    The buffer for the compressed frame. This must
> either be
> +     *             NULL or point to a buffer allocated by malloc
> since it may be
> +     *             reallocated, if its size is too small.
> +     * @outbuf_size: The size of the outbuf buffer.
> +     * @data_size: The size of the compressed frame.
> +     * @return:
> +     *     VIDEO_ENCODER_FRAME_ENCODE_DONE if successful.
> +     *     VIDEO_ENCODER_FRAME_UNSUPPORTED if the frame cannot be
> encoded.
> +     *     VIDEO_ENCODER_FRAME_DROP if the frame was dropped. This
> value can
> +     *                              only happen if rate control is
> active.
> +     */
> +    int (*encode_frame)(VideoEncoder *encoder, const SpiceBitmap
> *bitmap,
> +                        int width, int height, const SpiceRect *src,
> +                        int top_down, uint32_t frame_mm_time,
> uint8_t **outbuf,
> +                        size_t *outbuf_size, int *data_size);
> +
> +    /*
> +     * Bit rate control methods.
> +     */
> +
> +    /* When rate control is active statistics are periodically
> obtained from
> +     * the client and sent to the video encoder through this method.
> +     *
> +     * @encoder:    The video encoder.
> +     * @num_frames: The number of frames that reached the client
> during the
> +     *              time period the report is referring to.
> +     * @num_drops:  The part of the above frames that was dropped by
> the client
> +     *              due to late arrival time.
> +     * @start_frame_mm_time: The mm_time of the first frame included
> in the
> +     *              report.
> +     * @end_frame_mm_time: The mm_time of the last frame included in
> the report.
> +     * @end_frame_delay: This indicates how long in advance the
> client received
> +     *              the last frame before having to display it.
> +     * @audio delay: The latency of the audio playback or MAX_UINT
> if it is not
> +     *              tracked.
> +     */
> +    void (*client_stream_report)(VideoEncoder *encoder,
> +                                 uint32_t num_frames, uint32_t
> num_drops,
> +                                 uint32_t start_frame_mm_time,
> +                                 uint32_t end_frame_mm_time,
> +                                 int32_t end_frame_delay, uint32_t
> audio_delay);
> +
> +    /* This notifies the video encoder each time a frame is dropped
> due to pipe
> +     * congestion.
> +     *
> +     * Note that frames are being dropped before they are encoded
> and that there
> +     * may be any number of encoded frames in the network queue.
> +     * The client reports provide richer and typically more reactive
> information
> +     * for fine tuning the playback parameters but this function
> provides a
> +     * fallback when client reports are getting delayed or are not
> supported
> +     * by the client.
> +     *
> +     * @encoder:    The video encoder.
> +     */
> +    void (*notify_server_frame_drop)(VideoEncoder *encoder);
> +
> +    /* This queries the video encoder's current bit rate.
> +     *
> +     * @encoder:    The video encoder.
> +     * @return:     The current bit rate in bits per second.
> +     */
> +    uint64_t (*get_bit_rate)(VideoEncoder *encoder);
> +
> +    /* Collects video statistics.
> +     *
> +     * @encoder:    The video encoder.
> +     * @stats:      A VideoEncoderStats structure to fill with the
> collected
> +     *              statistics.
> +     */
> +    void (*get_stats)(VideoEncoder *encoder, VideoEncoderStats
> *stats);
> +};
> +
> +
> +/* When rate control is active the video encoder can use these
> callbacks to
> + * figure out how to adjust the stream bit rate and adjust some
> stream
> + * parameters.
> + */
> +typedef struct VideoEncoderRateControlCbs {
> +    /* Returns the stream's estimated roundtrip time in
> milliseconds. */
> +    uint32_t (*get_roundtrip_ms)(void *opaque);
> +
> +    /* Returns the estimated input frame rate.
> +     *
> +     * This is the number of frames per second arriving from the
> guest to
> +     * spice-server, before any drops.
> +     */
> +    uint32_t (*get_source_fps)(void *opaque);
> +
> +    /* Informs the client of the minimum playback delay.
> +     *
> +     * @delay_ms:   The minimum number of milliseconds required for
> the frames
> +     *              to reach the client.
> +     */
> +    void (*update_client_playback_delay)(void *opaque, uint32_t
> delay_ms);
> +} VideoEncoderRateControlCbs;
> +
> +
> +/* Instantiates the video encoder.
> + *
> + * @starting_bit_rate: An initial estimate of the available stream
> bit rate or
> + *                     zero if the client does not support rate
> control.
> + * @cbs:               A set of callback methods to be used for rate
> control.
> + * @cbs_opaque:        A pointer to be passed to the rate control
> callbacks.
> + * @return:            A pointer to a structure implementing the
> VideoEncoder
> + *                     methods.
> + */
> +VideoEncoder* mjpeg_encoder_new(uint64_t starting_bit_rate,
> +                                VideoEncoderRateControlCbs *cbs,
> +                                void *cbs_opaque);
> +
> +#endif
_______________________________________________
Spice-devel mailing list
Spice-devel@xxxxxxxxxxxxxxxxxxxxx
http://lists.freedesktop.org/mailman/listinfo/spice-devel




[Index of Archives]     [Linux ARM Kernel]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [IETF Annouce]     [Security]     [Bugtraq]     [Linux]     [Linux OMAP]     [Linux MIPS]     [ECOS]     [Asterisk Internet PBX]     [Linux API]     [Monitors]