Homepage
Demos
Overview
Downloads
Dev. Resources
Reference
Credits

JPEGGenerator.cc

Go to the documentation of this file.
00001 #include "JPEGGenerator.h"
00002 #include "InterleavedYUVGenerator.h"
00003 #include "Events/DataEvent.h"
00004 #include "Events/EventRouter.h"
00005 #include "Events/FilterBankEvent.h"
00006 #include "Wireless/Wireless.h"
00007 #include "Shared/Config.h"
00008 #include "Shared/WorldState.h"
00009 
00010 #include "Shared/jpeg-6b/jpeg_mem_dest.h"
00011 
00012 #include "Shared/debuget.h"
00013 
00014 JPEGGenerator::JPEGGenerator(unsigned int mysid, FilterBankGenerator* fbg, EventBase::EventTypeID_t tid)
00015   : FilterBankGenerator("JPEGGenerator","JPEGGenerator",EventBase::visJPEGEGID,mysid,fbg,tid), srcMode(SRC_AUTO), curMode(SRC_AUTO), bytesUsed(NULL), cinfo(), jerr(), quality(-1U)
00016 {
00017   if(dynamic_cast<const InterleavedYUVGenerator*>(src)!=NULL)
00018     curMode=SRC_COLOR;
00019   else
00020     curMode=SRC_GRAYSCALE;
00021 
00022   // We set the err object before we create the compress...  the idea
00023   // is if the creation fails, we can still get the error as to why it
00024   // failed.
00025   cinfo.err = jpeg_std_error(&jerr);
00026   jpeg_create_compress(&cinfo);
00027 
00028   //this part is only necessary if you override setNumImages yourself
00029   if(fbg!=NULL) {
00030     numLayers=numChannels=0; //this is to force setNumImages to override settings provided by FilterBankGenerator
00031     setNumImages(fbg->getNumLayers(),fbg->getNumChannels());
00032   }
00033 }
00034 
00035 JPEGGenerator::JPEGGenerator(unsigned int mysid, src_mode_t mode, FilterBankGenerator* fbg, EventBase::EventTypeID_t tid)
00036   : FilterBankGenerator("JPEGGenerator","JPEGGenerator",EventBase::visJPEGEGID,mysid,fbg,tid), srcMode(mode), curMode(mode), bytesUsed(NULL), cinfo(), jerr(), quality(-1U)
00037 {
00038   if(srcMode==SRC_AUTO) {
00039     if(dynamic_cast<const InterleavedYUVGenerator*>(src)!=NULL)
00040       curMode=SRC_COLOR;
00041     else
00042       curMode=SRC_GRAYSCALE;
00043   }
00044   
00045   // We set the err object before we create the compress...  the idea
00046   // is if the creation fails, we can still get the error as to why it
00047   // failed.
00048   cinfo.err = jpeg_std_error(&jerr);
00049   jpeg_create_compress(&cinfo);
00050 
00051   //this part is only necessary if you override setNumImages yourself
00052   if(fbg!=NULL) {
00053     numLayers=numChannels=0; //this is to force setNumImages to override settings provided by FilterBankGenerator
00054     setNumImages(fbg->getNumLayers(),fbg->getNumChannels());
00055   }
00056 }
00057 
00058 JPEGGenerator::~JPEGGenerator() {
00059   freeCaches();
00060   destruct();
00061   jpeg_destroy_compress(&cinfo);
00062 }
00063 
00064 
00065 /*! The const casts in this function are regretable but necessary
00066  *  since the corresponding OPEN-R functions require mutable
00067  *  arguments, even though they shouldn't be modifying the data
00068  */
00069 void
00070 JPEGGenerator::processEvent(const EventBase& event) {
00071   FilterBankGenerator::processEvent(event);
00072   if(event.getGeneratorID()==getListenGeneratorID() && event.getSourceID()==getListenSourceID()) {
00073     if(getSourceMode()==SRC_AUTO) { //if not auto, curMode was already set when srcMode was set
00074       if(dynamic_cast<const InterleavedYUVGenerator*>(src)!=NULL)
00075         curMode=SRC_COLOR;
00076       else
00077         curMode=SRC_GRAYSCALE;
00078     }
00079     erouter->postEvent(new FilterBankEvent(this,getGeneratorID(),getSourceID(),EventBase::activateETID));
00080     erouter->postEvent(new FilterBankEvent(this,getGeneratorID(),getSourceID(),EventBase::statusETID));
00081     erouter->postEvent(new FilterBankEvent(this,getGeneratorID(),getSourceID(),EventBase::deactivateETID));
00082   }
00083 }
00084 
00085 unsigned int
00086 JPEGGenerator::getBinSize() const {
00087   unsigned int used=FilterBankGenerator::getBinSize();
00088   used+=strlen("JPEGColor")+LoadSave::stringpad;
00089   if(bytesUsed[selectedSaveLayer][selectedSaveChannel]!=0)
00090     used+=bytesUsed[selectedSaveLayer][selectedSaveChannel];
00091   else
00092     used+=widths[selectedSaveLayer]*heights[selectedSaveLayer]*3+JPEG_HEADER_PAD;
00093   return used;
00094 }
00095 
00096 unsigned int
00097 JPEGGenerator::LoadBuffer(const char buf[], unsigned int len) {
00098   unsigned int origlen=len;
00099   unsigned int used;
00100   std::string tmp;
00101   if(0==(used=FilterBankGenerator::LoadBuffer(buf,len))) return 0;
00102   len-=used; buf+=used;
00103   if(0==(used=decode(tmp,buf,len))) return 0;
00104   len-=used; buf+=used;
00105   if(tmp!="JPEGColor" && tmp!="JPEGGray") {
00106     serr->printf("Unhandled image type for JPEGGenerator: %s",tmp.c_str());
00107     return 0;
00108   } else {
00109     if(tmp=="JPEGColor" && getCurrentSourceFormat()==SRC_GRAYSCALE)
00110       serr->printf("Warning: loading grayscale into color image");
00111     if(tmp=="JPEGGrayscale" && getCurrentSourceFormat()==SRC_COLOR)
00112       serr->printf("Warning: loading color into grayscale image");
00113     unsigned int tmpL;
00114     if(0==(used=decode(tmpL,buf,len))) return 0;
00115     len-=used; buf+=used;
00116     if(tmpL>len)
00117       return 0;
00118     if(images[selectedSaveLayer][selectedSaveChannel]!=NULL)
00119       delete [] images[selectedSaveLayer][selectedSaveChannel];
00120     images[selectedSaveLayer][selectedSaveChannel]=createImageCache(selectedSaveLayer,selectedSaveChannel);
00121     used=bytesUsed[selectedSaveLayer][selectedSaveChannel]=tmpL;
00122     unsigned char* img=getImage(selectedSaveLayer,selectedSaveChannel);
00123     if(img==NULL)
00124       return 0;
00125     memcpy(img,buf,used);
00126     len-=used; buf+=used;
00127     imageValids[selectedSaveLayer][selectedSaveChannel]=true;
00128     return origlen-len; 
00129   }
00130 }
00131 
00132 unsigned int
00133 JPEGGenerator::SaveBuffer(char buf[], unsigned int len) const {
00134   unsigned int origlen=len;
00135   unsigned int used;
00136   if(0==(used=FilterBankGenerator::SaveBuffer(buf,len))) return 0;
00137   len-=used; buf+=used;
00138 
00139   char * type;
00140   if(getCurrentSourceFormat()==SRC_COLOR)
00141     type="JPEGColor";
00142   else if(getCurrentSourceFormat()==SRC_GRAYSCALE)
00143     type="JPEGGrayscale";
00144   else {
00145     serr->printf("SaveBuffer failed - unsuitable or unknown mode/generator pair");
00146     return 0;
00147   }
00148   if(0==(used=encode(type,buf,len))) return 0;
00149   len-=used; buf+=used;
00150   
00151   if(images[selectedSaveLayer][selectedSaveChannel]==NULL) {
00152     serr->printf("JPEGGenerator::SaveBuffer() failed because selected image is NULL -- call selectSaveImage first to make sure it's up to date\n");
00153     return 0;
00154   }
00155   if(!imageValids[selectedSaveLayer][selectedSaveChannel]) {
00156     serr->printf("JPEGGenerator::SaveBuffer() failed because selected image is invalid -- call selectSaveImage first to make sure it's up to date\n");
00157     return 0;
00158   }
00159   unsigned char* img=images[selectedSaveLayer][selectedSaveChannel];
00160   if(img==NULL)
00161     return 0;
00162   if(0==(used=encode(bytesUsed[selectedSaveLayer][selectedSaveChannel],buf,len))) return 0;
00163   len-=used; buf+=used;
00164   used=bytesUsed[selectedSaveLayer][selectedSaveChannel];
00165   if(used>len)
00166     return 0;
00167   memcpy(buf,img,used);
00168   len-=used;
00169   return origlen-len;
00170 }
00171 
00172 void
00173 JPEGGenerator::setNumImages(unsigned int nLayers, unsigned int nChannels) {
00174   if(nLayers==numLayers && nChannels==numChannels)
00175     return;
00176   FilterBankGenerator::setNumImages(nLayers,nChannels);
00177   for(unsigned int i=0; i<numLayers; i++)
00178     strides[i]=skips[i]=0;
00179   bytesUsed=new unsigned int*[numLayers];
00180   for(unsigned int res=0; res<numLayers; res++) {
00181     increments[res]=3;
00182     bytesUsed[res]=new unsigned int[numChannels];
00183     for(unsigned int i=0; i<numChannels; i++)
00184       bytesUsed[res][i]=0;
00185   }
00186 }
00187 
00188 unsigned char *
00189 JPEGGenerator::createImageCache(unsigned int layer, unsigned int /*chan*/) const {
00190   return new unsigned char[widths[layer]*heights[layer]*3+JPEG_HEADER_PAD];
00191 }
00192 
00193 /*! This function is taken pretty directly from the write_jpeg_mem()
00194  *  function from Sony's W3AIBO sample code.
00195  *
00196  *  I have adapted it for this object, and added the ability to
00197  *  process greyscale images as well as color.
00198  */
00199 void
00200 JPEGGenerator::calcImage(unsigned int layer, unsigned int chan) {
00201   PROFSECTION("JPEGGenerator::calcImage(...)",state->mainProfile);
00202 try {
00203   //pass the destination buffer and buffer size here
00204   jpeg_mem_dest(&cinfo, images[layer][chan], widths[layer]*heights[layer]*3+JPEG_HEADER_PAD);
00205 
00206   // mode setup
00207   cinfo.image_width = widths[layer];
00208   cinfo.image_height = heights[layer];
00209   if(getCurrentSourceFormat()==SRC_COLOR ) {
00210     cinfo.input_components = 3;   /* # of color components per pixel */
00211     cinfo.in_color_space = JCS_YCbCr; /* colorspace of input image */
00212   } else if(getCurrentSourceFormat()==SRC_GRAYSCALE) {
00213     cinfo.input_components = 1;   /* # of color components per pixel */
00214     cinfo.in_color_space = JCS_GRAYSCALE; /* colorspace of input image */
00215   } else {
00216     serr->printf("%s %s Compression failed - unsuitable or unknown mode/generator pair",getClassName().c_str(),getName().c_str());
00217     jpeg_destroy_compress(&cinfo);
00218     return;
00219   }
00220 
00221   // parameter setup
00222   jpeg_set_defaults(&cinfo);
00223   unsigned int qual=(quality==-1U?config->vision.rawcam_compress_quality:quality);
00224   jpeg_set_quality(&cinfo, qual, false); /* limit to baseline-JPEG values */
00225   cinfo.dct_method=config->vision.jpeg_dct_method;
00226   if(cinfo.in_color_space==JCS_GRAYSCALE && src->getIncrement(layer)!=1) {
00227     //special case, need to remove interleaved channels as we compress (single channel, grayscale)
00228     jpeg_start_compress(&cinfo, TRUE);
00229     unsigned int row_stride = src->getStride(layer);  /* JSAMPLEs per row in image_buffer */
00230     JSAMPROW row_pointer[1] = { new JSAMPLE[src->getWidth(layer)] };
00231     unsigned char * curpos=src->getImage(layer,chan);
00232     const unsigned int inc=src->getIncrement(layer);
00233     while (cinfo.next_scanline < cinfo.image_height) {
00234       for(unsigned int x=0; x<src->getWidth(layer); x++)
00235         row_pointer[0][x] = curpos[x*inc];
00236       jpeg_write_scanlines(&cinfo, row_pointer, 1);
00237       curpos+=row_stride;
00238     }
00239     jpeg_finish_compress(&cinfo);
00240     
00241   } else  {
00242     if(cinfo.in_color_space==JCS_YCbCr) {
00243       unsigned int ysamp=1;
00244       unsigned int uvsamp=1;
00245       const unsigned int maxsamp=2;  // according to jpeg docs, this should be able to go up to 4, but I get error: "Sampling factors too large for interleaved scan"
00246       if(config->vision.rawcam_y_skip>config->vision.rawcam_uv_skip) {
00247         uvsamp=config->vision.rawcam_y_skip-config->vision.rawcam_uv_skip+1;
00248         if(uvsamp>maxsamp)
00249           uvsamp=maxsamp;
00250       } else {
00251         ysamp=config->vision.rawcam_uv_skip-config->vision.rawcam_y_skip+1;
00252         if(ysamp>maxsamp)
00253           ysamp=maxsamp;
00254       }
00255       cinfo.comp_info[0].h_samp_factor=ysamp;
00256       cinfo.comp_info[0].v_samp_factor=ysamp;
00257       cinfo.comp_info[1].h_samp_factor=uvsamp;
00258       cinfo.comp_info[1].v_samp_factor=uvsamp;
00259       cinfo.comp_info[2].h_samp_factor=uvsamp;
00260       cinfo.comp_info[2].v_samp_factor=uvsamp;
00261     }
00262 
00263     // compression
00264     jpeg_start_compress(&cinfo, TRUE);
00265     unsigned int row_stride = src->getStride(layer);  /* JSAMPLEs per row in image_buffer */
00266     JSAMPROW row_pointer[1] = { const_cast<JSAMPROW>(src->getImage(layer,chan)) };
00267     while (cinfo.next_scanline < cinfo.image_height) {
00268       jpeg_write_scanlines(&cinfo, row_pointer, 1);
00269       row_pointer[0]+=row_stride;
00270     }
00271     jpeg_finish_compress(&cinfo);
00272   }
00273 
00274   // results
00275   bytesUsed[layer][chan]=jpeg_mem_size(&cinfo);
00276   imageValids[layer][chan]=true;
00277 } catch(const std::exception& ex) {
00278   std::cerr << "Exception while compressing JPEG: " << ex.what() << std::endl; //really, can only be bad_alloc
00279   std::cerr << "layer==" << layer << " channel==" << chan << " image==" << (void*)images[layer][chan] << std::endl;
00280   std::cerr << "width==" << widths[layer] << " height==" << heights[layer] << std::endl;
00281   std::cerr << "row_stride==" << src->getStride(layer) << " next_scanline==" << (void*)cinfo.next_scanline << " image_height==" << cinfo.image_height << std::endl;
00282   jpeg_destroy_compress(&cinfo);
00283 }
00284 }
00285 
00286 void
00287 JPEGGenerator::destruct() {
00288   FilterBankGenerator::destruct();
00289   for(unsigned int res=0; res<numLayers; res++)
00290     delete [] bytesUsed[res];
00291   delete [] bytesUsed;
00292   bytesUsed=NULL;
00293 }
00294 
00295 /*! @file
00296  * @brief Implements JPEGGenerator, which generates FilterBankEvents containing JPEG compressed images
00297  * @author ejt (Creator)
00298  *
00299  * $Author: ejt $
00300  * $Name: tekkotsu-2_4_1 $
00301  * $Revision: 1.14 $
00302  * $State: Exp $
00303  * $Date: 2005/08/16 18:08:51 $
00304  */
00305 

Tekkotsu v2.4.1
Generated Tue Aug 16 16:32:47 2005 by Doxygen 1.4.4