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
00089 static int
00090 fill_input_buffer
00091 (
00092 IN struct jpeg_decompress_struct * pds
00093 )
00094 {
00095 ASSERT(pds, "null");
00096 source_context_t * psc = (source_context_t *) pds->src;
00097 ASSERT(psc, "null source object");
00098 ASSERT(psc->pstream, "null stream");
00099
00100
00101
00102
00103 psc->pstream->read(psc->buffer, s_bufferSize);
00104 int nRead = psc->pstream->gcount();
00105
00106
00107
00108
00109 if (nRead <= 0) {
00110 psc->buffer[0] = 0xFF;
00111 psc->buffer[1] = JPEG_EOI;
00112 nRead = 2;
00113 }
00114
00115
00116 psc->pub.next_input_byte = (JOCTET *) psc->buffer;
00117 psc->pub.bytes_in_buffer = nRead;
00118
00119 return TRUE;
00120 }
00121
00122
00123
00124 static void
00125 skip_input_data
00126 (
00127 IN struct jpeg_decompress_struct * pds,
00128 IN long bytes
00129 )
00130 {
00131 ASSERT(pds, "null");
00132 source_context_t * psc = (source_context_t *) pds->src;
00133 ASSERT(psc, "null source");
00134
00135 if (bytes < 1)
00136 return;
00137
00138 while (bytes > (long) psc->pub.bytes_in_buffer) {
00139 bytes -= psc->pub.bytes_in_buffer;
00140 psc->pub.fill_input_buffer(pds);
00141 }
00142
00143 psc->pub.next_input_byte += bytes;
00144 psc->pub.bytes_in_buffer -= bytes;
00145 }
00146
00147
00148
00149 static void
00150 term_source
00151 (
00152 IN struct jpeg_decompress_struct * pds
00153 )
00154 {
00155 pds = pds;
00156
00157 }
00158
00159
00160
00161 static void
00162 setJpegSourceStream
00163 (
00164 IN struct jpeg_decompress_struct& cinfo,
00165 IN std::istream& stream
00166 )
00167 {
00168 ASSERT_THROW(stream.good(), "bad?");
00169
00170
00171
00172
00173 if (!cinfo.src) {
00174 cinfo.src = (struct jpeg_source_mgr *)
00175 (*cinfo.mem->alloc_small)((j_common_ptr) &cinfo,
00176 JPOOL_PERMANENT,
00177 sizeof(source_context_t));
00178 ASSERT(cinfo.src, "out of memory");
00179
00180 source_context_t * psc = (source_context_t *) cinfo.src;
00181 psc->clear();
00182 }
00183
00184
00185 source_context_t * psc = (source_context_t *) cinfo.src;
00186 ASSERT(psc, "null");
00187 psc->pub.init_source = init_source;
00188 psc->pub.fill_input_buffer = fill_input_buffer;
00189 psc->pub.skip_input_data = skip_input_data;
00190 psc->pub.resync_to_restart = jpeg_resync_to_restart;
00191 psc->pub.term_source = term_source;
00192 psc->pub.next_input_byte = (JOCTET *) psc->buffer;
00193 psc->pub.bytes_in_buffer = 0;
00194
00195 psc->pstream = &stream;
00196 }
00197
00198
00199
00200 struct my_error_mgr {
00201 struct jpeg_error_mgr errmgr;
00202 jmp_buf setjmp_buffer;
00203 };
00204
00205
00206
00207 static void
00208 my_error_exit
00209 (
00210 IN j_common_ptr cinfo
00211 )
00212 {
00213 my_error_mgr * err = (my_error_mgr *) cinfo->err;
00214 longjmp(err->setjmp_buffer, 1);
00215 }
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225 void
00226 readJpegFromStream
00227 (
00228 IO std::istream& stream,
00229 OUT image_t& image
00230 )
00231 {
00232 perf::Timer timer("readJpegFromStream");
00233 ASSERT_THROW(stream.good(), "bad?");
00234 image.clear();
00235
00236 struct jpeg_decompress_struct cinfo;
00237 struct my_error_mgr jerr;
00238 JSAMPROW rowptr[1];
00239
00240
00241 cinfo.err = jpeg_std_error(&jerr.errmgr);
00242 jerr.errmgr.error_exit = my_error_exit;
00243 cinfo.err->output_message = NULL;
00244 if (setjmp(jerr.setjmp_buffer)) {
00245 jpeg_destroy_decompress(&cinfo);
00246 image.clear();
00247 WAVE_EX(wex);
00248 wex << "Failed to read jpeg from stream";
00249 }
00250
00251
00252 jpeg_create_decompress(&cinfo);
00253 setJpegSourceStream(cinfo, stream);
00254 jpeg_read_header(&cinfo, TRUE);
00255 cinfo.out_color_space = JCS_RGB;
00256 cinfo.quantize_colors = FALSE;
00257 jpeg_calc_output_dimensions(&cinfo);
00258
00259
00260 image.width = cinfo.output_width;
00261 image.height = cinfo.output_height;
00262 image.bytes_per_pixel = 3;
00263 image.bit_depth = 24;
00264 image.allocate();
00265 if (!image.data) {
00266 jpeg_destroy_decompress(&cinfo);
00267 WAVE_EX(wex);
00268 wex << "Out of memory";
00269 }
00270
00271
00272 jpeg_start_decompress(&cinfo);
00273 while (cinfo.output_scanline < cinfo.output_height) {
00274 rowptr[0] = (JSAMPROW) (image.data +
00275 (cinfo.output_scanline * cinfo.output_width));
00276 jpeg_read_scanlines(&cinfo, rowptr, (JDIMENSION) 1);
00277 }
00278
00279
00280 jpeg_finish_decompress(&cinfo);
00281 jpeg_destroy_decompress(&cinfo);
00282 }
00283
00284
00285
00286 class JpegImageLoader : public ImageLoader {
00287 public:
00288 ~JpegImageLoader(void) throw() { }
00289
00290
00291 const char * getLoaderName(void) const throw() { return "JPEG"; }
00292
00293 bool canLoadImage(IN nstream::Manager * mgr,
00294 IN const char * name) const {
00295 mgr = mgr;
00296 ASSERT(name, "null");
00297
00298 const char * ext = GetExtension(name);
00299 return (!strcasecmp(ext, "jpg") ||
00300 !strcasecmp(ext, "jpeg"));
00301 }
00302
00303 void load(IN nstream::Stream * stream,
00304 OUT image_t& image) const {
00305 ASSERT(stream, "null");
00306 std::istream& input = stream->getStream();
00307 ASSERT_THROW(input.good(), "bad?");
00308
00309 readJpegFromStream(input, image);
00310 }
00311 };
00312
00313
00314
00315 smart_ptr<ImageLoader>
00316 createJpegImageLoader
00317 (
00318 void
00319 )
00320 {
00321 smart_ptr<ImageLoader> local = new JpegImageLoader;
00322 ASSERT_THROW(local, "out of memory");
00323
00324 return local;
00325 }
00326
00327
00328
00329 };
00330