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.
---
 server/mjpeg_encoder.c |  102 ++++++++++++++++++++++++++++++++++++++++++++++++
 server/mjpeg_encoder.h |    5 ++
 2 files changed, 107 insertions(+), 0 deletions(-)

diff --git a/server/mjpeg_encoder.c b/server/mjpeg_encoder.c
index ae48da5..8e74e0a 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 cd8f6af..03b25cc 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
-- 
1.7.5.4

_______________________________________________
Spice-devel mailing list
Spice-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/spice-devel

Reply via email to