~ubuntu-branches/debian/stretch/spice/stretch

« back to all changes in this revision

Viewing changes to server/mjpeg_encoder.c

  • Committer: Package Import Robot
  • Author(s): Liang Guo, Liang Guo, Michael Tokarev
  • Date: 2011-11-29 14:37:08 UTC
  • mfrom: (0.6.1) (0.4.2) (2.1.3 sid)
  • Revision ID: package-import@ubuntu.com-20111129143708-jptkxyjl3a4rds2r
Tags: 0.10.0-1
[ Liang Guo ]
* New upstream release (Closes: #651262)
* Refresh debian/copyright
* Remove fix-typo-in-cmd_line_parser-cpp.patch, applied upstream
* Remove fix-typo-in-record-cpp.patch, applied upstream
* Remove use-requires-private-for-libspice-pkgconfig.patch, applied upstream
* Change Build-Depends on libspice-protocol-dev to (>= 0.9.1~)
* Refresh libspice-server1.symbols
* Update debian/rules clean target
* Ignore common/win/my_getopt-1.5/Makefile change when building package
* debian/control: set DMUA

[ Michael Tokarev ]
* use `rm -f' instead of `-rm' in debian/rules clean targets
* remove python_modules/*.pyc in clean target

Show diffs side-by-side

added added

removed removed

Lines of Context:
15
15
   You should have received a copy of the GNU Lesser General Public
16
16
   License along with this library; if not, see <http://www.gnu.org/licenses/>.
17
17
*/
 
18
#ifdef HAVE_CONFIG_H
 
19
#include <config.h>
 
20
#endif
18
21
 
19
22
#include "red_common.h"
20
23
#include "mjpeg_encoder.h"
 
24
#include <jerror.h>
21
25
#include <jpeglib.h>
22
26
 
23
27
struct MJpegEncoder {
24
28
    int width;
25
29
    int height;
26
 
    int stride;
27
 
    uint8_t *frame;
 
30
    uint8_t *row;
28
31
    int first_frame;
29
32
    int quality;
30
33
 
31
34
    struct jpeg_compress_struct cinfo;
32
35
    struct jpeg_error_mgr jerr;
 
36
 
 
37
    unsigned int bytes_per_pixel; /* bytes per pixel of the input buffer */
 
38
    void (*pixel_converter)(uint8_t *src, uint8_t *dest);
33
39
};
34
40
 
35
41
MJpegEncoder *mjpeg_encoder_new(int width, int height)
41
47
    enc->first_frame = TRUE;
42
48
    enc->width = width;
43
49
    enc->height = height;
44
 
    enc->stride = width * 3;
45
50
    enc->quality = 70;
46
 
    if (enc->stride < width) {
47
 
        abort();
48
 
    }
49
 
    enc->frame = spice_malloc_n(enc->stride, height);
50
 
 
51
51
    enc->cinfo.err = jpeg_std_error(&enc->jerr);
52
 
 
53
52
    jpeg_create_compress(&enc->cinfo);
54
53
 
55
54
    return enc;
58
57
void mjpeg_encoder_destroy(MJpegEncoder *encoder)
59
58
{
60
59
    jpeg_destroy_compress(&encoder->cinfo);
61
 
    free(encoder->frame);
 
60
    free(encoder->row);
62
61
    free(encoder);
63
62
}
64
63
 
65
 
uint8_t *mjpeg_encoder_get_frame(MJpegEncoder *encoder)
66
 
{
67
 
    return encoder->frame;
68
 
}
69
 
size_t mjpeg_encoder_get_frame_stride(MJpegEncoder *encoder)
70
 
{
71
 
    return encoder->stride;
72
 
}
73
 
 
74
 
void init_destination(j_compress_ptr cinfo)
75
 
{
76
 
}
77
 
 
78
 
boolean empty_output_buffer(j_compress_ptr cinfo)
79
 
{
80
 
    return FALSE;
81
 
}
82
 
 
83
 
void term_destination(j_compress_ptr cinfo)
84
 
{
85
 
}
86
 
 
87
 
int mjpeg_encoder_encode_frame(MJpegEncoder *encoder,
88
 
                               uint8_t *buffer, size_t buffer_len)
89
 
{
90
 
    struct jpeg_destination_mgr destmgr;
91
 
    uint8_t *frame;
92
 
    int n;
93
 
 
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;
99
 
 
100
 
    encoder->cinfo.dest = &destmgr;
 
64
uint8_t mjpeg_encoder_get_bytes_per_pixel(MJpegEncoder *encoder)
 
65
{
 
66
    return encoder->bytes_per_pixel;
 
67
}
 
68
 
 
69
#ifndef JCS_EXTENSIONS
 
70
/* Pixel conversion routines */
 
71
static void pixel_rgb24bpp_to_24(uint8_t *src, uint8_t *dest)
 
72
{
 
73
    /* libjpegs stores rgb, spice/win32 stores bgr */
 
74
    *dest++ = src[2]; /* red */
 
75
    *dest++ = src[1]; /* green */
 
76
    *dest++ = src[0]; /* blue */
 
77
}
 
78
 
 
79
static void pixel_rgb32bpp_to_24(uint8_t *src, uint8_t *dest)
 
80
{
 
81
    uint32_t pixel = *(uint32_t *)src;
 
82
    *dest++ = (pixel >> 16) & 0xff;
 
83
    *dest++ = (pixel >>  8) & 0xff;
 
84
    *dest++ = (pixel >>  0) & 0xff;
 
85
}
 
86
#endif
 
87
 
 
88
static void pixel_rgb16bpp_to_24(uint8_t *src, uint8_t *dest)
 
89
{
 
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);
 
94
}
 
95
 
 
96
 
 
97
/* code from libjpeg 8 to handle compression to a memory buffer
 
98
 *
 
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.
 
102
 */
 
103
typedef struct {
 
104
  struct jpeg_destination_mgr pub; /* public fields */
 
105
 
 
106
  unsigned char ** outbuffer;   /* target buffer */
 
107
  size_t * outsize;
 
108
  unsigned char * newbuffer;    /* newly allocated buffer */
 
109
  uint8_t * buffer;             /* start of buffer */
 
110
  size_t bufsize;
 
111
} mem_destination_mgr;
 
112
 
 
113
static void init_mem_destination(j_compress_ptr cinfo)
 
114
{
 
115
}
 
116
 
 
117
static boolean empty_mem_output_buffer(j_compress_ptr cinfo)
 
118
{
 
119
  size_t nextsize;
 
120
  uint8_t * nextbuffer;
 
121
  mem_destination_mgr *dest = (mem_destination_mgr *) cinfo->dest;
 
122
 
 
123
  /* Try to allocate new buffer with double size */
 
124
  nextsize = dest->bufsize * 2;
 
125
  nextbuffer = malloc(nextsize);
 
126
 
 
127
  if (nextbuffer == NULL)
 
128
    ERREXIT1(cinfo, JERR_OUT_OF_MEMORY, 10);
 
129
 
 
130
  memcpy(nextbuffer, dest->buffer, dest->bufsize);
 
131
 
 
132
  if (dest->newbuffer != NULL)
 
133
    free(dest->newbuffer);
 
134
 
 
135
  dest->newbuffer = nextbuffer;
 
136
 
 
137
  dest->pub.next_output_byte = nextbuffer + dest->bufsize;
 
138
  dest->pub.free_in_buffer = dest->bufsize;
 
139
 
 
140
  dest->buffer = nextbuffer;
 
141
  dest->bufsize = nextsize;
 
142
 
 
143
  return TRUE;
 
144
}
 
145
 
 
146
static void term_mem_destination(j_compress_ptr cinfo)
 
147
{
 
148
  mem_destination_mgr *dest = (mem_destination_mgr *) cinfo->dest;
 
149
 
 
150
  *dest->outbuffer = dest->buffer;
 
151
  *dest->outsize = dest->bufsize - dest->pub.free_in_buffer;
 
152
}
 
153
 
 
154
/*
 
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.
 
163
 */
 
164
 
 
165
static void
 
166
spice_jpeg_mem_dest(j_compress_ptr cinfo,
 
167
                    unsigned char ** outbuffer, size_t * outsize)
 
168
{
 
169
  mem_destination_mgr *dest;
 
170
#define OUTPUT_BUF_SIZE  4096   /* choose an efficiently fwrite'able size */
 
171
 
 
172
  if (outbuffer == NULL || outsize == NULL)     /* sanity check */
 
173
    ERREXIT(cinfo, JERR_BUFFER_SIZE);
 
174
 
 
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.
 
177
   */
 
178
  if (cinfo->dest == NULL) {    /* first time for this JPEG object? */
 
179
    cinfo->dest = spice_malloc(sizeof(mem_destination_mgr));
 
180
  }
 
181
 
 
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;
 
189
 
 
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;
 
196
  }
 
197
 
 
198
  dest->pub.next_output_byte = dest->buffer = *outbuffer;
 
199
  dest->pub.free_in_buffer = dest->bufsize = *outsize;
 
200
}
 
