summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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