summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristophe Fergeau <cfergeau@redhat.com>2011-06-24 14:48:24 +0200
committerChristophe Fergeau <cfergeau@redhat.com>2011-07-22 16:53:56 +0200
commit4275095ff956068027af10d26b966d3e23887619 (patch)
tree4bbf2f26a2bc05c45717472479d5ac30a4e6460f
parentcacca4dce6be474a2e564eba544af8222228f492 (diff)
downloadspice-4275095ff956068027af10d26b966d3e23887619.tar.gz
spice-4275095ff956068027af10d26b966d3e23887619.tar.xz
spice-4275095ff956068027af10d26b966d3e23887619.zip
mjpeg_encoder: add mjpeg_encoder_encode_scanline
This API is meant to allow us to move the pixel format conversion into MjpegEncoder. This will allow us to be able to use the additional pixel formats from libjpeg-turbo when available.
-rw-r--r--server/mjpeg_encoder.c102
-rw-r--r--server/mjpeg_encoder.h5
2 files changed, 107 insertions, 0 deletions
diff --git a/server/mjpeg_encoder.c b/server/mjpeg_encoder.c
index ae48da53..8e74e0a5 100644
--- a/server/mjpeg_encoder.c
+++ b/server/mjpeg_encoder.c
@@ -29,11 +29,15 @@ struct MJpegEncoder {
int height;
int stride;
uint8_t *frame;
+ uint8_t *row;
int first_frame;
int quality;
struct jpeg_compress_struct cinfo;
struct jpeg_error_mgr jerr;
+
+ unsigned int bytes_per_pixel; /* bytes per pixel of the input buffer */
+ void (*pixel_converter)(uint8_t *src, uint8_t *dest);
};
MJpegEncoder *mjpeg_encoder_new(int width, int height)
@@ -51,6 +55,7 @@ MJpegEncoder *mjpeg_encoder_new(int width, int height)
abort();
}
enc->frame = spice_malloc_n(enc->stride, height);
+ enc->row = spice_malloc(enc->stride);
enc->cinfo.err = jpeg_std_error(&enc->jerr);
@@ -63,6 +68,7 @@ void mjpeg_encoder_destroy(MJpegEncoder *encoder)
{
jpeg_destroy_compress(&encoder->cinfo);
free(encoder->frame);
+ free(encoder->row);
free(encoder);
}
@@ -76,6 +82,32 @@ size_t mjpeg_encoder_get_frame_stride(MJpegEncoder *encoder)
}
+/* Pixel conversion routines */
+static void pixel_rgb24bpp_to_24(uint8_t *src, uint8_t *dest)
+{
+ /* libjpegs stores rgb, spice/win32 stores bgr */
+ *dest++ = src[2]; /* red */
+ *dest++ = src[1]; /* green */
+ *dest++ = src[0]; /* blue */
+}
+
+static void pixel_rgb32bpp_to_24(uint8_t *src, uint8_t *dest)
+{
+ uint32_t pixel = *(uint32_t *)src;
+ *dest++ = (pixel >> 16) & 0xff;
+ *dest++ = (pixel >> 8) & 0xff;
+ *dest++ = (pixel >> 0) & 0xff;
+}
+
+static void pixel_rgb16bpp_to_24(uint8_t *src, uint8_t *dest)
+{
+ uint16_t pixel = *(uint16_t *)src;
+ *dest++ = ((pixel >> 7) & 0xf8) | ((pixel >> 12) & 0x7);
+ *dest++ = ((pixel >> 2) & 0xf8) | ((pixel >> 7) & 0x7);
+ *dest++ = ((pixel << 3) & 0xf8) | ((pixel >> 2) & 0x7);
+}
+
+
/* code from libjpeg 8 to handle compression to a memory buffer
*
* Copyright (C) 1994-1996, Thomas G. Lane.
@@ -182,6 +214,76 @@ jpeg_mem_dest (j_compress_ptr cinfo,
}
/* end of code from libjpeg */
+int mjpeg_encoder_start_frame(MJpegEncoder *encoder, SpiceBitmapFmt format,
+ uint8_t **dest, size_t *dest_len)
+{
+ switch (format) {
+ case SPICE_BITMAP_FMT_32BIT:
+ encoder->bytes_per_pixel = 4;
+ encoder->pixel_converter = pixel_rgb32bpp_to_24;
+ break;
+ case SPICE_BITMAP_FMT_16BIT:
+ encoder->bytes_per_pixel = 2;
+ encoder->pixel_converter = pixel_rgb16bpp_to_24;
+ break;
+ case SPICE_BITMAP_FMT_24BIT:
+ encoder->bytes_per_pixel = 3;
+ encoder->pixel_converter = pixel_rgb24bpp_to_24;
+ break;
+ default:
+ red_printf_some(1000, "unsupported format %d", format);
+ return FALSE;
+ }
+
+ jpeg_mem_dest(&encoder->cinfo, dest, dest_len);
+
+ encoder->cinfo.image_width = encoder->width;
+ encoder->cinfo.image_height = encoder->height;
+ encoder->cinfo.input_components = 3;
+ encoder->cinfo.in_color_space = JCS_RGB;
+
+ jpeg_set_defaults(&encoder->cinfo);
+ encoder->cinfo.dct_method = JDCT_IFAST;
+ jpeg_set_quality(&encoder->cinfo, encoder->quality, TRUE);
+ jpeg_start_compress(&encoder->cinfo, encoder->first_frame);
+
+ return TRUE;
+}
+
+int mjpeg_encoder_encode_scanline(MJpegEncoder *encoder, uint8_t *src_pixels,
+ size_t image_width)
+{
+ unsigned int scanlines_written;
+ uint8_t *row;
+
+ row = encoder->row;
+ if (encoder->pixel_converter) {
+ unsigned int x;
+ for (x = 0; x < image_width; x++) {
+ encoder->pixel_converter(src_pixels, row);
+ row += 3;
+ src_pixels += encoder->bytes_per_pixel;
+ }
+ }
+ scanlines_written = jpeg_write_scanlines(&encoder->cinfo, &encoder->row, 1);
+ if (scanlines_written == 0) { /* Not enough space */
+ jpeg_abort_compress(&encoder->cinfo);
+ return 0;
+ }
+
+ return scanlines_written;
+}
+
+size_t mjpeg_encoder_end_frame(MJpegEncoder *encoder)
+{
+ mem_destination_mgr *dest = (mem_destination_mgr *) encoder->cinfo.dest;
+
+ jpeg_finish_compress(&encoder->cinfo);
+
+ encoder->first_frame = FALSE;
+ return dest->pub.next_output_byte - dest->buffer;
+}
+
int mjpeg_encoder_encode_frame(MJpegEncoder *encoder,
uint8_t **buffer, size_t *buffer_len)
{
diff --git a/server/mjpeg_encoder.h b/server/mjpeg_encoder.h
index cd8f6af4..03b25cc8 100644
--- a/server/mjpeg_encoder.h
+++ b/server/mjpeg_encoder.h
@@ -30,6 +30,11 @@ uint8_t *mjpeg_encoder_get_frame(MJpegEncoder *encoder);
size_t mjpeg_encoder_get_frame_stride(MJpegEncoder *encoder);
int mjpeg_encoder_encode_frame(MJpegEncoder *encoder,
uint8_t **buffer, size_t *buffer_len);
+int mjpeg_encoder_start_frame(MJpegEncoder *encoder, SpiceBitmapFmt format,
+ uint8_t **dest, size_t *dest_len);
+int mjpeg_encoder_encode_scanline(MJpegEncoder *encoder, uint8_t *src_pixels,
+ size_t image_width);
+size_t mjpeg_encoder_end_frame(MJpegEncoder *encoder);
#endif