[Spice-commits] 3 commits - server/mjpeg_encoder.c server/mjpeg_encoder.h server/red_worker.c

Christophe Fergau teuf at kemper.freedesktop.org
Fri Oct 30 08:21:29 PDT 2015


 server/mjpeg_encoder.c |  193 ++++++++++++++++++++++++++++++++++++-------------
 server/mjpeg_encoder.h |   28 +------
 server/red_worker.c    |   85 ++-------------------
 3 files changed, 160 insertions(+), 146 deletions(-)

New commits:
commit f2c8609985beffd4dcbfcf0aa61cd2e468113fe1
Author: Francois Gouget <fgouget at codeweavers.com>
Date:   Wed Oct 14 17:31:14 2015 +0200

    server: Hide the MJPEG encoder internals from red_worker.c
    
    Signed-off-by: Francois Gouget <fgouget at codeweavers.com>

diff --git a/server/mjpeg_encoder.c b/server/mjpeg_encoder.c
index 3cb2144..c8253a7 100644
--- a/server/mjpeg_encoder.c
+++ b/server/mjpeg_encoder.c
@@ -693,11 +693,22 @@ static void mjpeg_encoder_adjust_fps(MJpegEncoder *encoder, uint64_t now)
     }
 }
 
-int mjpeg_encoder_start_frame(MJpegEncoder *encoder,
-                              SpiceBitmapFmt format,
-                              int width, int height,
-                              uint8_t **dest, size_t *dest_len,
-                              uint32_t frame_mm_time)
+/*
+ * dest must be either NULL or allocated by malloc, since it might be freed
+ * during the encoding, if its size is too small.
+ *
+ * return:
+ *  MJPEG_ENCODER_FRAME_UNSUPPORTED : frame cannot be encoded
+ *  MJPEG_ENCODER_FRAME_DROP        : frame should be dropped. This value can only be returned
+ *                                    if mjpeg rate control is active.
+ *  MJPEG_ENCODER_FRAME_ENCODE_DONE : frame encoding started. Continue with
+ *                                    mjpeg_encoder_encode_scanline.
+ */
+static int mjpeg_encoder_start_frame(MJpegEncoder *encoder,
+                                     SpiceBitmapFmt format,
+                                     int width, int height,
+                                     uint8_t **dest, size_t *dest_len,
+                                     uint32_t frame_mm_time)
 {
     uint32_t quality;
 
@@ -792,7 +803,7 @@ int mjpeg_encoder_start_frame(MJpegEncoder *encoder,
 
     encoder->num_frames++;
     encoder->avg_quality += quality;
-    return MJPEG_ENCODER_FRAME_ENCODE_START;
+    return MJPEG_ENCODER_FRAME_ENCODE_DONE;
 }
 
 static int mjpeg_encoder_encode_scanline(MJpegEncoder *encoder,
@@ -824,7 +835,7 @@ static int mjpeg_encoder_encode_scanline(MJpegEncoder *encoder,
     return scanlines_written;
 }
 
-size_t mjpeg_encoder_end_frame(MJpegEncoder *encoder)
+static size_t mjpeg_encoder_end_frame(MJpegEncoder *encoder)
 {
     mem_destination_mgr *dest = (mem_destination_mgr *) encoder->cinfo.dest;
     MJpegEncoderRateControl *rate_control = &encoder->rate_control;
@@ -879,8 +890,8 @@ static inline uint8_t *get_image_line(SpiceChunks *chunks, size_t *offset,
     return ret;
 }
 
-int mjpeg_encoder_encode_frame(MJpegEncoder *encoder, const SpiceRect *src,
-                               const SpiceBitmap *image, int top_down)
+static int encode_frame(MJpegEncoder *encoder, const SpiceRect *src,
+                        const SpiceBitmap *image, int top_down)
 {
     SpiceChunks *chunks;
     uint32_t image_stride;
@@ -916,6 +927,30 @@ int mjpeg_encoder_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)
+{
+    int ret = mjpeg_encoder_start_frame(encoder, bitmap->format,
+                                    width, height, outbuf, outbuf_size,
+                                    frame_mm_time);
+    if (ret != MJPEG_ENCODER_FRAME_ENCODE_DONE) {
+        return ret;
+    }
+
+    if (!encode_frame(encoder, src, bitmap, top_down)) {
+        return MJPEG_ENCODER_FRAME_UNSUPPORTED;
+    }
+
+    *data_size = mjpeg_encoder_end_frame(encoder);
+
+    return MJPEG_ENCODER_FRAME_ENCODE_DONE;
+}
+
+
 static void mjpeg_encoder_quality_eval_stop(MJpegEncoder *encoder)
 {
     MJpegEncoderRateControl *rate_control = &encoder->rate_control;
diff --git a/server/mjpeg_encoder.h b/server/mjpeg_encoder.h
index 8e2af10..d070e70 100644
--- a/server/mjpeg_encoder.h
+++ b/server/mjpeg_encoder.h
@@ -24,7 +24,7 @@
 enum {
     MJPEG_ENCODER_FRAME_UNSUPPORTED = -1,
     MJPEG_ENCODER_FRAME_DROP,
-    MJPEG_ENCODER_FRAME_ENCODE_START,
+    MJPEG_ENCODER_FRAME_ENCODE_DONE,
 };
 
 typedef struct MJpegEncoder MJpegEncoder;
@@ -53,24 +53,12 @@ MJpegEncoder *mjpeg_encoder_new(uint64_t starting_bit_rate,
                                 MJpegEncoderRateControlCbs *cbs, void *opaque);
 void mjpeg_encoder_destroy(MJpegEncoder *encoder);
 
-/*
- * dest must be either NULL or allocated by malloc, since it might be freed
- * during the encoding, if its size is too small.
- *
- * return:
- *  MJPEG_ENCODER_FRAME_UNSUPPORTED : frame cannot be encoded
- *  MJPEG_ENCODER_FRAME_DROP        : frame should be dropped. This value can only be returned
- *                                    if mjpeg rate control is active.
- *  MJPEG_ENCODER_FRAME_ENCODE_START: frame encoding started. Continue with
- *                                    mjpeg_encoder_encode_scanline.
- */
-int mjpeg_encoder_start_frame(MJpegEncoder *encoder, SpiceBitmapFmt format,
-                              int width, int height,
-                              uint8_t **dest, size_t *dest_len,
-                              uint32_t frame_mm_time);
-int mjpeg_encoder_encode_frame(MJpegEncoder *encoder, const SpiceRect *src,
-                               const SpiceBitmap *image, int top_down);
-size_t mjpeg_encoder_end_frame(MJpegEncoder *encoder);
+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);
 
 /*
  * bit rate control
diff --git a/server/red_worker.c b/server/red_worker.c
index 8803557..2edfef5 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -7759,11 +7759,12 @@ static inline int red_marshall_stream_data(RedChannelClient *rcc,
                         reds_get_mm_time();
 
     outbuf_size = dcc->send_data.stream_outbuf_size;
-    ret = mjpeg_encoder_start_frame(agent->mjpeg_encoder, image->u.bitmap.format,
-                                    width, height,
-                                    &dcc->send_data.stream_outbuf,
-                                    &outbuf_size,
-                                    frame_mm_time);
+    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);
     switch (ret) {
     case MJPEG_ENCODER_FRAME_DROP:
         spice_assert(dcc->use_mjpeg_encoder_rate_control);
@@ -7773,19 +7774,12 @@ static inline int red_marshall_stream_data(RedChannelClient *rcc,
         return TRUE;
     case MJPEG_ENCODER_FRAME_UNSUPPORTED:
         return FALSE;
-    case MJPEG_ENCODER_FRAME_ENCODE_START:
+    case MJPEG_ENCODER_FRAME_ENCODE_DONE:
         break;
     default:
-        spice_error("bad return value (%d) from mjpeg_encoder_start_frame", ret);
+        spice_error("bad return value (%d) from mjpeg_encoder_encode_frame", ret);
         return FALSE;
     }
-
-    if (!mjpeg_encoder_encode_frame(agent->mjpeg_encoder,
-                                    &drawable->red_drawable->u.copy.src_area,
-                                    &image->u.bitmap, stream->top_down)) {
-         return FALSE;
-     }
-    n = mjpeg_encoder_end_frame(agent->mjpeg_encoder);
     dcc->send_data.stream_outbuf_size = outbuf_size;
 
     if (!drawable->sized_stream) {
commit 3708bf9cf0315c2ab7299b5b93cc6d50fd8f1dae
Author: Francois Gouget <fgouget at codeweavers.com>
Date:   Wed Oct 14 17:31:01 2015 +0200

    server: Move the MJPEG encoder functions to mjpeg_encoder.c
    
    Note that this requires some adjustments to the encode_frame()
    parameters to avoid red_worker-specific types.
    
    Signed-off-by: Francois Gouget <fgouget at codeweavers.com>

diff --git a/server/mjpeg_encoder.c b/server/mjpeg_encoder.c
index 3f8252a..3cb2144 100644
--- a/server/mjpeg_encoder.c
+++ b/server/mjpeg_encoder.c
@@ -192,7 +192,7 @@ void mjpeg_encoder_destroy(MJpegEncoder *encoder)
     free(encoder);
 }
 
-uint8_t mjpeg_encoder_get_bytes_per_pixel(MJpegEncoder *encoder)
+static uint8_t mjpeg_encoder_get_bytes_per_pixel(MJpegEncoder *encoder)
 {
     return encoder->bytes_per_pixel;
 }
@@ -693,7 +693,8 @@ static void mjpeg_encoder_adjust_fps(MJpegEncoder *encoder, uint64_t now)
     }
 }
 
-int mjpeg_encoder_start_frame(MJpegEncoder *encoder, SpiceBitmapFmt format,
+int mjpeg_encoder_start_frame(MJpegEncoder *encoder,
+                              SpiceBitmapFmt format,
                               int width, int height,
                               uint8_t **dest, size_t *dest_len,
                               uint32_t frame_mm_time)
@@ -794,8 +795,9 @@ int mjpeg_encoder_start_frame(MJpegEncoder *encoder, SpiceBitmapFmt format,
     return MJPEG_ENCODER_FRAME_ENCODE_START;
 }
 
-int mjpeg_encoder_encode_scanline(MJpegEncoder *encoder, uint8_t *src_pixels,
-                                  size_t image_width)
+static int mjpeg_encoder_encode_scanline(MJpegEncoder *encoder,
+                                         uint8_t *src_pixels,
+                                         size_t image_width)
 {
     unsigned int scanlines_written;
     uint8_t *row;
@@ -851,6 +853,69 @@ size_t mjpeg_encoder_end_frame(MJpegEncoder *encoder)
     return encoder->rate_control.last_enc_size;
 }
 
+static inline uint8_t *get_image_line(SpiceChunks *chunks, size_t *offset,
+                                      int *chunk_nr, int stride)
+{
+    uint8_t *ret;
+    SpiceChunk *chunk;
+
+    chunk = &chunks->chunk[*chunk_nr];
+
+    if (*offset == chunk->len) {
+        if (*chunk_nr == chunks->num_chunks - 1) {
+            return NULL; /* Last chunk */
+        }
+        *offset = 0;
+        (*chunk_nr)++;
+        chunk = &chunks->chunk[*chunk_nr];
+    }
+
+    if (chunk->len - *offset < stride) {
+        spice_warning("bad chunk alignment");
+        return NULL;
+    }
+    ret = chunk->data + *offset;
+    *offset += stride;
+    return ret;
+}
+
+int mjpeg_encoder_encode_frame(MJpegEncoder *encoder, const SpiceRect *src,
+                               const SpiceBitmap *image, int top_down)
+{
+    SpiceChunks *chunks;
+    uint32_t image_stride;
+    size_t offset;
+    int i, chunk;
+
+    chunks = image->data;
+    offset = 0;
+    chunk = 0;
+    image_stride = image->stride;
+
+    const int skip_lines = top_down ? src->top : image->y - (src->bottom - 0);
+    for (i = 0; i < skip_lines; i++) {
+        get_image_line(chunks, &offset, &chunk, image_stride);
+    }
+
+    const unsigned int stream_height = src->bottom - src->top;
+    const unsigned int stream_width = src->right - src->left;
+
+    for (i = 0; i < stream_height; i++) {
+        uint8_t *src_line = get_image_line(chunks, &offset, &chunk, image_stride);
+
+        if (!src_line) {
+            return FALSE;
+        }
+
+        src_line += src->left * mjpeg_encoder_get_bytes_per_pixel(encoder);
+        if (mjpeg_encoder_encode_scanline(encoder, src_line, stream_width) == 0) {
+            return FALSE;
+        }
+    }
+
+    return TRUE;
+}
+
 static void mjpeg_encoder_quality_eval_stop(MJpegEncoder *encoder)
 {
     MJpegEncoderRateControl *rate_control = &encoder->rate_control;
@@ -1021,6 +1086,7 @@ static void mjpeg_encoder_increase_bit_rate(MJpegEncoder *encoder)
                                            rate_control->quality_id,
                                            rate_control->fps);
 }
