fuse_image_content.cpp

00001
00002 /***************************************************************************
00003  *  fuse_image_content.cpp - FUSE image content encapsulation
00004  *
00005  *  Created: Thu Nov 15 15:55:51 2007
00006  *  Copyright  2005-2007  Tim Niemueller [www.niemueller.de]
00007  *
00008  ****************************************************************************/
00009
00010 /*  This program is free software; you can redistribute it and/or modify
00011  *  it under the terms of the GNU General Public License as published by
00012  *  the Free Software Foundation; either version 2 of the License, or
00013  *  (at your option) any later version. A runtime exception applies to
00014  *  this software (see LICENSE.GPL_WRE file mentioned below for details).
00015  *
00016  *  This program is distributed in the hope that it will be useful,
00017  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  *  GNU Library General Public License for more details.
00020  *
00021  *  Read the full text in the LICENSE.GPL_WRE file in the doc directory.
00022  */
00023
00024 #include <fvutils/net/fuse_image_content.h>
00025 #include <fvutils/ipc/shm_image.h>
00026 #include <fvutils/color/conversions.h>
00027 #include <fvutils/compression/jpeg_decompressor.h>
00028
00029 #include <core/exceptions/system.h>
00030 #include <core/exceptions/software.h>
00031
00032 #include <cstdlib>
00033 #include <netinet/in.h>
00034 #include <cstring>
00035 
00036 /** @class FuseImageContent <fvutils/net/fuse_image_content.h>
00037  * FUSE image content.
00038  * @ingroup FUSE
00039  * @ingroup FireVision
00040  * @author Tim Niemueller
00041  */
00042 
00043 /** Constructor.
00044  * @param type message type
00045  * @param payload payload
00046  * @param payload_size size of payload
00047  */
00048 FuseImageContent::FuseImageContent(uint32_t type,
00049                                    void *payload, size_t payload_size)
00050 {
00051   if ( type != FUSE_MT_IMAGE ) {
00052     throw fawkes::TypeMismatchException("Type %u != FUSE_MT_IMAGE (%u)", type, FUSE_MT_IMAGE);
00053   }
00054
00055   _payload_size = payload_size;
00056   _payload      = payload;
00057
00058   __header = (FUSE_image_message_header_t *)_payload;
00059   __buffer = (unsigned char *)_payload + sizeof(FUSE_image_message_header_t);
00060   __capture_time = new fawkes::Time(ntohl(__header->capture_time_sec),
00061                                     ntohl(__header->capture_time_usec));
00062
00063   __buffer_size = ntohl(__header->buffer_size);
00064 }
00065
00066 
00067 /** Constructor.
00068  * Copies data from given buffer.
00069  * @param b shared memory image buffer to copy image from
00070  */
00071 FuseImageContent::FuseImageContent(SharedMemoryImageBuffer *b)
00072 {
00073   __buffer_size  = colorspace_buffer_size(b->colorspace(), b->width(), b->height());
00074   _payload_size  = __buffer_size + sizeof(FUSE_image_message_header_t);
00075   _payload = malloc(_payload_size);
00076
00077   if ( _payload == NULL ) {
00078     throw fawkes::OutOfMemoryException("Cannot allocate FuseImageContent buffer");
00079   }
00080
00081   __header = (FUSE_image_message_header_t *)_payload;
00082   __buffer = (unsigned char *)_payload + sizeof(FUSE_image_message_header_t);
00083
00084   strncpy(__header->image_id, b->image_id(), IMAGE_ID_MAX_LENGTH);
00085   __header->format = FUSE_IF_RAW;
00086   __header->colorspace = htons(b->colorspace());
00087   __header->reserved = 0;
00088   __header->width  = htonl(b->width());
00089   __header->height = htonl(b->height());
00090   __header->buffer_size = htonl(__buffer_size);
00091
00092   long int cts = 0, ctus = 0;
00093   b->capture_time(&cts, &ctus);
00094   __header->capture_time_sec = htonl(cts);
00095   __header->capture_time_usec = htonl(ctus);
00096
00097   __capture_time = NULL;
00098
00099   b->lock_for_read();
00100   memcpy(__buffer, b->buffer(), __buffer_size);
00101   b->unlock();
00102 }
00103
00104 
00105 /** Constructor.
00106  * Copies data from given buffer.
00107  * @param image_format image format
00108  * @param image_id image ID
00109  * @param buffer image buffer, encoded according to image_format
00110  * @param buffer_size size of buffer in bytes
00111  * @param colorspace color space
00112  * @param width width of image in pixels
00113  * @param height height of image in pixels
00114  * @param capture_time_sec optional seconds part of the capture time
00115  * @param capture_time_usec optional microseconds part of the capture time
00116  */
00117 FuseImageContent::FuseImageContent(FUSE_image_format_t image_format, const char *image_id,
00118                                    unsigned char *buffer, size_t buffer_size,
00119                                    colorspace_t colorspace,
00120                                    unsigned int width, unsigned int height,
00121                                    long int capture_time_sec,
00122                                    long int capture_time_usec)
00123 {
00124   __buffer_size  = buffer_size;
00125   _payload_size  = __buffer_size + sizeof(FUSE_image_message_header_t);
00126   _payload = malloc(_payload_size);
00127
00128   if ( _payload == NULL ) {
00129     throw fawkes::OutOfMemoryException("Cannot allocate FuseImageContent buffer");
00130   }
00131
00132   __header = (FUSE_image_message_header_t *)_payload;
00133   __buffer = (unsigned char *)_payload + sizeof(FUSE_image_message_header_t);
00134
00135   strncpy(__header->image_id, image_id, IMAGE_ID_MAX_LENGTH);
00136   __header->format = image_format;
00137   __header->colorspace = htons(colorspace);
00138   __header->reserved = 0;
00139   __header->width  = htonl(width);
00140   __header->height = htonl(height);
00141   __header->buffer_size = htonl(__buffer_size);
00142   __header->capture_time_sec = htonl(capture_time_sec);
00143   __header->capture_time_usec = htonl(capture_time_usec);
00144
00145   __capture_time = NULL;
00146
00147   memcpy(__buffer, buffer, __buffer_size);
00148 }
00149
00150 
00151 /** Destructor. */
00152 FuseImageContent::~FuseImageContent()
00153 {
00154   delete __capture_time;
00155 }
00156 
00157 /** Image buffer.
00158  * @return image buffer
00159  */
00160 unsigned char *
00161 FuseImageContent::buffer() const
00162 {
00163   return __buffer;
00164 }
00165
00166 
00167 /** Get size of buffer.
00168  * @return size of buffer returned by buffer()
00169  */
00170 size_t
00171 FuseImageContent::buffer_size() const
00172 {
00173   return __buffer_size;
00174 }
00175
00176 
00177 /** Get image width.
00178  * @return width of image in pixels
00179  */
00180 unsigned int
00181 FuseImageContent::pixel_width() const
00182 {
00183   return ntohl(__header->width);
00184 }
00185
00186 
00187 /** Get image height.
00188  * @return height of image in pixels
00189  */
00190 unsigned int
00191 FuseImageContent::pixel_height() const
00192 {
00193   return ntohl(__header->height);
00194 }
00195
00196 
00197 /** Get colorspace.
00198  * @return colorspace
00199  */
00200 unsigned int
00201 FuseImageContent::colorspace() const
00202 {
00203   return ntohs(__header->colorspace);
00204 }
00205
00206 
00207 /** Get image format.
00208  * @return format
00209  */
00210 unsigned int
00211 FuseImageContent::format() const
00212 {
00213   return __header->format;
00214 }
00215
00216 
00217 /** Get capture time.
00218  * @return capture time
00219  */
00220 fawkes::Time *
00221 FuseImageContent::capture_time() const
00222 {
00223   if ( ! __capture_time ) {
00224     __capture_time = new fawkes::Time(ntohl(__header->capture_time_sec),
00225                                       ntohl(__header->capture_time_usec));
00226   }
00227   return __capture_time;
00228 }
00229
00230 void
00231 FuseImageContent::serialize()
00232 {
00233   // Nothing to do here
00234 }
00235
00236 
00237 /** Decompress image data.
00238  * This is a utility method which can be used on clients to decompress compressed
00239  * image payload. Since every time a new decompressor is created and deleted
00240  * this method can be slower compared to decompressing the data directly in your
00241  * application so use with care.
00242  * @param yuv422_planar_buffer an already allocated buffer where the decompressed image
00243  * will be stored.
00244  * @param buffer_size size of yuv422_planar_buffer in bytes. Must be big enough to store
00245  * a YUV422_PLANAR image of the image dimensions of the compressed data.
00246  */
00247 void
00248 FuseImageContent::decompress(unsigned char *yuv422_planar_buffer, size_t buffer_size)
00249 {
00250   if ( buffer_size < colorspace_buffer_size(YUV422_PLANAR, ntohs(__header->width),
00251                                             ntohs(__header->height)) ) {
00252     throw fawkes::IllegalArgumentException("Supplied buffer is too small\n");
00253   }
00254   if ( __header->format != FUSE_IF_JPEG ) {
00255     JpegImageDecompressor *decompressor = new JpegImageDecompressor();
00256     decompressor->set_compressed_buffer(__buffer, __buffer_size);
00257     decompressor->set_decompressed_buffer(yuv422_planar_buffer, buffer_size);
00258     decompressor->decompress();
00259     delete decompressor;
00260   } else {
00261     convert((colorspace_t)ntohs(__header->colorspace), YUV422_PLANAR,
00262             __buffer, yuv422_planar_buffer,
00263             ntohs(__header->width), ntohs(__header->height));
00264   }
00265 }