jpeg_compressor.cpp
00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include <fvutils/compression/jpeg_compressor.h>
00027 #include <fvutils/color/yuvrgb.h>
00028 #include <fvutils/color/rgbyuv.h>
00029
00030 #include <core/exception.h>
00031
00032 #include <cstdio>
00033 #include <cstring>
00034 #include <cstdlib>
00035 #include <setjmp.h>
00036 extern "C" {
00037 #include <jpeglib.h>
00038 #include <jerror.h>
00039 }
00040
00041 namespace firevision {
00042 #if 0
00043 }
00044 #endif
00045
00046
00047
00048
00049 typedef struct {
00050 struct jpeg_error_mgr pub;
00051 jmp_buf setjmp_buffer;
00052 } fv_jpeg_error_mgr_t;
00053
00054
00055
00056
00057
00058 typedef struct {
00059 struct jpeg_destination_mgr pub;
00060 JOCTET *buffer;
00061 int bufsize;
00062 int datacount;
00063 } fv_jpeg_memory_destination_mgr_t;
00064
00065
00066
00067
00068
00069
00070 METHODDEF(void)
00071 fv_jpeg_init_destination (j_compress_ptr cinfo)
00072 {
00073 fv_jpeg_memory_destination_mgr_t *dest = (fv_jpeg_memory_destination_mgr_t *) cinfo->dest;
00074 dest->pub.next_output_byte = dest->buffer;
00075 dest->pub.free_in_buffer = dest->bufsize;
00076 dest->datacount=0;
00077 }
00078
00079
00080
00081
00082
00083 METHODDEF(boolean)
00084 fv_jpeg_empty_output_buffer (j_compress_ptr cinfo)
00085 {
00086 fv_jpeg_memory_destination_mgr_t *dest = (fv_jpeg_memory_destination_mgr_t *) cinfo->dest;
00087 dest->pub.next_output_byte = dest->buffer;
00088 dest->pub.free_in_buffer = dest->bufsize;
00089
00090 return TRUE;
00091 }
00092
00093
00094
00095
00096
00097
00098 METHODDEF(void)
00099 fv_jpeg_term_destination (j_compress_ptr cinfo)
00100 {
00101
00102
00103 fv_jpeg_memory_destination_mgr_t *dest = (fv_jpeg_memory_destination_mgr_t *) cinfo->dest;
00104 dest->datacount = dest->bufsize - dest->pub.free_in_buffer;
00105 }
00106
00107
00108
00109
00110
00111
00112 GLOBAL(void)
00113 fv_jpeg_memory_destination_setup(j_compress_ptr cinfo, JOCTET *buffer,int bufsize)
00114 {
00115 fv_jpeg_memory_destination_mgr_t *dest;
00116 if ( cinfo->dest == NULL ) {
00117 cinfo->dest = (struct jpeg_destination_mgr *)
00118 (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
00119 sizeof(fv_jpeg_memory_destination_mgr_t));
00120
00121 }
00122
00123 dest = (fv_jpeg_memory_destination_mgr_t *) cinfo->dest;
00124 dest->bufsize = bufsize;
00125 dest->buffer = buffer;
00126 dest->pub.init_destination = fv_jpeg_init_destination;
00127 dest->pub.empty_output_buffer = fv_jpeg_empty_output_buffer;
00128 dest->pub.term_destination = fv_jpeg_term_destination;
00129 }
00130
00131 METHODDEF(void)
00132 init_source(j_decompress_ptr cinfo)
00133 {
00134
00135 }
00136
00137 METHODDEF(boolean)
00138 fill_input_buffer(j_decompress_ptr cinfo)
00139 {
00140
00141 return FALSE;
00142 }
00143
00144 METHODDEF(void)
00145 skip_input_data(j_decompress_ptr cinfo, long num_bytes)
00146 {
00147 if ((size_t)num_bytes > cinfo->src->bytes_in_buffer) {
00148 cinfo->src->next_input_byte = NULL;
00149 cinfo->src->bytes_in_buffer = 0;
00150 } else {
00151 cinfo->src->next_input_byte += (size_t) num_bytes;
00152 cinfo->src->bytes_in_buffer -= (size_t) num_bytes;
00153 }
00154 }
00155
00156 METHODDEF(void)
00157 term_source(j_decompress_ptr cinfo)
00158 {
00159
00160 }
00161
00162
00163
00164
00165
00166
00167
00168
00169 GLOBAL(void)
00170 fv_jpeg_memory_source_setup(j_decompress_ptr cinfo, unsigned char *ptr, size_t size)
00171 {
00172 struct jpeg_source_mgr *src;
00173 src = cinfo->src = (struct jpeg_source_mgr *)
00174 (*cinfo->mem->alloc_small) ((j_common_ptr)cinfo,
00175 JPOOL_PERMANENT,
00176 sizeof(*src));
00177 src->init_source = init_source;
00178 src->fill_input_buffer = fill_input_buffer;
00179 src->skip_input_data = skip_input_data;
00180 src->resync_to_restart = jpeg_resync_to_restart;
00181 src->term_source = term_source;
00182 src->next_input_byte = ptr;
00183 src->bytes_in_buffer = size;
00184 }
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197 JpegImageCompressor::JpegImageCompressor(unsigned int quality, JpegColorspace jcs)
00198 {
00199 this->quality = quality;
00200 jpeg_cs = jcs;
00201 }
00202
00203
00204 JpegImageCompressor::~JpegImageCompressor()
00205 {
00206 }
00207
00208
00209 void
00210 JpegImageCompressor::compress()
00211 {
00212 struct jpeg_compress_struct cinfo;
00213 struct jpeg_error_mgr jerr;
00214 unsigned int row_stride;
00215 unsigned char *row_buffer;
00216
00217
00218 fv_jpeg_memory_destination_mgr_t *dest;
00219
00220
00221 FILE *outfile = NULL;
00222
00223
00224
00225 memset (&cinfo, 0, sizeof(cinfo));
00226 cinfo.err = jpeg_std_error(&jerr);
00227 jpeg_create_compress(&cinfo);
00228
00229
00230 cinfo.image_width = width;
00231 cinfo.image_height = height;
00232 cinfo.input_components = 3;
00233 if ( jpeg_cs == JPEG_CS_RGB ) {
00234 cinfo.in_color_space = JCS_RGB;
00235 } else {
00236 cinfo.in_color_space = JCS_YCbCr;
00237 }
00238
00239 row_stride = cinfo.image_width * cinfo.input_components;
00240
00241 if ( compdest == COMP_DEST_MEM ) {
00242
00243 fv_jpeg_memory_destination_setup(&cinfo, (JOCTET *)jpeg_buffer, jpeg_buffer_size);
00244 } else {
00245 outfile = fopen(filename, "wb");
00246 if (outfile == NULL) {
00247 throw fawkes::Exception("JpegImageCompressor: cannot open %s\n", filename);
00248 }
00249 jpeg_stdio_dest( &cinfo, outfile );
00250 }
00251
00252 jpeg_set_defaults(&cinfo);
00253 jpeg_set_quality (&cinfo, quality, true );
00254 jpeg_start_compress(&cinfo, true);
00255
00256
00257 row_buffer = (unsigned char *)malloc( row_stride );
00258
00259
00260 if ( jpeg_cs == JPEG_CS_RGB ) {
00261 while (cinfo.next_scanline < cinfo.image_height) {
00262 convert_line_yuv422planar_to_rgb( buffer, row_buffer,
00263 cinfo.image_width, cinfo.image_height,
00264 cinfo.next_scanline, 0 );
00265 jpeg_write_scanlines(&cinfo, &row_buffer, 1);
00266 }
00267 } else {
00268 while (cinfo.next_scanline < cinfo.image_height) {
00269 convert_line_yuv422planar_to_yuv444packed( buffer, row_buffer,
00270 cinfo.image_width, cinfo.image_height,
00271 cinfo.next_scanline, 0 );
00272 jpeg_write_scanlines(&cinfo, &row_buffer, 1);
00273 }
00274 }
00275
00276 free(row_buffer);
00277 jpeg_finish_compress(&cinfo);
00278
00279 if ( compdest == COMP_DEST_MEM ) {
00280
00281 dest=(fv_jpeg_memory_destination_mgr_t *)cinfo.dest;
00282 jpeg_bytes = dest->datacount;
00283 } else {
00284 fclose( outfile );
00285 }
00286
00287
00288 jpeg_destroy_compress(&cinfo);
00289
00290 }
00291
00292
00293 void
00294 JpegImageCompressor::set_image_dimensions(unsigned int width, unsigned int height)
00295 {
00296 this->width = width;
00297 this->height = height;
00298 }
00299
00300
00301 void
00302 JpegImageCompressor::set_image_buffer(colorspace_t cspace, unsigned char *buffer)
00303 {
00304 if ( cspace == YUV422_PLANAR ) {
00305 this->buffer = buffer;
00306 }
00307 }
00308
00309
00310 void
00311 JpegImageCompressor::set_compression_destination(ImageCompressor::CompressionDestination cd)
00312 {
00313 compdest = cd;
00314 }
00315
00316
00317 bool
00318 JpegImageCompressor::supports_compression_destination(ImageCompressor::CompressionDestination cd)
00319 {
00320 return true;
00321 }
00322
00323
00324 void
00325 JpegImageCompressor::set_destination_buffer(unsigned char *buf, unsigned int buf_size)
00326 {
00327 jpeg_buffer = buf;
00328 jpeg_buffer_size = buf_size;
00329 }
00330
00331
00332 size_t
00333 JpegImageCompressor::compressed_size()
00334 {
00335 return jpeg_bytes;
00336 }
00337
00338 size_t
00339 JpegImageCompressor::recommended_compressed_buffer_size()
00340 {
00341 return width * height / 5;
00342 }
00343
00344
00345 void
00346 JpegImageCompressor::set_filename(const char *filename)
00347 {
00348 this->filename = filename;
00349 }
00350
00351 }