Fawkes API
Fawkes Development Version
|
00001 00002 /*************************************************************************** 00003 * imagedecompressor.h - image de-compressor interface 00004 * 00005 * Created: July 2007 (Sci-Bono, South Africa, B&B) 00006 * Copyright 2006-2007 Daniel Beck 00007 * 2007-2011 Tim Niemueller [www.niemueller.de] 00008 * 00009 ****************************************************************************/ 00010 00011 /* This program is free software; you can redistribute it and/or modify 00012 * it under the terms of the GNU General Public License as published by 00013 * the Free Software Foundation; either version 2 of the License, or 00014 * (at your option) any later version. A runtime exception applies to 00015 * this software (see LICENSE.GPL_WRE file mentioned below for details). 00016 * 00017 * This program is distributed in the hope that it will be useful, 00018 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00019 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00020 * GNU Library General Public License for more details. 00021 * 00022 * Read the full text in the LICENSE.GPL_WRE file in the doc directory. 00023 */ 00024 00025 #include <fvutils/color/conversions.h> 00026 #include <fvutils/compression/jpeg_decompressor.h> 00027 #include <core/exception.h> 00028 00029 #include <sys/types.h> 00030 #include <cstdio> 00031 #include <cstdlib> 00032 #include <setjmp.h> 00033 00034 extern "C" { 00035 #include <jpeglib.h> 00036 #include <jerror.h> 00037 } 00038 00039 namespace firevision { 00040 #if 0 /* just to make Emacs auto-indent happy */ 00041 } 00042 #endif 00043 00044 ///@cond INTERNALS 00045 00046 typedef struct { 00047 struct jpeg_source_mgr pub; 00048 00049 JOCTET * buffer; 00050 } my_source_mgr; 00051 00052 typedef my_source_mgr * my_src_ptr; 00053 00054 00055 struct my_error_mgr { 00056 struct jpeg_error_mgr pub; /* "public" fields */ 00057 00058 jmp_buf setjmp_buffer; /* for return to caller */ 00059 }; 00060 00061 typedef struct my_error_mgr * my_error_ptr; 00062 00063 /* 00064 * Here's the routine that will replace the standard error_exit method: 00065 */ 00066 00067 METHODDEF(void) 00068 my_error_exit (j_common_ptr cinfo) 00069 { 00070 /* cinfo->err really points to a my_error_mgr struct, so coerce pointer */ 00071 my_error_ptr myerr = (my_error_ptr) cinfo->err; 00072 00073 /* Return control to the setjmp point */ 00074 longjmp(myerr->setjmp_buffer, 1); 00075 } 00076 00077 METHODDEF(void) 00078 init_source (j_decompress_ptr cinfo) 00079 { 00080 } 00081 00082 00083 METHODDEF(boolean) 00084 fill_input_buffer (j_decompress_ptr cinfo) 00085 { 00086 return TRUE; 00087 } 00088 00089 METHODDEF(void) 00090 skip_input_data (j_decompress_ptr cinfo, long num_bytes) 00091 { 00092 my_src_ptr src = (my_src_ptr) cinfo->src; 00093 /* Just a dumb implementation for now. Could use fseek() except 00094 * it doesn't work on pipes. Not clear that being smart is worth 00095 * any trouble anyway --- large skips are infrequent. 00096 */ 00097 if (num_bytes > 0) { 00098 while (num_bytes > (long) src->pub.bytes_in_buffer) { 00099 num_bytes -= (long) src->pub.bytes_in_buffer; 00100 (void) fill_input_buffer(cinfo); 00101 /* note we assume that fill_input_buffer will never return FALSE, 00102 * so suspension need not be handled. 00103 */ 00104 } 00105 src->pub.next_input_byte += (size_t) num_bytes; 00106 src->pub.bytes_in_buffer -= (size_t) num_bytes; 00107 } 00108 } 00109 00110 METHODDEF(void) 00111 term_source (j_decompress_ptr cinfo) 00112 { 00113 /* no work necessary here */ 00114 } 00115 00116 GLOBAL(void) 00117 my_mem_src (j_decompress_ptr cinfo, JOCTET * buffer, size_t bytes) 00118 { 00119 my_src_ptr src; 00120 00121 if (cinfo->src == NULL) { /* first time for this JPEG object? */ 00122 cinfo->src = (struct jpeg_source_mgr *) 00123 (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, 00124 sizeof(my_source_mgr)); 00125 src = (my_src_ptr) cinfo->src; 00126 // src->buffer = (JOCTET *) 00127 // (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, 00128 // INPUT_BUF_SIZE * SIZEOF(JOCTET)); 00129 } 00130 00131 src = (my_src_ptr) cinfo->src; 00132 src->pub.init_source = init_source; 00133 src->pub.fill_input_buffer = fill_input_buffer; 00134 src->pub.skip_input_data = skip_input_data; 00135 src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */ 00136 src->pub.term_source = term_source; 00137 src->pub.bytes_in_buffer = bytes; 00138 src->pub.next_input_byte = buffer; 00139 } 00140 00141 /// @endcond 00142 00143 /** @class JpegImageDecompressor <fvutils/compression/jpeg_decompressor.h> 00144 * Decompressor for JPEG images. 00145 * @author Daniel Beck 00146 * @author Tim Niemueller 00147 */ 00148 00149 /** Constructor. */ 00150 JpegImageDecompressor::JpegImageDecompressor() 00151 { 00152 } 00153 00154 void 00155 JpegImageDecompressor::decompress() 00156 { 00157 JSAMPROW row_pointer[1]; 00158 unsigned long location = 0; 00159 unsigned char *buffer; 00160 00161 // JPEG decompression 00162 // Allocate and initialize a JPEG decompression object 00163 struct jpeg_decompress_struct cinfo; 00164 00165 struct my_error_mgr jerr; 00166 cinfo.err = jpeg_std_error(&jerr.pub); 00167 jerr.pub.error_exit = my_error_exit; 00168 /* Establish the setjmp return context for my_error_exit to use. */ 00169 if (setjmp(jerr.setjmp_buffer)) { 00170 char buffer[JMSG_LENGTH_MAX]; 00171 (*cinfo.err->format_message) ((jpeg_common_struct *)&cinfo, buffer); 00172 00173 /* If we get here, the JPEG code has signaled an error. 00174 * We need to clean up the JPEG object, close the input file, and return. 00175 */ 00176 jpeg_destroy_decompress(&cinfo); 00177 throw fawkes::Exception("Decompression failed: %s", buffer); 00178 } 00179 00180 jpeg_create_decompress(&cinfo); 00181 00182 // Specify the source of the compressed data 00183 my_mem_src(&cinfo, _compressed_buffer, _compressed_buffer_size); 00184 00185 // Call jpeg_read_header() to obtain image info 00186 jpeg_read_header(&cinfo, TRUE); 00187 00188 // set output color space 00189 // cinfo.out_color_space = JCS_YCbCr; 00190 00191 // Set parameters for decompression 00192 00193 // jpeg_start_decompress(...); 00194 jpeg_start_decompress(&cinfo); 00195 00196 buffer = (unsigned char*)malloc( cinfo.output_width * cinfo.output_height * cinfo.num_components ); 00197 00198 row_pointer[0] = (unsigned char *)malloc( cinfo.output_width * cinfo.num_components ); 00199 00200 // while (scan lines remain to be read) 00201 // jpeg_read_scanlines(...); 00202 while( cinfo.output_scanline < cinfo.image_height ) 00203 { 00204 jpeg_read_scanlines( &cinfo, row_pointer, 1 ); 00205 for( unsigned int i=0; i < cinfo.image_width * cinfo.num_components; i++) 00206 buffer[location++] = row_pointer[0][i]; 00207 } 00208 00209 // jpeg_finish_decompress(...); 00210 jpeg_finish_decompress(&cinfo); 00211 00212 // Release the JPEG decompression object 00213 jpeg_destroy_decompress(&cinfo); 00214 00215 free(row_pointer[0]); 00216 00217 // convert to yuv422packed and store in member frame_buffer 00218 convert(RGB, YUV422_PLANAR, buffer, _decompressed_buffer, cinfo.output_width, cinfo.output_height); 00219 00220 free(buffer); 00221 00222 } 00223 00224 } // end namespace firevision