201
/* end of code from libjpeg */
 
202
 
 
203
int mjpeg_encoder_start_frame(MJpegEncoder *encoder, SpiceBitmapFmt format,
 
204
                              uint8_t **dest, size_t *dest_len)
 
205
{
 
206
    encoder->cinfo.in_color_space   = JCS_RGB;
 
207
    encoder->cinfo.input_components = 3;
 
208
    switch (format) {
 
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;
 
215
#else
 
216
        encoder->pixel_converter = pixel_rgb32bpp_to_24;
 
217
#endif
 
218
        break;
 
219
    case SPICE_BITMAP_FMT_16BIT:
 
220
        encoder->bytes_per_pixel = 2;
 
221
        encoder->pixel_converter = pixel_rgb16bpp_to_24;
 
222
        break;
 
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;
 
227
#else
 
228
        encoder->pixel_converter = pixel_rgb24bpp_to_24;
 
229
#endif
 
230
        break;
 
231
    default:
 
232
        red_printf_some(1000, "unsupported format %d", format);
 
233
        return FALSE;
 
234
    }
 
235
 
 
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) {
 
240
            return FALSE;
 
241
        }
 
242
        encoder->row = spice_malloc(stride);
 
243
    }
 
244
 
 
245
    spice_jpeg_mem_dest(&encoder->cinfo, dest, dest_len);
