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