Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035 #include "wave-jpeg.h"
00036
00037
00038 #include <setjmp.h>
00039 #include <jpeglib.h>
00040
00041 #include "common/wave_ex.h"
00042 #include "nstream/nstream.h"
00043 #include "perf/perf.h"
00044 #include "util/file.h"
00045 #include "util/token_stream.h"
00046
00047
00048
00049 namespace media {
00050
00051
00052
00053
00054 static const int s_bufferSize = 4096;
00055
00056 struct source_context_t {
00057
00058 source_context_t(void) throw() { this->clear(); }
00059 void clear(void) throw() {
00060 pstream = NULL;
00061 }
00062
00063 struct jpeg_source_mgr pub;
00064 std::istream * pstream;
00065 char buffer[s_bufferSize];
00066 };
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077 static void
00078 init_source
00079 (
00080 IN struct jpeg_decompress_struct * pds
00081 )
00082 {
00083 pds = pds;
00084
00085 }
00086
00087
00088 #ifdef WIN32
00089 typedef boolean boolean_t;
00090 #else // WIN32
00091 typedef int boolean_t;
00092 #endif // WIN32
00093
00094 static boolean_t
00095 fill_input_buffer
00096 (
00097 IN struct jpeg_decompress_struct * pds
00098 )
00099 {
00100 ASSERT(pds, "null");
00101 source_context_t * psc = (source_context_t *) pds->src;
00102 ASSERT(psc, "null source object");
00103 ASSERT(psc->pstream, "null stream");
00104
00105
00106
00107
00108 psc->pstream->read(psc->buffer, s_bufferSize);
00109 int nRead = psc->pstream->gcount();
00110
00111
00112
00113
00114 if (nRead <= 0) {
00115 psc->buffer[0] = 0xFF;
00116 psc->buffer[1] = JPEG_EOI;
00117 nRead = 2;
00118 }
00119
00120
00121 psc->pub.next_input_byte = (JOCTET *) psc->buffer;
00122 psc->pub.bytes_in_buffer = nRead;
00123
00124 return TRUE;
00125 }
00126
00127
00128
00129 static void
00130 skip_input_data
00131 (
00132 IN struct jpeg_decompress_struct * pds,
00133 IN long bytes
00134 )
00135 {
00136 ASSERT(pds, "null");
00137 source_context_t * psc = (source_context_t *) pds->src;
00138 ASSERT(psc, "null source");
00139
00140 if (bytes < 1)
00141 return;
00142
00143 while (bytes > (long) psc->pub.bytes_in_buffer) {
00144 bytes -= psc->pub.bytes_in_buffer;
00145 psc->pub.fill_input_buffer(pds);
00146 }
00147
00148 psc->pub.next_input_byte += bytes;
00149 psc->pub.bytes_in_buffer -= bytes;
00150 }
00151
00152
00153
00154 static void
00155 term_source
00156 (
00157 IN struct jpeg_decompress_struct * pds
00158 )
00159 {
00160 pds = pds;
00161
00162 }
00163
00164
00165
00166 static void
00167 setJpegSourceStream
00168 (
00169 IN struct jpeg_decompress_struct& cinfo,
00170 IN std::istream& stream
00171 )
00172 {
00173 ASSERT_THROW(stream.good(), "bad?");
00174
00175
00176
00177
00178 if (!cinfo.src) {
00179 cinfo.src = (struct jpeg_source_mgr *)
00180 (*cinfo.mem->alloc_small)((j_common_ptr) &cinfo,
00181 JPOOL_PERMANENT,
00182 sizeof(source_context_t));
00183 ASSERT(cinfo.src, "out of memory");
00184
00185 source_context_t * psc = (source_context_t *) cinfo.src;
00186 psc->clear();
00187 }
00188
00189
00190 source_context_t * psc = (source_context_t *) cinfo.src;
00191 ASSERT(psc, "null");
00192 psc->pub.init_source = init_source;
00193 psc->pub.fill_input_buffer = fill_input_buffer;
00194 psc->pub.skip_input_data = skip_input_data;
00195 psc->pub.resync_to_restart = jpeg_resync_to_restart;
00196 psc->pub.term_source = term_source;
00197 psc->pub.next_input_byte = (JOCTET *) psc->buffer;
00198 psc->pub.bytes_in_buffer = 0;
00199
00200 psc->pstream = &stream;
00201 }
00202
00203
00204
00205 struct my_error_mgr {
00206 struct jpeg_error_mgr errmgr;
00207 jmp_buf setjmp_buffer;
00208 };
00209
00210
00211
00212 static void
00213 my_error_exit
00214 (
00215 IN j_common_ptr cinfo
00216 )
00217 {
00218 my_error_mgr * err = (my_error_mgr *) cinfo->err;
00219 longjmp(err->setjmp_buffer, 1);
00220 }
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230 void
00231 readJpegFromStream
00232 (
00233 IO std::istream& stream,
00234 OUT image_t& image
00235 )
00236 {
00237 perf::Timer timer("readJpegFromStream");
00238 ASSERT_THROW(stream.good(), "bad?");
00239 image.clear();
00240
00241 struct jpeg_decompress_struct cinfo;
00242 struct my_error_mgr jerr;
00243 JSAMPROW rowptr[1];
00244
00245
00246 cinfo.err = jpeg_std_error(&jerr.errmgr);
00247 jerr.errmgr.error_exit = my_error_exit;
00248 cinfo.err->output_message = NULL;
00249 if (setjmp(jerr.setjmp_buffer)) {
00250 jpeg_destroy_decompress(&cinfo);
00251 image.clear();
00252 WAVE_EX(wex);
00253 wex << "Failed to read jpeg from stream";
00254 }
00255
00256
00257 jpeg_create_decompress(&cinfo);
00258 setJpegSourceStream(cinfo, stream);
00259 jpeg_read_header(&cinfo, TRUE);
00260 cinfo.out_color_space = JCS_RGB;
00261 cinfo.quantize_colors = FALSE;
00262 jpeg_calc_output_dimensions(&cinfo);
00263
00264
00265 image.width = cinfo.output_width;
00266 image.height = cinfo.output_height;
00267 image.bytes_per_pixel = 3;
00268 image.bit_depth = 24;
00269 image.color_format = eColorFormat_RGB;
00270 image.allocate();
00271 if (!image.data) {
00272 jpeg_destroy_decompress(&cinfo);
00273 WAVE_EX(wex);
00274 wex << "Out of memory";
00275 }
00276
00277
00278 jpeg_start_decompress(&cinfo);
00279 while (cinfo.output_scanline < cinfo.output_height) {
00280 rowptr[0] = (JSAMPROW) (image.data +
00281 (cinfo.output_scanline * cinfo.output_width));
00282 jpeg_read_scanlines(&cinfo, rowptr, (JDIMENSION) 1);
00283 }
00284
00285
00286 jpeg_finish_decompress(&cinfo);
00287 jpeg_destroy_decompress(&cinfo);
00288 }
00289
00290
00291
00292 class JpegImageLoader : public ImageLoader {
00293 public:
00294 ~JpegImageLoader(void) throw() { }
00295
00296
00297 const char * getLoaderName(void) const throw() { return "JPEG"; }
00298
00299 bool canLoadImage(IN nstream::Manager * mgr,
00300 IN const char * name) const {
00301 mgr = mgr;
00302 ASSERT(name, "null");
00303
00304 const char * ext = GetExtension(name);
00305 return (!strcasecmp(ext, "jpg") ||
00306 !strcasecmp(ext, "jpeg"));
00307 }
00308
00309 void load(IN nstream::Stream * stream,
00310 OUT image_t& image) const {
00311 ASSERT(stream, "null");
00312 std::istream& input = stream->getStream();
00313 ASSERT_THROW(input.good(), "bad?");
00314
00315 readJpegFromStream(input, image);
00316 }
00317 };
00318
00319
00320
00321 smart_ptr<ImageLoader>
00322 createJpegImageLoader
00323 (
00324 void
00325 )
00326 {
00327 smart_ptr<ImageLoader> local = new JpegImageLoader;
00328 ASSERT_THROW(local, "out of memory");
00329
00330 return local;
00331 }
00332
00333
00334
00335 };
00336