From 7c2a39cd1384bb48ef108a324c53ed1149930f75 Mon Sep 17 00:00:00 2001 From: DRC Date: Thu, 3 Nov 2011 18:51:00 +0000 Subject: [PATCH] Move JPEG decoding into a standalone class (these should have been checked in with r4757. Oops.) git-svn-id: svn://svn.code.sf.net/p/tigervnc/code/trunk@4758 3789f03b-4d11-0410-bbf8-ca57d06f2519 --- common/rfb/JpegDecompressor.cxx | 233 ++++++++++++++++++++++++++++++++ common/rfb/JpegDecompressor.h | 60 ++++++++ 2 files changed, 293 insertions(+) create mode 100644 common/rfb/JpegDecompressor.cxx create mode 100644 common/rfb/JpegDecompressor.h diff --git a/common/rfb/JpegDecompressor.cxx b/common/rfb/JpegDecompressor.cxx new file mode 100644 index 00000000..9cd891a5 --- /dev/null +++ b/common/rfb/JpegDecompressor.cxx @@ -0,0 +1,233 @@ +/* Copyright (C) 2000-2003 Constantin Kaplinsky. All Rights Reserved. + * Copyright (C) 2004-2005 Cendio AB. All rights reserved. + * Copyright (C) 2011 D. R. Commander. All Rights Reserved. + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +#include +#include +#include +#include + +#include +extern "C" { +#include +} +#include +#include + +using namespace rfb; + + +// +// Error manager implmentation for the JPEG library +// + +struct JPEG_ERROR_MGR { + struct jpeg_error_mgr pub; + jmp_buf jmpBuffer; + char lastError[JMSG_LENGTH_MAX]; +}; + +static void +JpegErrorExit(j_common_ptr dinfo) +{ + JPEG_ERROR_MGR *err = (JPEG_ERROR_MGR *)dinfo->err; + + (*dinfo->err->output_message)(dinfo); + longjmp(err->jmpBuffer, 1); +} + +static void +JpegOutputMessage(j_common_ptr dinfo) +{ + JPEG_ERROR_MGR *err = (JPEG_ERROR_MGR *)dinfo->err; + + (*dinfo->err->format_message)(dinfo, err->lastError); +} + + +// +// Source manager implementation for the JPEG library. +// + +struct JPEG_SRC_MGR { + struct jpeg_source_mgr pub; + JpegDecompressor *instance; +}; + +static void +JpegNoOp(j_decompress_ptr dinfo) +{ +} + +static boolean +JpegFillInputBuffer(j_decompress_ptr dinfo) +{ + ERREXIT(dinfo, JERR_BUFFER_SIZE); + return TRUE; +} + +static void +JpegSkipInputData(j_decompress_ptr dinfo, long num_bytes) +{ + JPEG_SRC_MGR *src = (JPEG_SRC_MGR *)dinfo->src; + + if (num_bytes < 0 || (size_t)num_bytes > src->pub.bytes_in_buffer) { + ERREXIT(dinfo, JERR_BUFFER_SIZE); + } else { + src->pub.next_input_byte += (size_t) num_bytes; + src->pub.bytes_in_buffer -= (size_t) num_bytes; + } +} + +JpegDecompressor::JpegDecompressor(void) +{ + dinfo = new jpeg_decompress_struct; + + err = new struct JPEG_ERROR_MGR; + dinfo->err = jpeg_std_error(&err->pub); + snprintf(err->lastError, JMSG_LENGTH_MAX, "No error"); + err->pub.error_exit = JpegErrorExit; + err->pub.output_message = JpegOutputMessage; + + if(setjmp(err->jmpBuffer)) { + // this will execute if libjpeg has an error + throw rdr::Exception(err->lastError); + } + + jpeg_create_decompress(dinfo); + + src = new struct JPEG_SRC_MGR; + src->pub.init_source = JpegNoOp; + src->pub.fill_input_buffer = JpegFillInputBuffer; + src->pub.skip_input_data = JpegSkipInputData; + src->pub.resync_to_restart = jpeg_resync_to_restart; + src->pub.term_source = JpegNoOp; + src->instance = this; + dinfo->src = (struct jpeg_source_mgr *)src; +} + +JpegDecompressor::~JpegDecompressor(void) +{ + if(setjmp(err->jmpBuffer)) { + // this will execute if libjpeg has an error + return; + } + + jpeg_destroy_decompress(dinfo); + + delete err; + delete src; + + delete dinfo; +} + +void JpegDecompressor::decompress(const rdr::U8 *jpegBuf, int jpegBufLen, + rdr::U8 *buf, int pitch, const Rect& r, const PixelFormat& pf) +{ + int w = r.width(); + int h = r.height(); + int pixelsize; + int dstBufPitch; + rdr::U8 *dstBuf = NULL; + bool dstBufIsTemp = false; + JSAMPROW *rowPointer = NULL; + + if(setjmp(err->jmpBuffer)) { + // this will execute if libjpeg has an error + jpeg_abort_decompress(dinfo); + if (dstBufIsTemp && dstBuf) delete[] dstBuf; + if (rowPointer) delete[] rowPointer; + throw rdr::Exception(err->lastError); + } + + src->pub.next_input_byte = jpegBuf; + src->pub.bytes_in_buffer = jpegBufLen; + + jpeg_read_header(dinfo, TRUE); + dinfo->out_color_space = JCS_RGB; + pixelsize = 3; + if (pitch == 0) pitch = w * pf.bpp / 8; + dstBufPitch = pitch; + +#ifdef JCS_EXTENSIONS + // Try to have libjpeg output directly to our native format + if (pf.is888()) { + int redShift, greenShift, blueShift; + + if(pf.bigEndian) { + redShift = 24 - pf.redShift; + greenShift = 24 - pf.greenShift; + blueShift = 24 - pf.blueShift; + } else { + redShift = pf.redShift; + greenShift = pf.greenShift; + blueShift = pf.blueShift; + } + + // libjpeg can only handle some "standard" formats + if(redShift == 0 && greenShift == 8 && blueShift == 16) + dinfo->out_color_space = JCS_EXT_RGBX; + if(redShift == 16 && greenShift == 8 && blueShift == 0) + dinfo->out_color_space = JCS_EXT_BGRX; + if(redShift == 24 && greenShift == 16 && blueShift == 8) + dinfo->out_color_space = JCS_EXT_XBGR; + if(redShift == 8 && greenShift == 16 && blueShift == 24) + dinfo->out_color_space = JCS_EXT_XRGB; + + if (dinfo->out_color_space != JCS_RGB) { + dstBuf = (rdr::U8 *)buf; + pixelsize = 4; + } + } +#endif + + if (dinfo->out_color_space == JCS_RGB) { + dstBuf = new rdr::U8[w * h * pixelsize]; + dstBufIsTemp = true; + dstBufPitch = w * pixelsize; + } + + rowPointer = new JSAMPROW[h]; + for (int dy = 0; dy < h; dy++) + rowPointer[dy] = (JSAMPROW)(&dstBuf[dy * dstBufPitch]); + + jpeg_start_decompress(dinfo); + + if (dinfo->output_width != (unsigned)r.width() + || dinfo->output_height != (unsigned)r.height() + || dinfo->output_components != pixelsize) { + jpeg_abort_decompress(dinfo); + if (dstBufIsTemp && dstBuf) delete[] dstBuf; + if (rowPointer) delete[] rowPointer; + throw rdr::Exception("Tight Decoding: Wrong JPEG data received.\n"); + } + + while (dinfo->output_scanline < dinfo->output_height) { + jpeg_read_scanlines(dinfo, &rowPointer[dinfo->output_scanline], + dinfo->output_height - dinfo->output_scanline); + } + + if (dinfo->out_color_space == JCS_RGB) + pf.bufferFromRGB((rdr::U8*)buf, dstBuf, w, pitch, h); + + jpeg_finish_decompress(dinfo); + + if (dstBufIsTemp) delete [] dstBuf; + delete[] rowPointer; +} diff --git a/common/rfb/JpegDecompressor.h b/common/rfb/JpegDecompressor.h new file mode 100644 index 00000000..ed367786 --- /dev/null +++ b/common/rfb/JpegDecompressor.h @@ -0,0 +1,60 @@ +/* Copyright (C) 2000-2003 Constantin Kaplinsky. All Rights Reserved. + * Copyright (C) 2004-2005 Cendio AB. All rights reserved. + * Copyright (C) 2011 D. R. Commander. All Rights Reserved. + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +// +// JpegDecompressor decompresses a JPEG image into RGB output +// an underlying MemOutStream +// + +#ifndef __RFB_JPEGDECOMPRESSOR_H__ +#define __RFB_JPEGDECOMPRESSOR_H__ + +#include +#include + +struct jpeg_decompress_struct; + +struct JPEG_ERROR_MGR; +struct JPEG_SRC_MGR; + +namespace rfb { + + class JpegDecompressor { + + public: + + JpegDecompressor(void); + virtual ~JpegDecompressor(); + + void decompress(const rdr::U8 *, int, rdr::U8 *, int, const Rect&, + const PixelFormat&); + + private: + + struct jpeg_decompress_struct *dinfo; + + struct JPEG_ERROR_MGR *err; + struct JPEG_SRC_MGR *src; + + }; + +} // end of namespace rfb + +#endif -- 2.39.5