1 /*
2 * Copyright 2012 The LibYuv Project Authors. All rights reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11 #include "libyuv/mjpeg_decoder.h"
12
13 #ifdef HAVE_JPEG
14 #include <assert.h>
15
16 #if !defined(__pnacl__) && !defined(__CLR_VER) && \
17 !defined(COVERAGE_ENABLED) && !defined(TARGET_IPHONE_SIMULATOR)
18 // Must be included before jpeglib.
19 #include <setjmp.h>
20 #define HAVE_SETJMP
21
22 #if defined(_MSC_VER)
23 // disable warning 4324: structure was padded due to __declspec(align())
24 #pragma warning(disable:4324)
25 #endif
26
27 #endif
28 struct FILE; // For jpeglib.h.
29
30 // C++ build requires extern C for jpeg internals.
31 #ifdef __cplusplus
32 extern "C" {
33 #endif
34
35 #include <jpeglib.h>
36
37 #ifdef __cplusplus
38 } // extern "C"
39 #endif
40
41 #include "libyuv/planar_functions.h" // For CopyPlane().
42
43 namespace libyuv {
44
45 #ifdef HAVE_SETJMP
46 struct SetJmpErrorMgr {
47 jpeg_error_mgr base; // Must be at the top
48 jmp_buf setjmp_buffer;
49 };
50 #endif
51
52 const int MJpegDecoder::kColorSpaceUnknown = JCS_UNKNOWN;
53 const int MJpegDecoder::kColorSpaceGrayscale = JCS_GRAYSCALE;
54 const int MJpegDecoder::kColorSpaceRgb = JCS_RGB;
55 const int MJpegDecoder::kColorSpaceYCbCr = JCS_YCbCr;
56 const int MJpegDecoder::kColorSpaceCMYK = JCS_CMYK;
57 const int MJpegDecoder::kColorSpaceYCCK = JCS_YCCK;
58
59 // Methods that are passed to jpeglib.
60 boolean fill_input_buffer(jpeg_decompress_struct* cinfo);
61 void init_source(jpeg_decompress_struct* cinfo);
62 void skip_input_data(jpeg_decompress_struct* cinfo, long num_bytes); // NOLINT
63 void term_source(jpeg_decompress_struct* cinfo);
64 void ErrorHandler(jpeg_common_struct* cinfo);
65
MJpegDecoder()66 MJpegDecoder::MJpegDecoder()
67 : has_scanline_padding_(LIBYUV_FALSE),
68 num_outbufs_(0),
69 scanlines_(NULL),
70 scanlines_sizes_(NULL),
71 databuf_(NULL),
72 databuf_strides_(NULL) {
73 decompress_struct_ = new jpeg_decompress_struct;
74 source_mgr_ = new jpeg_source_mgr;
75 #ifdef HAVE_SETJMP
76 error_mgr_ = new SetJmpErrorMgr;
77 decompress_struct_->err = jpeg_std_error(&error_mgr_->base);
78 // Override standard exit()-based error handler.
79 error_mgr_->base.error_exit = &ErrorHandler;
80 #endif
81 decompress_struct_->client_data = NULL;
82 source_mgr_->init_source = &init_source;
83 source_mgr_->fill_input_buffer = &fill_input_buffer;
84 source_mgr_->skip_input_data = &skip_input_data;
85 source_mgr_->resync_to_restart = &jpeg_resync_to_restart;
86 source_mgr_->term_source = &term_source;
87 jpeg_create_decompress(decompress_struct_);
88 decompress_struct_->src = source_mgr_;
89 buf_vec_.buffers = &buf_;
90 buf_vec_.len = 1;
91 }
92
~MJpegDecoder()93 MJpegDecoder::~MJpegDecoder() {
94 jpeg_destroy_decompress(decompress_struct_);
95 delete decompress_struct_;
96 delete source_mgr_;
97 #ifdef HAVE_SETJMP
98 delete error_mgr_;
99 #endif
100 DestroyOutputBuffers();
101 }
102
LoadFrame(const uint8 * src,size_t src_len)103 LIBYUV_BOOL MJpegDecoder::LoadFrame(const uint8* src, size_t src_len) {
104 if (!ValidateJpeg(src, src_len)) {
105 return LIBYUV_FALSE;
106 }
107
108 buf_.data = src;
109 buf_.len = static_cast<int>(src_len);
110 buf_vec_.pos = 0;
111 decompress_struct_->client_data = &buf_vec_;
112 #ifdef HAVE_SETJMP
113 if (setjmp(error_mgr_->setjmp_buffer)) {
114 // We called jpeg_read_header, it experienced an error, and we called
115 // longjmp() and rewound the stack to here. Return error.
116 return LIBYUV_FALSE;
117 }
118 #endif
119 if (jpeg_read_header(decompress_struct_, TRUE) != JPEG_HEADER_OK) {
120 // ERROR: Bad MJPEG header
121 return LIBYUV_FALSE;
122 }
123 AllocOutputBuffers(GetNumComponents());
124 for (int i = 0; i < num_outbufs_; ++i) {
125 int scanlines_size = GetComponentScanlinesPerImcuRow(i);
126 if (scanlines_sizes_[i] != scanlines_size) {
127 if (scanlines_[i]) {
128 delete scanlines_[i];
129 }
130 scanlines_[i] = new uint8* [scanlines_size];
131 scanlines_sizes_[i] = scanlines_size;
132 }
133
134 // We allocate padding for the final scanline to pad it up to DCTSIZE bytes
135 // to avoid memory errors, since jpeglib only reads full MCUs blocks. For
136 // the preceding scanlines, the padding is not needed/wanted because the
137 // following addresses will already be valid (they are the initial bytes of
138 // the next scanline) and will be overwritten when jpeglib writes out that
139 // next scanline.
140 int databuf_stride = GetComponentStride(i);
141 int databuf_size = scanlines_size * databuf_stride;
142 if (databuf_strides_[i] != databuf_stride) {
143 if (databuf_[i]) {
144 delete databuf_[i];
145 }
146 databuf_[i] = new uint8[databuf_size];
147 databuf_strides_[i] = databuf_stride;
148 }
149
150 if (GetComponentStride(i) != GetComponentWidth(i)) {
151 has_scanline_padding_ = LIBYUV_TRUE;
152 }
153 }
154 return LIBYUV_TRUE;
155 }
156
DivideAndRoundUp(int numerator,int denominator)157 static int DivideAndRoundUp(int numerator, int denominator) {
158 return (numerator + denominator - 1) / denominator;
159 }
160
DivideAndRoundDown(int numerator,int denominator)161 static int DivideAndRoundDown(int numerator, int denominator) {
162 return numerator / denominator;
163 }
164
165 // Returns width of the last loaded frame.
GetWidth()166 int MJpegDecoder::GetWidth() {
167 return decompress_struct_->image_width;
168 }
169
170 // Returns height of the last loaded frame.
GetHeight()171 int MJpegDecoder::GetHeight() {
172 return decompress_struct_->image_height;
173 }
174
175 // Returns format of the last loaded frame. The return value is one of the
176 // kColorSpace* constants.
GetColorSpace()177 int MJpegDecoder::GetColorSpace() {
178 return decompress_struct_->jpeg_color_space;
179 }
180
181 // Number of color components in the color space.
GetNumComponents()182 int MJpegDecoder::GetNumComponents() {
183 return decompress_struct_->num_components;
184 }
185
186 // Sample factors of the n-th component.
GetHorizSampFactor(int component)187 int MJpegDecoder::GetHorizSampFactor(int component) {
188 return decompress_struct_->comp_info[component].h_samp_factor;
189 }
190
GetVertSampFactor(int component)191 int MJpegDecoder::GetVertSampFactor(int component) {
192 return decompress_struct_->comp_info[component].v_samp_factor;
193 }
194
GetHorizSubSampFactor(int component)195 int MJpegDecoder::GetHorizSubSampFactor(int component) {
196 return decompress_struct_->max_h_samp_factor /
197 GetHorizSampFactor(component);
198 }
199
GetVertSubSampFactor(int component)200 int MJpegDecoder::GetVertSubSampFactor(int component) {
201 return decompress_struct_->max_v_samp_factor /
202 GetVertSampFactor(component);
203 }
204
GetImageScanlinesPerImcuRow()205 int MJpegDecoder::GetImageScanlinesPerImcuRow() {
206 return decompress_struct_->max_v_samp_factor * DCTSIZE;
207 }
208
GetComponentScanlinesPerImcuRow(int component)209 int MJpegDecoder::GetComponentScanlinesPerImcuRow(int component) {
210 int vs = GetVertSubSampFactor(component);
211 return DivideAndRoundUp(GetImageScanlinesPerImcuRow(), vs);
212 }
213
GetComponentWidth(int component)214 int MJpegDecoder::GetComponentWidth(int component) {
215 int hs = GetHorizSubSampFactor(component);
216 return DivideAndRoundUp(GetWidth(), hs);
217 }
218
GetComponentHeight(int component)219 int MJpegDecoder::GetComponentHeight(int component) {
220 int vs = GetVertSubSampFactor(component);
221 return DivideAndRoundUp(GetHeight(), vs);
222 }
223
224 // Get width in bytes padded out to a multiple of DCTSIZE
GetComponentStride(int component)225 int MJpegDecoder::GetComponentStride(int component) {
226 return (GetComponentWidth(component) + DCTSIZE - 1) & ~(DCTSIZE - 1);
227 }
228
GetComponentSize(int component)229 int MJpegDecoder::GetComponentSize(int component) {
230 return GetComponentWidth(component) * GetComponentHeight(component);
231 }
232
UnloadFrame()233 LIBYUV_BOOL MJpegDecoder::UnloadFrame() {
234 #ifdef HAVE_SETJMP
235 if (setjmp(error_mgr_->setjmp_buffer)) {
236 // We called jpeg_abort_decompress, it experienced an error, and we called
237 // longjmp() and rewound the stack to here. Return error.
238 return LIBYUV_FALSE;
239 }
240 #endif
241 jpeg_abort_decompress(decompress_struct_);
242 return LIBYUV_TRUE;
243 }
244
245 // TODO(fbarchard): Allow rectangle to be specified: x, y, width, height.
DecodeToBuffers(uint8 ** planes,int dst_width,int dst_height)246 LIBYUV_BOOL MJpegDecoder::DecodeToBuffers(
247 uint8** planes, int dst_width, int dst_height) {
248 if (dst_width != GetWidth() ||
249 dst_height > GetHeight()) {
250 // ERROR: Bad dimensions
251 return LIBYUV_FALSE;
252 }
253 #ifdef HAVE_SETJMP
254 if (setjmp(error_mgr_->setjmp_buffer)) {
255 // We called into jpeglib, it experienced an error sometime during this
256 // function call, and we called longjmp() and rewound the stack to here.
257 // Return error.
258 return LIBYUV_FALSE;
259 }
260 #endif
261 if (!StartDecode()) {
262 return LIBYUV_FALSE;
263 }
264 SetScanlinePointers(databuf_);
265 int lines_left = dst_height;
266 // Compute amount of lines to skip to implement vertical crop.
267 // TODO(fbarchard): Ensure skip is a multiple of maximum component
268 // subsample. ie 2
269 int skip = (GetHeight() - dst_height) / 2;
270 if (skip > 0) {
271 // There is no API to skip lines in the output data, so we read them
272 // into the temp buffer.
273 while (skip >= GetImageScanlinesPerImcuRow()) {
274 if (!DecodeImcuRow()) {
275 FinishDecode();
276 return LIBYUV_FALSE;
277 }
278 skip -= GetImageScanlinesPerImcuRow();
279 }
280 if (skip > 0) {
281 // Have a partial iMCU row left over to skip. Must read it and then
282 // copy the parts we want into the destination.
283 if (!DecodeImcuRow()) {
284 FinishDecode();
285 return LIBYUV_FALSE;
286 }
287 for (int i = 0; i < num_outbufs_; ++i) {
288 // TODO(fbarchard): Compute skip to avoid this
289 assert(skip % GetVertSubSampFactor(i) == 0);
290 int rows_to_skip =
291 DivideAndRoundDown(skip, GetVertSubSampFactor(i));
292 int scanlines_to_copy = GetComponentScanlinesPerImcuRow(i) -
293 rows_to_skip;
294 int data_to_skip = rows_to_skip * GetComponentStride(i);
295 CopyPlane(databuf_[i] + data_to_skip, GetComponentStride(i),
296 planes[i], GetComponentWidth(i),
297 GetComponentWidth(i), scanlines_to_copy);
298 planes[i] += scanlines_to_copy * GetComponentWidth(i);
299 }
300 lines_left -= (GetImageScanlinesPerImcuRow() - skip);
301 }
302 }
303
304 // Read full MCUs but cropped horizontally
305 for (; lines_left > GetImageScanlinesPerImcuRow();
306 lines_left -= GetImageScanlinesPerImcuRow()) {
307 if (!DecodeImcuRow()) {
308 FinishDecode();
309 return LIBYUV_FALSE;
310 }
311 for (int i = 0; i < num_outbufs_; ++i) {
312 int scanlines_to_copy = GetComponentScanlinesPerImcuRow(i);
313 CopyPlane(databuf_[i], GetComponentStride(i),
314 planes[i], GetComponentWidth(i),
315 GetComponentWidth(i), scanlines_to_copy);
316 planes[i] += scanlines_to_copy * GetComponentWidth(i);
317 }
318 }
319
320 if (lines_left > 0) {
321 // Have a partial iMCU row left over to decode.
322 if (!DecodeImcuRow()) {
323 FinishDecode();
324 return LIBYUV_FALSE;
325 }
326 for (int i = 0; i < num_outbufs_; ++i) {
327 int scanlines_to_copy =
328 DivideAndRoundUp(lines_left, GetVertSubSampFactor(i));
329 CopyPlane(databuf_[i], GetComponentStride(i),
330 planes[i], GetComponentWidth(i),
331 GetComponentWidth(i), scanlines_to_copy);
332 planes[i] += scanlines_to_copy * GetComponentWidth(i);
333 }
334 }
335 return FinishDecode();
336 }
337
DecodeToCallback(CallbackFunction fn,void * opaque,int dst_width,int dst_height)338 LIBYUV_BOOL MJpegDecoder::DecodeToCallback(CallbackFunction fn, void* opaque,
339 int dst_width, int dst_height) {
340 if (dst_width != GetWidth() ||
341 dst_height > GetHeight()) {
342 // ERROR: Bad dimensions
343 return LIBYUV_FALSE;
344 }
345 #ifdef HAVE_SETJMP
346 if (setjmp(error_mgr_->setjmp_buffer)) {
347 // We called into jpeglib, it experienced an error sometime during this
348 // function call, and we called longjmp() and rewound the stack to here.
349 // Return error.
350 return LIBYUV_FALSE;
351 }
352 #endif
353 if (!StartDecode()) {
354 return LIBYUV_FALSE;
355 }
356 SetScanlinePointers(databuf_);
357 int lines_left = dst_height;
358 // TODO(fbarchard): Compute amount of lines to skip to implement vertical crop
359 int skip = (GetHeight() - dst_height) / 2;
360 if (skip > 0) {
361 while (skip >= GetImageScanlinesPerImcuRow()) {
362 if (!DecodeImcuRow()) {
363 FinishDecode();
364 return LIBYUV_FALSE;
365 }
366 skip -= GetImageScanlinesPerImcuRow();
367 }
368 if (skip > 0) {
369 // Have a partial iMCU row left over to skip.
370 if (!DecodeImcuRow()) {
371 FinishDecode();
372 return LIBYUV_FALSE;
373 }
374 for (int i = 0; i < num_outbufs_; ++i) {
375 // TODO(fbarchard): Compute skip to avoid this
376 assert(skip % GetVertSubSampFactor(i) == 0);
377 int rows_to_skip = DivideAndRoundDown(skip, GetVertSubSampFactor(i));
378 int data_to_skip = rows_to_skip * GetComponentStride(i);
379 // Change our own data buffer pointers so we can pass them to the
380 // callback.
381 databuf_[i] += data_to_skip;
382 }
383 int scanlines_to_copy = GetImageScanlinesPerImcuRow() - skip;
384 (*fn)(opaque, databuf_, databuf_strides_, scanlines_to_copy);
385 // Now change them back.
386 for (int i = 0; i < num_outbufs_; ++i) {
387 int rows_to_skip = DivideAndRoundDown(skip, GetVertSubSampFactor(i));
388 int data_to_skip = rows_to_skip * GetComponentStride(i);
389 databuf_[i] -= data_to_skip;
390 }
391 lines_left -= scanlines_to_copy;
392 }
393 }
394 // Read full MCUs until we get to the crop point.
395 for (; lines_left >= GetImageScanlinesPerImcuRow();
396 lines_left -= GetImageScanlinesPerImcuRow()) {
397 if (!DecodeImcuRow()) {
398 FinishDecode();
399 return LIBYUV_FALSE;
400 }
401 (*fn)(opaque, databuf_, databuf_strides_, GetImageScanlinesPerImcuRow());
402 }
403 if (lines_left > 0) {
404 // Have a partial iMCU row left over to decode.
405 if (!DecodeImcuRow()) {
406 FinishDecode();
407 return LIBYUV_FALSE;
408 }
409 (*fn)(opaque, databuf_, databuf_strides_, lines_left);
410 }
411 return FinishDecode();
412 }
413
init_source(j_decompress_ptr cinfo)414 void init_source(j_decompress_ptr cinfo) {
415 fill_input_buffer(cinfo);
416 }
417
fill_input_buffer(j_decompress_ptr cinfo)418 boolean fill_input_buffer(j_decompress_ptr cinfo) {
419 BufferVector* buf_vec = reinterpret_cast<BufferVector*>(cinfo->client_data);
420 if (buf_vec->pos >= buf_vec->len) {
421 assert(0 && "No more data");
422 // ERROR: No more data
423 return FALSE;
424 }
425 cinfo->src->next_input_byte = buf_vec->buffers[buf_vec->pos].data;
426 cinfo->src->bytes_in_buffer = buf_vec->buffers[buf_vec->pos].len;
427 ++buf_vec->pos;
428 return TRUE;
429 }
430
skip_input_data(j_decompress_ptr cinfo,long num_bytes)431 void skip_input_data(j_decompress_ptr cinfo, long num_bytes) { // NOLINT
432 cinfo->src->next_input_byte += num_bytes;
433 }
434
term_source(j_decompress_ptr cinfo)435 void term_source(j_decompress_ptr cinfo) {
436 // Nothing to do.
437 }
438
439 #ifdef HAVE_SETJMP
ErrorHandler(j_common_ptr cinfo)440 void ErrorHandler(j_common_ptr cinfo) {
441 // This is called when a jpeglib command experiences an error. Unfortunately
442 // jpeglib's error handling model is not very flexible, because it expects the
443 // error handler to not return--i.e., it wants the program to terminate. To
444 // recover from errors we use setjmp() as shown in their example. setjmp() is
445 // C's implementation for the "call with current continuation" functionality
446 // seen in some functional programming languages.
447 // A formatted message can be output, but is unsafe for release.
448 #ifdef DEBUG
449 char buf[JMSG_LENGTH_MAX];
450 (*cinfo->err->format_message)(cinfo, buf);
451 // ERROR: Error in jpeglib: buf
452 #endif
453
454 SetJmpErrorMgr* mgr = reinterpret_cast<SetJmpErrorMgr*>(cinfo->err);
455 // This rewinds the call stack to the point of the corresponding setjmp()
456 // and causes it to return (for a second time) with value 1.
457 longjmp(mgr->setjmp_buffer, 1);
458 }
459 #endif
460
AllocOutputBuffers(int num_outbufs)461 void MJpegDecoder::AllocOutputBuffers(int num_outbufs) {
462 if (num_outbufs != num_outbufs_) {
463 // We could perhaps optimize this case to resize the output buffers without
464 // necessarily having to delete and recreate each one, but it's not worth
465 // it.
466 DestroyOutputBuffers();
467
468 scanlines_ = new uint8** [num_outbufs];
469 scanlines_sizes_ = new int[num_outbufs];
470 databuf_ = new uint8* [num_outbufs];
471 databuf_strides_ = new int[num_outbufs];
472
473 for (int i = 0; i < num_outbufs; ++i) {
474 scanlines_[i] = NULL;
475 scanlines_sizes_[i] = 0;
476 databuf_[i] = NULL;
477 databuf_strides_[i] = 0;
478 }
479
480 num_outbufs_ = num_outbufs;
481 }
482 }
483
DestroyOutputBuffers()484 void MJpegDecoder::DestroyOutputBuffers() {
485 for (int i = 0; i < num_outbufs_; ++i) {
486 delete [] scanlines_[i];
487 delete [] databuf_[i];
488 }
489 delete [] scanlines_;
490 delete [] databuf_;
491 delete [] scanlines_sizes_;
492 delete [] databuf_strides_;
493 scanlines_ = NULL;
494 databuf_ = NULL;
495 scanlines_sizes_ = NULL;
496 databuf_strides_ = NULL;
497 num_outbufs_ = 0;
498 }
499
500 // JDCT_IFAST and do_block_smoothing improve performance substantially.
StartDecode()501 LIBYUV_BOOL MJpegDecoder::StartDecode() {
502 decompress_struct_->raw_data_out = TRUE;
503 decompress_struct_->dct_method = JDCT_IFAST; // JDCT_ISLOW is default
504 decompress_struct_->dither_mode = JDITHER_NONE;
505 // Not applicable to 'raw':
506 decompress_struct_->do_fancy_upsampling = (boolean)(LIBYUV_FALSE);
507 // Only for buffered mode:
508 decompress_struct_->enable_2pass_quant = (boolean)(LIBYUV_FALSE);
509 // Blocky but fast:
510 decompress_struct_->do_block_smoothing = (boolean)(LIBYUV_FALSE);
511
512 if (!jpeg_start_decompress(decompress_struct_)) {
513 // ERROR: Couldn't start JPEG decompressor";
514 return LIBYUV_FALSE;
515 }
516 return LIBYUV_TRUE;
517 }
518
FinishDecode()519 LIBYUV_BOOL MJpegDecoder::FinishDecode() {
520 // jpeglib considers it an error if we finish without decoding the whole
521 // image, so we call "abort" rather than "finish".
522 jpeg_abort_decompress(decompress_struct_);
523 return LIBYUV_TRUE;
524 }
525
SetScanlinePointers(uint8 ** data)526 void MJpegDecoder::SetScanlinePointers(uint8** data) {
527 for (int i = 0; i < num_outbufs_; ++i) {
528 uint8* data_i = data[i];
529 for (int j = 0; j < scanlines_sizes_[i]; ++j) {
530 scanlines_[i][j] = data_i;
531 data_i += GetComponentStride(i);
532 }
533 }
534 }
535
DecodeImcuRow()536 inline LIBYUV_BOOL MJpegDecoder::DecodeImcuRow() {
537 return (unsigned int)(GetImageScanlinesPerImcuRow()) ==
538 jpeg_read_raw_data(decompress_struct_,
539 scanlines_,
540 GetImageScanlinesPerImcuRow());
541 }
542
543 // The helper function which recognizes the jpeg sub-sampling type.
JpegSubsamplingTypeHelper(int * subsample_x,int * subsample_y,int number_of_components)544 JpegSubsamplingType MJpegDecoder::JpegSubsamplingTypeHelper(
545 int* subsample_x, int* subsample_y, int number_of_components) {
546 if (number_of_components == 3) { // Color images.
547 if (subsample_x[0] == 1 && subsample_y[0] == 1 &&
548 subsample_x[1] == 2 && subsample_y[1] == 2 &&
549 subsample_x[2] == 2 && subsample_y[2] == 2) {
550 return kJpegYuv420;
551 } else if (subsample_x[0] == 1 && subsample_y[0] == 1 &&
552 subsample_x[1] == 2 && subsample_y[1] == 1 &&
553 subsample_x[2] == 2 && subsample_y[2] == 1) {
554 return kJpegYuv422;
555 } else if (subsample_x[0] == 1 && subsample_y[0] == 1 &&
556 subsample_x[1] == 1 && subsample_y[1] == 1 &&
557 subsample_x[2] == 1 && subsample_y[2] == 1) {
558 return kJpegYuv444;
559 }
560 } else if (number_of_components == 1) { // Grey-scale images.
561 if (subsample_x[0] == 1 && subsample_y[0] == 1) {
562 return kJpegYuv400;
563 }
564 }
565 return kJpegUnknown;
566 }
567
568 } // namespace libyuv
569 #endif // HAVE_JPEG
570
571