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