summaryrefslogtreecommitdiffstats
path: root/server/mjpeg_encoder.c
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 /server/mjpeg_encoder.c
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.
Diffstat (limited to 'server/mjpeg_encoder.c')
-rw-r--r--server/mjpeg_encoder.c102
1 files changed, 102 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)
{