101
246
 
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;
106
 
 
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);
111
253
 
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);
117
 
            return 0;
 
254
    return TRUE;
 
255
}
 
256
 
 
257
int mjpeg_encoder_encode_scanline(MJpegEncoder *encoder, uint8_t *src_pixels,
 
258
                                  size_t image_width)
 
259
{
 
260
    unsigned int scanlines_written;
 
261
    uint8_t *row;
 
262
 
 
263
    row = encoder->row;
 
264
    if (encoder->pixel_converter) {
 
265
        unsigned int x;
 
266
        for (x = 0; x < image_width; x++) {
 
267
            encoder->pixel_converter(src_pixels, row);
 
268
            row += 3;
 
269
            src_pixels += encoder->bytes_per_pixel;
118
270
        }
119
 
        frame += encoder->stride;
120
 
    }
 
271
        scanlines_written = jpeg_write_scanlines(&encoder->cinfo, &encoder->row, 1);
 
272
    } else {
 
273
        scanlines_written = jpeg_write_scanlines(&encoder->cinfo, &src_pixels, 1);
 
274
    }
 
275
    if (scanlines_written == 0) { /* Not enough space */
 
276
        jpeg_abort_compress(&encoder->cinfo);
 
277
        return 0;
 
278
    }
 
279
 
 
280
    return scanlines_written;
 
281
}
 
282
 
 
283
size_t mjpeg_encoder_end_frame(MJpegEncoder *encoder)
 
284
{
 
285
    mem_destination_mgr *dest = (mem_destination_mgr *) encoder->cinfo.dest;
121
286
 
122
287
    jpeg_finish_compress(&encoder->cinfo);
123
288
 
124
289
    encoder->first_frame = FALSE;
125
 
    return destmgr.next_output_byte - buffer;
 
290
    return dest->pub.next_output_byte - dest->buffer;
126
291
}