Homepage Demos Overview Downloads Tutorials 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 <write_jpeg.h>
00008 #include "Shared/Config.h"
00009 #include "Shared/WorldState.h"
00010 
00011 #include <jpeg_mem_dest.h>
00012 
00013 
00014 #include "Shared/debuget.h"
00015 
00016 JPEGGenerator::JPEGGenerator(EventBase::EventGeneratorID_t gid, unsigned int sid, unsigned int mysid)
00017   : FilterBankGenerator("JPEGGenerator",0,0,gid,sid,EventBase::visJPEGEGID,mysid), src(NULL), srcMode(SRC_AUTO), curMode(SRC_AUTO), bytesUsed(NULL), cinfo(), jerr(), quality(-1U)
00018 {
00019   setNumImages(numLayers,numChannels);
00020 
00021   // We set the err object before we create the compress...  the idea
00022   // is if the creation fails, we can still get the error as to why it
00023   // failed.
00024   cinfo.err = jpeg_std_error(&jerr);
00025   jpeg_create_compress(&cinfo);
00026 }
00027 
00028 JPEGGenerator::JPEGGenerator(EventBase::EventGeneratorID_t gid, unsigned int sid, unsigned int mysid, src_mode_t mode)
00029   : FilterBankGenerator("JPEGGenerator",0,0,gid,sid,EventBase::visJPEGEGID,mysid), src(NULL), srcMode(mode), curMode(SRC_AUTO), bytesUsed(NULL), cinfo(), jerr(), quality(-1U)
00030 {
00031   setNumImages(numLayers,numChannels);
00032 
00033   // We set the err object before we create the compress...  the idea
00034   // is if the creation fails, we can still get the error as to why it
00035   // failed.
00036   cinfo.err = jpeg_std_error(&jerr);
00037   jpeg_create_compress(&cinfo);
00038 }
00039 
00040 JPEGGenerator::~JPEGGenerator() {
00041   freeCaches();
00042   destruct();
00043   jpeg_destroy_compress(&cinfo);
00044 }
00045 
00046 
00047 /*! The const casts in this function are regretable but necessary
00048  *  since the corresponding OPEN-R functions require mutable
00049  *  arguments, even though they shouldn't be modifying the data
00050  */
00051 void
00052 JPEGGenerator::processEvent(const EventBase& event) {
00053   const FilterBankEvent& fbkevent=dynamic_cast<const FilterBankEvent& >(event);
00054   src=fbkevent.getSource();
00055   frameNumber=src->getFrameNumber();
00056   if(getSourceMode()==SRC_AUTO) { //if not auto, curMode was already set when srcMode was set
00057     if(dynamic_cast<const InterleavedYUVGenerator*>(src)!=NULL)
00058       curMode=SRC_COLOR;
00059     else
00060       curMode=SRC_GRAYSCALE;
00061   }
00062   if(src->getNumLayers()!=numLayers || src->getNumChannels()!=numChannels)
00063     setNumImages(src->getNumLayers(),src->getNumChannels());
00064   if(src->getWidth(numLayers-1)!=getWidth(numLayers-1)) {
00065     ASSERT(widths[numLayers-1]==0,"Strange, the image width changed after initial setting" << widths[numLayers-1]);
00066     setDimensions();
00067   }
00068 
00069   invalidateCaches();
00070   framesProcessed++;
00071   erouter->postEvent(new FilterBankEvent(this,getGeneratorID(),getSourceID()));
00072 }
00073 
00074 unsigned int
00075 JPEGGenerator::getBinSize() const {
00076   unsigned int used=FilterBankGenerator::getBinSize();
00077   used+=strlen("JPEGColor")+LoadSave::stringpad;
00078   if(bytesUsed[selectedSaveLayer][selectedSaveChannel]!=0)
00079     used+=bytesUsed[selectedSaveLayer][selectedSaveChannel];
00080   else
00081     used+=widths[selectedSaveLayer]*heights[selectedSaveLayer]*3+JPEG_HEADER_PAD;
00082   return used;
00083 }
00084 
00085 unsigned int
00086 JPEGGenerator::LoadBuffer(const char buf[], unsigned int len) {
00087   unsigned int origlen=len;
00088   unsigned int used;
00089   std::string tmp;
00090   if(0==(used=FilterBankGenerator::LoadBuffer(buf,len))) return 0;
00091   len-=used; buf+=used;
00092   if(0==(used=decode(tmp,buf,len))) return 0;
00093   len-=used; buf+=used;
00094   if(tmp!="JPEGColor" && tmp!="JPEGGray") {
00095     serr->printf("Unhandled image type for JPEGGenerator: %s",tmp.c_str());
00096     return 0;
00097   } else {
00098     if(tmp=="JPEGColor" && getCurrentSourceFormat()==SRC_GRAYSCALE)
00099       serr->printf("Warning: loading grayscale into color image");
00100     if(tmp=="JPEGGrayscale" && getCurrentSourceFormat()==SRC_COLOR)
00101       serr->printf("Warning: loading color into grayscale image");
00102     unsigned int tmpL;
00103     if(0==(used=decode(tmpL,buf,len))) return 0;
00104     len-=used; buf+=used;
00105     if(tmpL>len)
00106       return 0;
00107     if(images[selectedSaveLayer][selectedSaveChannel]!=NULL)
00108       delete [] images[selectedSaveLayer][selectedSaveChannel];
00109     images[selectedSaveLayer][selectedSaveChannel]=createImageCache(selectedSaveLayer,selectedSaveChannel);
00110     used=bytesUsed[selectedSaveLayer][selectedSaveChannel]=tmpL;
00111     unsigned char* img=getImage(selectedSaveLayer,selectedSaveChannel);
00112     if(img==NULL)
00113       return 0;
00114     memcpy(img,buf,used);
00115     len-=used; buf+=used;
00116     imageValids[selectedSaveLayer][selectedSaveChannel]=true;
00117     return origlen-len; 
00118   }
00119 }
00120 
00121 unsigned int
00122 JPEGGenerator::SaveBuffer(char buf[], unsigned int len) const {
00123   unsigned int origlen=len;
00124   unsigned int used;
00125   if(0==(used=FilterBankGenerator::SaveBuffer(buf,len))) return 0;
00126   len-=used; buf+=used;
00127 
00128   char * type;
00129   if(getCurrentSourceFormat()==SRC_COLOR)
00130     type="JPEGColor";
00131   else if(getCurrentSourceFormat()==SRC_GRAYSCALE)
00132     type="JPEGGrayscale";
00133   else {
00134     serr->printf("SaveBuffer failed - unsuitable or unknown mode/generator pair");
00135     return 0;
00136   }
00137   if(0==(used=encode(type,buf,len))) return 0;
00138   len-=used; buf+=used;
00139   
00140   unsigned char* img=getImage(selectedSaveLayer,selectedSaveChannel);
00141   if(img==NULL)
00142     return 0;
00143   if(0==(used=encode(bytesUsed[selectedSaveLayer][selectedSaveChannel],buf,len))) return 0;
00144   len-=used; buf+=used;
00145   used=bytesUsed[selectedSaveLayer][selectedSaveChannel];
00146   if(used>len)
00147     return 0;
00148   memcpy(buf,img,used);
00149   len-=used;
00150   return origlen-len;
00151 }
00152 
00153 void
00154 JPEGGenerator::setDimensions() {
00155   for(unsigned int i=0; i<numLayers; i++) {
00156     widths[i]=src->getWidth(i);
00157     heights[i]=src->getHeight(i);
00158     strides[i]=skips[i]=0;
00159   } 
00160 }
00161 
00162 void
00163 JPEGGenerator::setNumImages(unsigned int nLayers, unsigned int nChannels) {
00164   FilterBankGenerator::setNumImages(nLayers,nChannels);
00165   bytesUsed=new unsigned int*[numLayers];
00166   for(unsigned int res=0; res<numLayers; res++) {
00167     increments[res]=3;
00168     bytesUsed[res]=new unsigned int[numChannels];
00169     for(unsigned int i=0; i<numChannels; i++)
00170       bytesUsed[res][i]=0;
00171   }
00172 }
00173 
00174 unsigned char *
00175 JPEGGenerator::createImageCache(unsigned int layer, unsigned int /*chan*/) const {
00176   return new unsigned char[widths[layer]*heights[layer]*3+JPEG_HEADER_PAD];
00177 }
00178 
00179 /*! This function is taken pretty directly from the write_jpeg_mem()
00180  *  function from Sony's W3AIBO sample code.
00181  *
00182  *  I have adapted it for this object, and added the ability to
00183  *  process greyscale images as well as color.
00184  */
00185 void
00186 JPEGGenerator::calcImage(unsigned int layer, unsigned int chan) const {
00187   PROFSECTION("JPEGGenerator::calcImage(...)",state->mainProfile);
00188 
00189   //pass the destination buffer and buffer size here
00190   jpeg_mem_dest(&cinfo, images[layer][chan], widths[layer]*heights[layer]*3+JPEG_HEADER_PAD);
00191 
00192   // mode setup
00193   cinfo.image_width = widths[layer];
00194   cinfo.image_height = heights[layer];
00195   if(getCurrentSourceFormat()==SRC_COLOR ) {
00196     cinfo.input_components = 3;   /* # of color components per pixel */
00197     cinfo.in_color_space = JCS_YCbCr; /* colorspace of input image */
00198   } else if(getCurrentSourceFormat()==SRC_GRAYSCALE) {
00199     cinfo.input_components = 1;   /* # of color components per pixel */
00200     cinfo.in_color_space = JCS_GRAYSCALE; /* colorspace of input image */
00201   } else {
00202     serr->printf("Compression failed - unsuitable or unknown mode/generator pair");
00203     jpeg_destroy_compress(&cinfo);
00204     return;
00205   }
00206 
00207   // parameter setup
00208   jpeg_set_defaults(&cinfo);
00209   unsigned int qual=(quality==-1U?config->vision.rawcam_compress_quality:quality);
00210   jpeg_set_quality(&cinfo, qual, false); /* limit to baseline-JPEG values */
00211   cinfo.dct_method=config->vision.jpeg_dct_method;
00212   if(cinfo.in_color_space==JCS_YCbCr) {
00213     unsigned int ysamp=1;
00214     unsigned int uvsamp=1;
00215     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"
00216     if(config->vision.rawcam_y_skip>config->vision.rawcam_uv_skip) {
00217       uvsamp=config->vision.rawcam_y_skip-config->vision.rawcam_uv_skip+1;
00218       if(uvsamp>maxsamp)
00219         uvsamp=maxsamp;
00220     } else {
00221       ysamp=config->vision.rawcam_uv_skip-config->vision.rawcam_y_skip+1;
00222       if(ysamp>maxsamp)
00223         ysamp=maxsamp;
00224     }
00225     cinfo.comp_info[0].h_samp_factor=ysamp;
00226     cinfo.comp_info[0].v_samp_factor=ysamp;
00227     cinfo.comp_info[1].h_samp_factor=uvsamp;
00228     cinfo.comp_info[1].v_samp_factor=uvsamp;
00229     cinfo.comp_info[2].h_samp_factor=uvsamp;
00230     cinfo.comp_info[2].v_samp_factor=uvsamp;
00231   }
00232 
00233   // compression
00234   jpeg_start_compress(&cinfo, TRUE);
00235   unsigned int row_stride = src->getStride(layer);  /* JSAMPLEs per row in image_buffer */
00236   JSAMPROW row_pointer[1] = { const_cast<JSAMPROW>(src->getImage(layer,chan)) };
00237   while (cinfo.next_scanline < cinfo.image_height) {
00238     jpeg_write_scanlines(&cinfo, row_pointer, 1);
00239     row_pointer[0]+=row_stride;
00240   }
00241   jpeg_finish_compress(&cinfo);
00242 
00243   // results
00244   bytesUsed[layer][chan]=jpeg_mem_size(&cinfo);
00245   imageValids[layer][chan]=true;
00246 }
00247 
00248 void
00249 JPEGGenerator::destruct() {
00250   FilterBankGenerator::destruct();
00251   for(unsigned int res=0; res<numLayers; res++)
00252     delete [] bytesUsed[res];
00253   delete [] bytesUsed;
00254   bytesUsed=NULL;
00255 }
00256 
00257 /*! @file
00258  * @brief Implements JPEGGenerator, which generates FilterBankEvents containing JPEG compressed images
00259  * @author ejt (Creator)
00260  *
00261  * $Author: ejt $
00262  * $Name: tekkotsu-2_0 $
00263  * $Revision: 1.7 $
00264  * $State: Exp $
00265  * $Date: 2004/01/19 07:56:41 $
00266  */
00267 

Tekkotsu v2.0
Generated Wed Jan 21 03:20:28 2004 by Doxygen 1.3.4