Fawkes API  Fawkes Development Version
jpeg_decompressor.cpp
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