58
57
void mjpeg_encoder_destroy(MJpegEncoder *encoder)
60
59
jpeg_destroy_compress(&encoder->cinfo);
65
uint8_t *mjpeg_encoder_get_frame(MJpegEncoder *encoder)
67
return encoder->frame;
69
size_t mjpeg_encoder_get_frame_stride(MJpegEncoder *encoder)
71
return encoder->stride;
74
void init_destination(j_compress_ptr cinfo)
78
boolean empty_output_buffer(j_compress_ptr cinfo)
83
void term_destination(j_compress_ptr cinfo)
87
int mjpeg_encoder_encode_frame(MJpegEncoder *encoder,
88
uint8_t *buffer, size_t buffer_len)
90
struct jpeg_destination_mgr destmgr;
94
destmgr.next_output_byte = buffer;
95
destmgr.free_in_buffer = buffer_len;
96
destmgr.init_destination = init_destination;
97
destmgr.empty_output_buffer = empty_output_buffer;
98
destmgr.term_destination = term_destination;
100
encoder->cinfo.dest = &destmgr;
64
uint8_t mjpeg_encoder_get_bytes_per_pixel(MJpegEncoder *encoder)
66
return encoder->bytes_per_pixel;
69
#ifndef JCS_EXTENSIONS
70
/* Pixel conversion routines */
71
static void pixel_rgb24bpp_to_24(uint8_t *src, uint8_t *dest)
73
/* libjpegs stores rgb, spice/win32 stores bgr */
74
*dest++ = src[2]; /* red */
75
*dest++ = src[1]; /* green */
76
*dest++ = src[0]; /* blue */
79
static void pixel_rgb32bpp_to_24(uint8_t *src, uint8_t *dest)
81
uint32_t pixel = *(uint32_t *)src;
82
*dest++ = (pixel >> 16) & 0xff;
83
*dest++ = (pixel >> 8) & 0xff;
84
*dest++ = (pixel >> 0) & 0xff;
88
static void pixel_rgb16bpp_to_24(uint8_t *src, uint8_t *dest)
90
uint16_t pixel = *(uint16_t *)src;
91
*dest++ = ((pixel >> 7) & 0xf8) | ((pixel >> 12) & 0x7);
92
*dest++ = ((pixel >> 2) & 0xf8) | ((pixel >> 7) & 0x7);
93
*dest++ = ((pixel << 3) & 0xf8) | ((pixel >> 2) & 0x7);
97
/* code from libjpeg 8 to handle compression to a memory buffer
99
* Copyright (C) 1994-1996, Thomas G. Lane.
100
* Modified 2009 by Guido Vollbeding.
101
* This file is part of the Independent JPEG Group's software.
104
struct jpeg_destination_mgr pub; /* public fields */
106
unsigned char ** outbuffer; /* target buffer */
108
unsigned char * newbuffer; /* newly allocated buffer */
109
uint8_t * buffer; /* start of buffer */
111
} mem_destination_mgr;
113
static void init_mem_destination(j_compress_ptr cinfo)
117
static boolean empty_mem_output_buffer(j_compress_ptr cinfo)
120
uint8_t * nextbuffer;
121
mem_destination_mgr *dest = (mem_destination_mgr *) cinfo->dest;
123
/* Try to allocate new buffer with double size */
124
nextsize = dest->bufsize * 2;
125
nextbuffer = malloc(nextsize);
127
if (nextbuffer == NULL)
128
ERREXIT1(cinfo, JERR_OUT_OF_MEMORY, 10);
130
memcpy(nextbuffer, dest->buffer, dest->bufsize);
132
if (dest->newbuffer != NULL)
133
free(dest->newbuffer);
135
dest->newbuffer = nextbuffer;
137
dest->pub.next_output_byte = nextbuffer + dest->bufsize;
138
dest->pub.free_in_buffer = dest->bufsize;
140
dest->buffer = nextbuffer;
141
dest->bufsize = nextsize;
146
static void term_mem_destination(j_compress_ptr cinfo)
148
mem_destination_mgr *dest = (mem_destination_mgr *) cinfo->dest;
150
*dest->outbuffer = dest->buffer;
151
*dest->outsize = dest->bufsize - dest->pub.free_in_buffer;
155
* Prepare for output to a memory buffer.
156
* The caller may supply an own initial buffer with appropriate size.
157
* Otherwise, or when the actual data output exceeds the given size,
158
* the library adapts the buffer size as necessary.
159
* The standard library functions malloc/free are used for allocating
160
* larger memory, so the buffer is available to the application after
161
* finishing compression, and then the application is responsible for
162
* freeing the requested memory.
166
spice_jpeg_mem_dest(j_compress_ptr cinfo,
167
unsigned char ** outbuffer, size_t * outsize)
169
mem_destination_mgr *dest;
170
#define OUTPUT_BUF_SIZE 4096 /* choose an efficiently fwrite'able size */
172
if (outbuffer == NULL || outsize == NULL) /* sanity check */
173
ERREXIT(cinfo, JERR_BUFFER_SIZE);
175
/* The destination object is made permanent so that multiple JPEG images
176
* can be written to the same buffer without re-executing jpeg_mem_dest.
178
if (cinfo->dest == NULL) { /* first time for this JPEG object? */
179
cinfo->dest = spice_malloc(sizeof(mem_destination_mgr));
182
dest = (mem_destination_mgr *) cinfo->dest;
183
dest->pub.init_destination = init_mem_destination;
184
dest->pub.empty_output_buffer = empty_mem_output_buffer;
185
dest->pub.term_destination = term_mem_destination;
186
dest->outbuffer = outbuffer;
187
dest->outsize = outsize;
188
dest->newbuffer = NULL;
190
if (*outbuffer == NULL || *outsize == 0) {
191
/* Allocate initial buffer */
192
dest->newbuffer = *outbuffer = malloc(OUTPUT_BUF_SIZE);
193
if (dest->newbuffer == NULL)
194
ERREXIT1(cinfo, JERR_OUT_OF_MEMORY, 10);
195
*outsize = OUTPUT_BUF_SIZE;
198
dest->pub.next_output_byte = dest->buffer = *outbuffer;
199
dest->pub.free_in_buffer = dest->bufsize = *outsize;
201
/* end of code from libjpeg */
203
int mjpeg_encoder_start_frame(MJpegEncoder *encoder, SpiceBitmapFmt format,
204
uint8_t **dest, size_t *dest_len)
206
encoder->cinfo.in_color_space = JCS_RGB;
207
encoder->cinfo.input_components = 3;
209
case SPICE_BITMAP_FMT_32BIT:
210
case SPICE_BITMAP_FMT_RGBA:
211
encoder->bytes_per_pixel = 4;
212
#ifdef JCS_EXTENSIONS
213
encoder->cinfo.in_color_space = JCS_EXT_BGRX;
214
encoder->cinfo.input_components = 4;
216
encoder->pixel_converter = pixel_rgb32bpp_to_24;
219
case SPICE_BITMAP_FMT_16BIT:
220
encoder->bytes_per_pixel = 2;
221
encoder->pixel_converter = pixel_rgb16bpp_to_24;
223
case SPICE_BITMAP_FMT_24BIT:
224
encoder->bytes_per_pixel = 3;
225
#ifdef JCS_EXTENSIONS
226
encoder->cinfo.in_color_space = JCS_EXT_BGR;
228
encoder->pixel_converter = pixel_rgb24bpp_to_24;
232
red_printf_some(1000, "unsupported format %d", format);
236
if ((encoder->pixel_converter != NULL) && (encoder->row == NULL)) {
237
unsigned int stride = encoder->width * 3;
238
/* check for integer overflow */
239
if (stride < encoder->width) {
242
encoder->row = spice_malloc(stride);
245
spice_jpeg_mem_dest(&encoder->cinfo, dest, dest_len);
102
247
encoder->cinfo.image_width = encoder->width;
103
248
encoder->cinfo.image_height = encoder->height;
104
encoder->cinfo.input_components = 3;
105
encoder->cinfo.in_color_space = JCS_RGB;
107
249
jpeg_set_defaults(&encoder->cinfo);
108
250
encoder->cinfo.dct_method = JDCT_IFAST;
109
251
jpeg_set_quality(&encoder->cinfo, encoder->quality, TRUE);
110
252
jpeg_start_compress(&encoder->cinfo, encoder->first_frame);
112
frame = encoder->frame;
113
while (encoder->cinfo.next_scanline < encoder->cinfo.image_height) {
114
n = jpeg_write_scanlines(&encoder->cinfo, &frame, 1);
115
if (n == 0) { /* Not enough space */
116
jpeg_abort_compress(&encoder->cinfo);
257
int mjpeg_encoder_encode_scanline(MJpegEncoder *encoder, uint8_t *src_pixels,
260
unsigned int scanlines_written;
264
if (encoder->pixel_converter) {
266
for (x = 0; x < image_width; x++) {
267
encoder->pixel_converter(src_pixels, row);
269
src_pixels += encoder->bytes_per_pixel;
119
frame += encoder->stride;
271
scanlines_written = jpeg_write_scanlines(&encoder->cinfo, &encoder->row, 1);
273
scanlines_written = jpeg_write_scanlines(&encoder->cinfo, &src_pixels, 1);
275
if (scanlines_written == 0) { /* Not enough space */
276
jpeg_abort_compress(&encoder->cinfo);
280
return scanlines_written;
283
size_t mjpeg_encoder_end_frame(MJpegEncoder *encoder)
285
mem_destination_mgr *dest = (mem_destination_mgr *) encoder->cinfo.dest;
122
287
jpeg_finish_compress(&encoder->cinfo);
124
289
encoder->first_frame = FALSE;
125
return destmgr.next_output_byte - buffer;
290
return dest->pub.next_output_byte - dest->buffer;