Tekkotsu 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/Profiler.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     FilterBankEvent fbkev(this,getGeneratorID(),getSourceID(),EventBase::activateETID);
00080     erouter->postEvent(fbkev);
00081     fbkev.setTypeID(EventBase::statusETID);
00082     erouter->postEvent(fbkev);
00083     fbkev.setTypeID(EventBase::deactivateETID);
00084     erouter->postEvent(fbkev);
00085   }
00086 }
00087 
00088 unsigned int
00089 JPEGGenerator::getBinSize() const {
00090   unsigned int used=FilterBankGenerator::getBinSize();
00091   char * type;
00092   if(getCurrentSourceFormat()==SRC_COLOR)
00093     type="JPEGColor";
00094   else if(getCurrentSourceFormat()==SRC_GRAYSCALE)
00095     type="JPEGGrayscale";
00096   else {
00097     serr->printf("getBinSize failed - unsuitable or unknown mode/generator pair");
00098     return 0;
00099   }
00100   used+=strlen(type)+LoadSave::stringpad;
00101   if(bytesUsed[selectedSaveLayer][selectedSaveChannel]!=0)
00102     used+=bytesUsed[selectedSaveLayer][selectedSaveChannel];
00103   else
00104     used+=widths[selectedSaveLayer]*heights[selectedSaveLayer]*3+JPEG_HEADER_PAD;
00105   return used;
00106 }
00107 
00108 unsigned int
00109 JPEGGenerator::loadBuffer(const char buf[], unsigned int len) {
00110   unsigned int origlen=len;
00111   if(!checkInc(FilterBankGenerator::loadBuffer(buf,len),buf,len)) return 0;
00112   std::string tmp;
00113   if(!decodeInc(tmp,buf,len)) return 0;
00114   if(tmp!="JPEGColor" && tmp!="JPEGGrayscale") {
00115     serr->printf("Unhandled image type for JPEGGenerator: %s",tmp.c_str());
00116     return 0;
00117   } else {
00118     if(tmp=="JPEGColor" && getCurrentSourceFormat()==SRC_GRAYSCALE)
00119       serr->printf("Warning: loading grayscale into color image");
00120     if(tmp=="JPEGGrayscale" && getCurrentSourceFormat()==SRC_COLOR)
00121       serr->printf("Warning: loading color into grayscale image");
00122     unsigned int tmpL;
00123     if(!decodeInc(tmpL,buf,len)) return 0;
00124     if(tmpL>len)
00125       return 0;
00126     if(images[selectedSaveLayer][selectedSaveChannel]!=NULL)
00127       delete [] images[selectedSaveLayer][selectedSaveChannel];
00128     images[selectedSaveLayer][selectedSaveChannel]=createImageCache(selectedSaveLayer,selectedSaveChannel);
00129     unsigned int used=bytesUsed[selectedSaveLayer][selectedSaveChannel]=tmpL;
00130     unsigned char* img=getImage(selectedSaveLayer,selectedSaveChannel);
00131     if(img==NULL)
00132       return 0;
00133     memcpy(img,buf,used);
00134     len-=used; buf+=used;
00135     imageValids[selectedSaveLayer][selectedSaveChannel]=true;
00136     return origlen-len; 
00137   }
00138 }
00139 
00140 unsigned int
00141 JPEGGenerator::saveBuffer(char buf[], unsigned int len) const {
00142   unsigned int origlen=len;
00143   if(!checkInc(FilterBankGenerator::saveBuffer(buf,len),buf,len)) return 0;
00144 
00145   char * type;
00146   if(getCurrentSourceFormat()==SRC_COLOR)
00147     type="JPEGColor";
00148   else if(getCurrentSourceFormat()==SRC_GRAYSCALE)
00149     type="JPEGGrayscale";
00150   else {
00151     serr->printf("saveBuffer failed - unsuitable or unknown mode/generator pair");
00152     return 0;
00153   }
00154   if(!encodeInc(type,buf,len)) return 0;
00155   
00156   if(images[selectedSaveLayer][selectedSaveChannel]==NULL) {
00157     serr->printf("JPEGGenerator::saveBuffer() failed because selected image is NULL -- call selectSaveImage first to make sure it's up to date\n");
00158     return 0;
00159   }
00160   if(!imageValids[selectedSaveLayer][selectedSaveChannel]) {
00161     serr->printf("JPEGGenerator::saveBuffer() failed because selected image is invalid -- call selectSaveImage first to make sure it's up to date\n");
00162     return 0;
00163   }
00164   unsigned char* img=images[selectedSaveLayer][selectedSaveChannel];
00165   if(img==NULL)
00166     return 0;
00167   if(!encodeInc(bytesUsed[selectedSaveLayer][selectedSaveChannel],buf,len)) return 0;
00168   unsigned int used=bytesUsed[selectedSaveLayer][selectedSaveChannel];
00169   if(used>len)
00170     return 0;
00171   memcpy(buf,img,used);
00172   len-=used;
00173   return origlen-len;
00174 }
00175 
00176 void
00177 JPEGGenerator::setNumImages(unsigned int nLayers, unsigned int nChannels) {
00178   if(nLayers==numLayers && nChannels==numChannels)
00179     return;
00180   FilterBankGenerator::setNumImages(nLayers,nChannels);
00181   for(unsigned int i=0; i<numLayers; i++)
00182     strides[i]=skips[i]=0;
00183   bytesUsed=new unsigned int*[numLayers];
00184   for(unsigned int res=0; res<numLayers; res++) {
00185     increments[res]=3;
00186     bytesUsed[res]=new unsigned int[numChannels];
00187     for(unsigned int i=0; i<numChannels; i++)
00188       bytesUsed[res][i]=0;
00189   }
00190 }
00191 
00192 unsigned char *
00193 JPEGGenerator::createImageCache(unsigned int layer, unsigned int /*chan*/) const {
00194   return new unsigned char[widths[layer]*heights[layer]*3+JPEG_HEADER_PAD];
00195 }
00196 
00197 /*! This function is taken pretty directly from the write_jpeg_mem()
00198  *  function from Sony's W3AIBO sample code.
00199  *
00200  *  I have adapted it for this object, and added the ability to
00201  *  process greyscale images as well as color.
00202  */
00203 void
00204 JPEGGenerator::calcImage(unsigned int layer, unsigned int chan) {
00205   PROFSECTION("JPEGGenerator::calcImage(...)",*mainProfiler);
00206 try {
00207   //pass the destination buffer and buffer size here
00208   jpeg_mem_dest(&cinfo, images[layer][chan], widths[layer]*heights[layer]*3+JPEG_HEADER_PAD);
00209 
00210   // mode setup
00211   cinfo.image_width = widths[layer];
00212   cinfo.image_height = heights[layer];
00213   if(getCurrentSourceFormat()==SRC_COLOR ) {
00214     cinfo.input_components = 3;   /* # of color components per pixel */
00215     cinfo.in_color_space = JCS_YCbCr; /* colorspace of input image */
00216   } else if(getCurrentSourceFormat()==SRC_GRAYSCALE) {
00217     cinfo.input_components = 1;   /* # of color components per pixel */
00218     cinfo.in_color_space = JCS_GRAYSCALE; /* colorspace of input image */
00219   } else {
00220     serr->printf("%s %s Compression failed - unsuitable or unknown mode/generator pair",getClassName().c_str(),getName().c_str());
00221     jpeg_destroy_compress(&cinfo);
00222     return;
00223   }
00224 
00225   // parameter setup
00226   jpeg_set_defaults(&cinfo);
00227   unsigned int qual=(quality==-1U?config->vision.rawcam_compress_quality:quality);
00228   jpeg_set_quality(&cinfo, qual, false); /* limit to baseline-JPEG values */
00229   cinfo.dct_method=config->vision.jpeg_dct_method;
00230   if(cinfo.in_color_space==JCS_GRAYSCALE && src->getIncrement(layer)!=1) {
00231     //special case, need to remove interleaved channels as we compress (single channel, grayscale)
00232     jpeg_start_compress(&cinfo, TRUE);
00233     unsigned int row_stride = src->getStride(layer);  /* JSAMPLEs per row in image_buffer */
00234     JSAMPROW row_pointer[1] = { new JSAMPLE[src->getWidth(layer)] };
00235     unsigned char * curpos=src->getImage(layer,chan);
00236     const unsigned int inc=src->getIncrement(layer);
00237     while (cinfo.next_scanline < cinfo.image_height) {
00238       for(unsigned int x=0; x<src->getWidth(layer); x++)
00239         row_pointer[0][x] = curpos[x*inc];
00240       jpeg_write_scanlines(&cinfo, row_pointer, 1);
00241       curpos+=row_stride;
00242     }
00243     jpeg_finish_compress(&cinfo);
00244     
00245   } else  {
00246     if(cinfo.in_color_space==JCS_YCbCr) {
00247       unsigned int ysamp=1;
00248       unsigned int uvsamp=1;
00249       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"
00250       if(config->vision.rawcam_y_skip>config->vision.rawcam_uv_skip) {
00251         uvsamp=config->vision.rawcam_y_skip-config->vision.rawcam_uv_skip+1;
00252         if(uvsamp>maxsamp)
00253           uvsamp=maxsamp;
00254       } else {
00255         ysamp=config->vision.rawcam_uv_skip-config->vision.rawcam_y_skip+1;
00256         if(ysamp>maxsamp)
00257           ysamp=maxsamp;
00258       }
00259       cinfo.comp_info[0].h_samp_factor=ysamp;
00260       cinfo.comp_info[0].v_samp_factor=ysamp;
00261       cinfo.comp_info[1].h_samp_factor=uvsamp;
00262       cinfo.comp_info[1].v_samp_factor=uvsamp;
00263       cinfo.comp_info[2].h_samp_factor=uvsamp;
00264       cinfo.comp_info[2].v_samp_factor=uvsamp;
00265     }
00266 
00267     // compression
00268     jpeg_start_compress(&cinfo, TRUE);
00269     unsigned int row_stride = src->getStride(layer);  /* JSAMPLEs per row in image_buffer */
00270     JSAMPROW row_pointer[1] = { const_cast<JSAMPROW>(src->getImage(layer,chan)) };
00271     while (cinfo.next_scanline < cinfo.image_height) {
00272       jpeg_write_scanlines(&cinfo, row_pointer, 1);
00273       row_pointer[0]+=row_stride;
00274     }
00275     jpeg_finish_compress(&cinfo);
00276   }
00277 
00278   // results
00279   bytesUsed[layer][chan]=jpeg_mem_size(&cinfo);
00280   imageValids[layer][chan]=true;
00281 } catch(const std::exception& ex) {
00282   std::cerr << "Exception while compressing JPEG: " << ex.what() << std::endl; //really, can only be bad_alloc
00283   std::cerr << "layer==" << layer << " channel==" << chan << " image==" << (void*)images[layer][chan] << std::endl;
00284   std::cerr << "width==" << widths[layer] << " height==" << heights[layer] << std::endl;
00285   std::cerr << "row_stride==" << src->getStride(layer) << " next_scanline==" << reinterpret_cast<void*>(cinfo.next_scanline) << " image_height==" << cinfo.image_height << std::endl;
00286   jpeg_destroy_compress(&cinfo);
00287 }
00288 }
00289 
00290 void
00291 JPEGGenerator::destruct() {
00292   FilterBankGenerator::destruct();
00293   for(unsigned int res=0; res<numLayers; res++)
00294     delete [] bytesUsed[res];
00295   delete [] bytesUsed;
00296   bytesUsed=NULL;
00297 }
00298 
00299 /*! @file
00300  * @brief Implements JPEGGenerator, which generates FilterBankEvents containing JPEG compressed images
00301  * @author ejt (Creator)
00302  *
00303  * $Author: ejt $
00304  * $Name: tekkotsu-3_0 $
00305  * $Revision: 1.19 $
00306  * $State: Exp $
00307  * $Date: 2006/09/11 23:05:20 $
00308  */
00309 

Tekkotsu v3.0
Generated Wed Oct 4 00:03:43 2006 by Doxygen 1.4.7