+
 static void mjpeg_encoder_handle_positive_client_stream_report(MJpegEncoder *encoder,
                                                                uint32_t report_start_frame_mm_time)
 {
diff --git a/server/mjpeg_encoder.h b/server/mjpeg_encoder.h
index d584b92..8e2af10 100644
--- a/server/mjpeg_encoder.h
+++ b/server/mjpeg_encoder.h
@@ -53,8 +53,6 @@ MJpegEncoder *mjpeg_encoder_new(uint64_t starting_bit_rate,
                                 MJpegEncoderRateControlCbs *cbs, void *opaque);
 void mjpeg_encoder_destroy(MJpegEncoder *encoder);
 
-uint8_t mjpeg_encoder_get_bytes_per_pixel(MJpegEncoder *encoder);
-
 /*
  * dest must be either NULL or allocated by malloc, since it might be freed
  * during the encoding, if its size is too small.
@@ -70,8 +68,8 @@ int mjpeg_encoder_start_frame(MJpegEncoder *encoder, SpiceBitmapFmt format,
                               int width, int height,
                               uint8_t **dest, size_t *dest_len,
                               uint32_t frame_mm_time);
-int mjpeg_encoder_encode_scanline(MJpegEncoder *encoder, uint8_t *src_pixels,
-                                  size_t image_width);
+int mjpeg_encoder_encode_frame(MJpegEncoder *encoder, const SpiceRect *src,
+                               const SpiceBitmap *image, int top_down);
 size_t mjpeg_encoder_end_frame(MJpegEncoder *encoder);
 
 /*
diff --git a/server/red_worker.c b/server/red_worker.c
index 1fe316e..8803557 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -7699,69 +7699,6 @@ static inline void display_begin_send_message(RedChannelClient *rcc)
     red_channel_client_begin_send_message(rcc);
 }
 
-static inline uint8_t *red_get_image_line(SpiceChunks *chunks, size_t *offset,
-                                          int *chunk_nr, int stride)
-{
-    uint8_t *ret;
-    SpiceChunk *chunk;
-
-    chunk = &chunks->chunk[*chunk_nr];
-
-    if (*offset == chunk->len) {
-        if (*chunk_nr == chunks->num_chunks - 1) {
-            return NULL; /* Last chunk */
-        }
-        *offset = 0;
-        (*chunk_nr)++;
-        chunk = &chunks->chunk[*chunk_nr];
-    }
-
-    if (chunk->len - *offset < stride) {
-        spice_warning("bad chunk alignment");
-        return NULL;
-    }
-    ret = chunk->data + *offset;
-    *offset += stride;
-    return ret;
-}
-
-static int encode_frame(DisplayChannelClient *dcc, const SpiceRect *src,
-                        const SpiceBitmap *image, Stream *stream)
-{
-    SpiceChunks *chunks;
-    uint32_t image_stride;
-    size_t offset;
-    int i, chunk;
-    StreamAgent *agent = &dcc->stream_agents[stream - dcc->common.worker->streams_buf];
-
-    chunks = image->data;
-    offset = 0;
-    chunk = 0;
-    image_stride = image->stride;
-
-    const int skip_lines = stream->top_down ? src->top : image->y - (src->bottom - 0);
-    for (i = 0; i < skip_lines; i++) {
-        red_get_image_line(chunks, &offset, &chunk, image_stride);
-    }
-
-    const unsigned int stream_height = src->bottom - src->top;
-    const unsigned int stream_width = src->right - src->left;
-
-    for (i = 0; i < stream_height; i++) {
-        uint8_t *src_line = red_get_image_line(chunks, &offset, &chunk, image_stride);
-
-        if (!src_line) {
-            return FALSE;
-        }
-
-        src_line += src->left * mjpeg_encoder_get_bytes_per_pixel(agent->mjpeg_encoder);
-        if (mjpeg_encoder_encode_scanline(agent->mjpeg_encoder, src_line, stream_width) == 0)
-            return FALSE;
-    }
-
-    return TRUE;
-}
-
 static inline int red_marshall_stream_data(RedChannelClient *rcc,
                   SpiceMarshaller *base_marshaller, Drawable *drawable)
 {
@@ -7820,6 +7757,7 @@ static inline int red_marshall_stream_data(RedChannelClient *rcc,
     frame_mm_time =  drawable->red_drawable->mm_time ?
                         drawable->red_drawable->mm_time :
                         reds_get_mm_time();
+
     outbuf_size = dcc->send_data.stream_outbuf_size;
     ret = mjpeg_encoder_start_frame(agent->mjpeg_encoder, image->u.bitmap.format,
                                     width, height,
@@ -7842,10 +7780,11 @@ static inline int red_marshall_stream_data(RedChannelClient *rcc,
         return FALSE;
     }
 
-    if (!encode_frame(dcc, &drawable->red_drawable->u.copy.src_area,
-                      &image->u.bitmap, stream)) {
-        return FALSE;
-    }
+    if (!mjpeg_encoder_encode_frame(agent->mjpeg_encoder,
+                                    &drawable->red_drawable->u.copy.src_area,
+                                    &image->u.bitmap, stream->top_down)) {
+         return FALSE;
+     }
     n = mjpeg_encoder_end_frame(agent->mjpeg_encoder);
     dcc->send_data.stream_outbuf_size = outbuf_size;
 
commit fd451860df2df5a26d66a64c62b24afbe94c4e1b
Author: Francois Gouget <fgouget at codeweavers.com>
Date:   Wed Oct 14 17:30:52 2015 +0200

    server: Move mjpeg_encoder_new() to the end of mjpeg_encoder.c
    
    This also allows getting rid of a couple of forward definitions.
    
    Signed-off-by: Francois Gouget <fgouget at codeweavers.com>

diff --git a/server/mjpeg_encoder.c b/server/mjpeg_encoder.c
index 4d00454..3f8252a 100644
--- a/server/mjpeg_encoder.c
+++ b/server/mjpeg_encoder.c
@@ -174,11 +174,6 @@ struct MJpegEncoder {
     uint32_t num_frames;
 };
 
-static inline void mjpeg_encoder_reset_quality(MJpegEncoder *encoder,
-                                               int quality_id,
-                                               uint32_t fps,
-                                               uint64_t frame_enc_size);
-static uint32_t get_max_fps(uint64_t frame_size, uint64_t bytes_per_sec);
 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,
@@ -189,41 +184,6 @@ static inline int rate_control_is_active(MJpegEncoder* encoder)
     return encoder->cbs.get_roundtrip_ms != NULL;
 }
 
-MJpegEncoder *mjpeg_encoder_new(uint64_t starting_bit_rate,
-                                MJpegEncoderRateControlCbs *cbs, void *opaque)
-{
-    MJpegEncoder *enc;
-
-    spice_assert(!cbs || (cbs && cbs->get_roundtrip_ms && cbs->get_source_fps));
-
-    enc = spice_new0(MJpegEncoder, 1);
-
-    enc->first_frame = TRUE;
-    enc->rate_control.byte_rate = starting_bit_rate / 8;
-    enc->starting_bit_rate = starting_bit_rate;
-
-    if (cbs) {
-        struct timespec time;
-
-        clock_gettime(CLOCK_MONOTONIC, &time);
-        enc->cbs = *cbs;
-        enc->cbs_opaque = opaque;
-        mjpeg_encoder_reset_quality(enc, MJPEG_QUALITY_SAMPLE_NUM / 2, 5, 0);
-        enc->rate_control.during_quality_eval = TRUE;
-        enc->rate_control.quality_eval_data.type = MJPEG_QUALITY_EVAL_TYPE_SET;
-        enc->rate_control.quality_eval_data.reason = MJPEG_QUALITY_EVAL_REASON_RATE_CHANGE;
-        enc->rate_control.warmup_start_time = ((uint64_t) time.tv_sec) * 1000000000 + time.tv_nsec;
-    } else {
-        enc->cbs.get_roundtrip_ms = NULL;
-        mjpeg_encoder_reset_quality(enc, MJPEG_LEGACY_STATIC_QUALITY_ID, MJPEG_MAX_FPS, 0);
-    }
-
-    enc->cinfo.err = jpeg_std_error(&enc->jerr);
-    jpeg_create_compress(&enc->cinfo);
-
-    return enc;
-}
-
 void mjpeg_encoder_destroy(MJpegEncoder *encoder)
 {
     free(encoder->cinfo.dest);
@@ -1277,3 +1237,37 @@ void mjpeg_encoder_get_stats(MJpegEncoder *encoder, MJpegEncoderStats *stats)
     stats->cur_bit_rate = mjpeg_encoder_get_bit_rate(encoder);
     stats->avg_quality = (double)encoder->avg_quality / encoder->num_frames;
 }
+
+MJpegEncoder *mjpeg_encoder_new(uint64_t starting_bit_rate,
+                                MJpegEncoderRateControlCbs *cbs,
+                                void *cbs_opaque)
+{
+    MJpegEncoder *encoder = spice_new0(MJpegEncoder, 1);
+
+    spice_assert(!cbs || (cbs && cbs->get_roundtrip_ms && cbs->get_source_fps));
+
+    encoder->first_frame = TRUE;
+    encoder->rate_control.byte_rate = starting_bit_rate / 8;
+    encoder->starting_bit_rate = starting_bit_rate;
+
+    if (cbs) {
+        struct timespec time;
+
+        clock_gettime(CLOCK_MONOTONIC, &time);
+        encoder->cbs = *cbs;
+        encoder->cbs_opaque = cbs_opaque;
+        mjpeg_encoder_reset_quality(encoder, MJPEG_QUALITY_SAMPLE_NUM / 2, 5, 0);
+        encoder->rate_control.during_quality_eval = TRUE;
+        encoder->rate_control.quality_eval_data.type = MJPEG_QUALITY_EVAL_TYPE_SET;
+        encoder->rate_control.quality_eval_data.reason = MJPEG_QUALITY_EVAL_REASON_RATE_CHANGE;
+        encoder->rate_control.warmup_start_time = ((uint64_t) time.tv_sec) * 1000000000 + time.tv_nsec;
+    } else {
+        encoder->cbs.get_roundtrip_ms = NULL;
+        mjpeg_encoder_reset_quality(encoder, MJPEG_LEGACY_STATIC_QUALITY_ID, MJPEG_MAX_FPS, 0);
+    }
+
+    encoder->cinfo.err = jpeg_std_error(&encoder->jerr);
+    jpeg_create_compress(&encoder->cinfo);
+
+    return encoder;
+}


More information about the Spice-commits mailing list