[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