141294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org/*
241294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org *  Copyright 2012 The LibYuv Project Authors. All rights reserved.
341294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org *
441294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org *  Use of this source code is governed by a BSD-style license
541294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org *  that can be found in the LICENSE file in the root of the source
641294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org *  tree. An additional intellectual property rights grant can be found
741294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org *  in the file PATENTS. All contributing project authors may
841294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org *  be found in the AUTHORS file in the root of the source tree.
941294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org */
1041294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org
1141294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org#include "libyuv/mjpeg_decoder.h"
1241294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org
1341294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org#ifdef HAVE_JPEG
1441294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org#include <assert.h>
1541294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org
16d95585fb0ec024f6abd96f7b02e0df58019d46afjohannkoenig@chromium.org#if !defined(__pnacl__) && !defined(__CLR_VER) && \
17d95585fb0ec024f6abd96f7b02e0df58019d46afjohannkoenig@chromium.org    !defined(COVERAGE_ENABLED) && !defined(TARGET_IPHONE_SIMULATOR)
1841294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org// Must be included before jpeglib.
1941294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org#include <setjmp.h>
2041294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org#define HAVE_SETJMP
2141294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org#endif
2241294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.orgstruct FILE;  // For jpeglib.h.
2341294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org
2441294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org// C++ build requires extern C for jpeg internals.
2541294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org#ifdef __cplusplus
2641294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.orgextern "C" {
2741294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org#endif
2841294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org
2941294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org#include <jpeglib.h>
3041294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org
3141294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org#ifdef __cplusplus
3241294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org}  // extern "C"
3341294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org#endif
3441294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org
3541294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org#include "libyuv/planar_functions.h"  // For CopyPlane().
3641294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org
3741294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.orgnamespace libyuv {
3841294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org
3941294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org#ifdef HAVE_SETJMP
4041294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.orgstruct SetJmpErrorMgr {
4141294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  jpeg_error_mgr base;  // Must be at the top
4241294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  jmp_buf setjmp_buffer;
4341294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org};
4441294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org#endif
4541294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org
4641294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.orgconst int MJpegDecoder::kColorSpaceUnknown = JCS_UNKNOWN;
4741294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.orgconst int MJpegDecoder::kColorSpaceGrayscale = JCS_GRAYSCALE;
4841294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.orgconst int MJpegDecoder::kColorSpaceRgb = JCS_RGB;
4941294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.orgconst int MJpegDecoder::kColorSpaceYCbCr = JCS_YCbCr;
5041294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.orgconst int MJpegDecoder::kColorSpaceCMYK = JCS_CMYK;
5141294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.orgconst int MJpegDecoder::kColorSpaceYCCK = JCS_YCCK;
5241294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org
5341294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org// Methods that are passed to jpeglib.
5441294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.orgboolean fill_input_buffer(jpeg_decompress_struct* cinfo);
5541294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.orgvoid init_source(jpeg_decompress_struct* cinfo);
5641294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.orgvoid skip_input_data(jpeg_decompress_struct* cinfo,
5741294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org                     long num_bytes);  // NOLINT
5841294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.orgvoid term_source(jpeg_decompress_struct* cinfo);
5941294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.orgvoid ErrorHandler(jpeg_common_struct* cinfo);
6041294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org
6141294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.orgMJpegDecoder::MJpegDecoder()
6241294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org    : has_scanline_padding_(LIBYUV_FALSE),
6341294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org      num_outbufs_(0),
6441294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org      scanlines_(NULL),
6541294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org      scanlines_sizes_(NULL),
6641294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org      databuf_(NULL),
6741294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org      databuf_strides_(NULL) {
6841294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  decompress_struct_ = new jpeg_decompress_struct;
6941294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  source_mgr_ = new jpeg_source_mgr;
7041294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org#ifdef HAVE_SETJMP
7141294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  error_mgr_ = new SetJmpErrorMgr;
7241294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  decompress_struct_->err = jpeg_std_error(&error_mgr_->base);
7341294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  // Override standard exit()-based error handler.
7441294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  error_mgr_->base.error_exit = &ErrorHandler;
7541294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org#endif
7641294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  decompress_struct_->client_data = NULL;
7741294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  source_mgr_->init_source = &init_source;
7841294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  source_mgr_->fill_input_buffer = &fill_input_buffer;
7941294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  source_mgr_->skip_input_data = &skip_input_data;
8041294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  source_mgr_->resync_to_restart = &jpeg_resync_to_restart;
8141294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  source_mgr_->term_source = &term_source;
8241294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  jpeg_create_decompress(decompress_struct_);
8341294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  decompress_struct_->src = source_mgr_;
8441294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  buf_vec_.buffers = &buf_;
8541294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  buf_vec_.len = 1;
8641294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org}
8741294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org
8841294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.orgMJpegDecoder::~MJpegDecoder() {
8941294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  jpeg_destroy_decompress(decompress_struct_);
9041294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  delete decompress_struct_;
9141294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  delete source_mgr_;
9241294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org#ifdef HAVE_SETJMP
9341294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  delete error_mgr_;
9441294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org#endif
9541294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  DestroyOutputBuffers();
9641294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org}
9741294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org
9841294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.orgLIBYUV_BOOL MJpegDecoder::LoadFrame(const uint8* src, size_t src_len) {
9941294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  if (!ValidateJpeg(src, src_len)) {
10041294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org    return LIBYUV_FALSE;
10141294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  }
10241294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org
10341294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  buf_.data = src;
104d95585fb0ec024f6abd96f7b02e0df58019d46afjohannkoenig@chromium.org  buf_.len = static_cast<int>(src_len);
10541294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  buf_vec_.pos = 0;
10641294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  decompress_struct_->client_data = &buf_vec_;
10741294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org#ifdef HAVE_SETJMP
10841294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  if (setjmp(error_mgr_->setjmp_buffer)) {
10941294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org    // We called jpeg_read_header, it experienced an error, and we called
11041294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org    // longjmp() and rewound the stack to here. Return error.
11141294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org    return LIBYUV_FALSE;
11241294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  }
11341294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org#endif
11441294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  if (jpeg_read_header(decompress_struct_, TRUE) != JPEG_HEADER_OK) {
11541294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org    // ERROR: Bad MJPEG header
11641294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org    return LIBYUV_FALSE;
11741294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  }
11841294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  AllocOutputBuffers(GetNumComponents());
11941294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  for (int i = 0; i < num_outbufs_; ++i) {
12041294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org    int scanlines_size = GetComponentScanlinesPerImcuRow(i);
12141294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org    if (scanlines_sizes_[i] != scanlines_size) {
12241294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org      if (scanlines_[i]) {
12341294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org        delete scanlines_[i];
12441294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org      }
12541294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org      scanlines_[i] = new uint8* [scanlines_size];
12641294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org      scanlines_sizes_[i] = scanlines_size;
12741294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org    }
12841294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org
12941294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org    // We allocate padding for the final scanline to pad it up to DCTSIZE bytes
13041294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org    // to avoid memory errors, since jpeglib only reads full MCUs blocks. For
13141294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org    // the preceding scanlines, the padding is not needed/wanted because the
13241294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org    // following addresses will already be valid (they are the initial bytes of
13341294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org    // the next scanline) and will be overwritten when jpeglib writes out that
13441294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org    // next scanline.
13541294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org    int databuf_stride = GetComponentStride(i);
13641294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org    int databuf_size = scanlines_size * databuf_stride;
13741294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org    if (databuf_strides_[i] != databuf_stride) {
13841294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org      if (databuf_[i]) {
13941294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org        delete databuf_[i];
14041294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org      }
14141294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org      databuf_[i] = new uint8[databuf_size];
14241294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org      databuf_strides_[i] = databuf_stride;
14341294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org    }
14441294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org
14541294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org    if (GetComponentStride(i) != GetComponentWidth(i)) {
14641294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org      has_scanline_padding_ = LIBYUV_TRUE;
14741294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org    }
14841294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  }
14941294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  return LIBYUV_TRUE;
15041294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org}
15141294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org
15241294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.orgstatic int DivideAndRoundUp(int numerator, int denominator) {
15341294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  return (numerator + denominator - 1) / denominator;
15441294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org}
15541294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org
15641294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.orgstatic int DivideAndRoundDown(int numerator, int denominator) {
15741294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  return numerator / denominator;
15841294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org}
15941294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org
16041294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org// Returns width of the last loaded frame.
16141294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.orgint MJpegDecoder::GetWidth() {
16241294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  return decompress_struct_->image_width;
16341294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org}
16441294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org
16541294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org// Returns height of the last loaded frame.
16641294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.orgint MJpegDecoder::GetHeight() {
16741294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  return decompress_struct_->image_height;
16841294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org}
16941294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org
17041294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org// Returns format of the last loaded frame. The return value is one of the
17141294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org// kColorSpace* constants.
17241294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.orgint MJpegDecoder::GetColorSpace() {
17341294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  return decompress_struct_->jpeg_color_space;
17441294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org}
17541294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org
17641294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org// Number of color components in the color space.
17741294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.orgint MJpegDecoder::GetNumComponents() {
17841294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  return decompress_struct_->num_components;
17941294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org}
18041294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org
18141294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org// Sample factors of the n-th component.
18241294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.orgint MJpegDecoder::GetHorizSampFactor(int component) {
18341294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  return decompress_struct_->comp_info[component].h_samp_factor;
18441294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org}
18541294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org
18641294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.orgint MJpegDecoder::GetVertSampFactor(int component) {
18741294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  return decompress_struct_->comp_info[component].v_samp_factor;
18841294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org}
18941294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org
19041294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.orgint MJpegDecoder::GetHorizSubSampFactor(int component) {
19141294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  return decompress_struct_->max_h_samp_factor /
19241294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org      GetHorizSampFactor(component);
19341294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org}
19441294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org
19541294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.orgint MJpegDecoder::GetVertSubSampFactor(int component) {
19641294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  return decompress_struct_->max_v_samp_factor /
19741294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org      GetVertSampFactor(component);
19841294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org}
19941294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org
20041294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.orgint MJpegDecoder::GetImageScanlinesPerImcuRow() {
20141294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  return decompress_struct_->max_v_samp_factor * DCTSIZE;
20241294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org}
20341294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org
20441294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.orgint MJpegDecoder::GetComponentScanlinesPerImcuRow(int component) {
20541294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  int vs = GetVertSubSampFactor(component);
20641294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  return DivideAndRoundUp(GetImageScanlinesPerImcuRow(), vs);
20741294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org}
20841294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org
20941294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.orgint MJpegDecoder::GetComponentWidth(int component) {
21041294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  int hs = GetHorizSubSampFactor(component);
21141294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  return DivideAndRoundUp(GetWidth(), hs);
21241294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org}
21341294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org
21441294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.orgint MJpegDecoder::GetComponentHeight(int component) {
21541294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  int vs = GetVertSubSampFactor(component);
21641294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  return DivideAndRoundUp(GetHeight(), vs);
21741294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org}
21841294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org
21941294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org// Get width in bytes padded out to a multiple of DCTSIZE
22041294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.orgint MJpegDecoder::GetComponentStride(int component) {
22141294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  return (GetComponentWidth(component) + DCTSIZE - 1) & ~(DCTSIZE - 1);
22241294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org}
22341294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org
22441294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.orgint MJpegDecoder::GetComponentSize(int component) {
22541294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  return GetComponentWidth(component) * GetComponentHeight(component);
22641294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org}
22741294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org
22841294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.orgLIBYUV_BOOL MJpegDecoder::UnloadFrame() {
22941294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org#ifdef HAVE_SETJMP
23041294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  if (setjmp(error_mgr_->setjmp_buffer)) {
23141294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org    // We called jpeg_abort_decompress, it experienced an error, and we called
23241294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org    // longjmp() and rewound the stack to here. Return error.
23341294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org    return LIBYUV_FALSE;
23441294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  }
23541294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org#endif
23641294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  jpeg_abort_decompress(decompress_struct_);
23741294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  return LIBYUV_TRUE;
23841294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org}
23941294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org
24041294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org// TODO(fbarchard): Allow rectangle to be specified: x, y, width, height.
24141294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.orgLIBYUV_BOOL MJpegDecoder::DecodeToBuffers(
24241294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org    uint8** planes, int dst_width, int dst_height) {
24341294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  if (dst_width != GetWidth() ||
24441294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org      dst_height > GetHeight()) {
24541294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org    // ERROR: Bad dimensions
24641294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org    return LIBYUV_FALSE;
24741294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  }
24841294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org#ifdef HAVE_SETJMP
24941294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  if (setjmp(error_mgr_->setjmp_buffer)) {
25041294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org    // We called into jpeglib, it experienced an error sometime during this
25141294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org    // function call, and we called longjmp() and rewound the stack to here.
25241294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org    // Return error.
25341294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org    return LIBYUV_FALSE;
25441294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  }
25541294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org#endif
25641294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  if (!StartDecode()) {
25741294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org    return LIBYUV_FALSE;
25841294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  }
25941294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  SetScanlinePointers(databuf_);
26041294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  int lines_left = dst_height;
26141294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  // Compute amount of lines to skip to implement vertical crop.
26241294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  // TODO(fbarchard): Ensure skip is a multiple of maximum component
26341294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  // subsample. ie 2
26441294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  int skip = (GetHeight() - dst_height) / 2;
26541294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  if (skip > 0) {
26641294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org    // There is no API to skip lines in the output data, so we read them
26741294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org    // into the temp buffer.
26841294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org    while (skip >= GetImageScanlinesPerImcuRow()) {
26941294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org      if (!DecodeImcuRow()) {
27041294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org        FinishDecode();
27141294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org        return LIBYUV_FALSE;
27241294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org      }
27341294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org      skip -= GetImageScanlinesPerImcuRow();
27441294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org    }
27541294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org    if (skip > 0) {
27641294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org      // Have a partial iMCU row left over to skip. Must read it and then
27741294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org      // copy the parts we want into the destination.
27841294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org      if (!DecodeImcuRow()) {
27941294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org        FinishDecode();
28041294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org        return LIBYUV_FALSE;
28141294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org      }
28241294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org      for (int i = 0; i < num_outbufs_; ++i) {
28341294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org        // TODO(fbarchard): Compute skip to avoid this
28441294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org        assert(skip % GetVertSubSampFactor(i) == 0);
28541294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org        int rows_to_skip =
28641294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org            DivideAndRoundDown(skip, GetVertSubSampFactor(i));
28741294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org        int scanlines_to_copy = GetComponentScanlinesPerImcuRow(i) -
28841294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org                                rows_to_skip;
28941294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org        int data_to_skip = rows_to_skip * GetComponentStride(i);
29041294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org        CopyPlane(databuf_[i] + data_to_skip, GetComponentStride(i),
29141294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org                  planes[i], GetComponentWidth(i),
29241294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org                  GetComponentWidth(i), scanlines_to_copy);
29341294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org        planes[i] += scanlines_to_copy * GetComponentWidth(i);
29441294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org      }
29541294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org      lines_left -= (GetImageScanlinesPerImcuRow() - skip);
29641294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org    }
29741294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  }
29841294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org
29941294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  // Read full MCUs but cropped horizontally
30041294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  for (; lines_left > GetImageScanlinesPerImcuRow();
30141294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org         lines_left -= GetImageScanlinesPerImcuRow()) {
30241294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org    if (!DecodeImcuRow()) {
30341294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org      FinishDecode();
30441294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org      return LIBYUV_FALSE;
30541294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org    }
30641294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org    for (int i = 0; i < num_outbufs_; ++i) {
30741294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org      int scanlines_to_copy = GetComponentScanlinesPerImcuRow(i);
30841294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org      CopyPlane(databuf_[i], GetComponentStride(i),
30941294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org                planes[i], GetComponentWidth(i),
31041294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org                GetComponentWidth(i), scanlines_to_copy);
31141294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org      planes[i] += scanlines_to_copy * GetComponentWidth(i);
31241294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org    }
31341294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  }
31441294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org
31541294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  if (lines_left > 0) {
31641294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org    // Have a partial iMCU row left over to decode.
31741294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org    if (!DecodeImcuRow()) {
31841294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org      FinishDecode();
31941294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org      return LIBYUV_FALSE;
32041294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org    }
32141294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org    for (int i = 0; i < num_outbufs_; ++i) {
32241294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org      int scanlines_to_copy =
32341294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org          DivideAndRoundUp(lines_left, GetVertSubSampFactor(i));
32441294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org      CopyPlane(databuf_[i], GetComponentStride(i),
32541294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org                planes[i], GetComponentWidth(i),
32641294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org                GetComponentWidth(i), scanlines_to_copy);
32741294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org      planes[i] += scanlines_to_copy * GetComponentWidth(i);
32841294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org    }
32941294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  }
33041294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  return FinishDecode();
33141294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org}
33241294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org
33341294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.orgLIBYUV_BOOL MJpegDecoder::DecodeToCallback(CallbackFunction fn, void* opaque,
33441294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org    int dst_width, int dst_height) {
33541294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  if (dst_width != GetWidth() ||
33641294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org      dst_height > GetHeight()) {
33741294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org    // ERROR: Bad dimensions
33841294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org    return LIBYUV_FALSE;
33941294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  }
34041294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org#ifdef HAVE_SETJMP
34141294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  if (setjmp(error_mgr_->setjmp_buffer)) {
34241294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org    // We called into jpeglib, it experienced an error sometime during this
34341294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org    // function call, and we called longjmp() and rewound the stack to here.
34441294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org    // Return error.
34541294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org    return LIBYUV_FALSE;
34641294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  }
34741294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org#endif
34841294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  if (!StartDecode()) {
34941294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org    return LIBYUV_FALSE;
35041294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  }
35141294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  SetScanlinePointers(databuf_);
35241294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  int lines_left = dst_height;
35341294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  // TODO(fbarchard): Compute amount of lines to skip to implement vertical crop
35441294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  int skip = (GetHeight() - dst_height) / 2;
35541294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  if (skip > 0) {
35641294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org    while (skip >= GetImageScanlinesPerImcuRow()) {
35741294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org      if (!DecodeImcuRow()) {
35841294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org        FinishDecode();
35941294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org        return LIBYUV_FALSE;
36041294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org      }
36141294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org      skip -= GetImageScanlinesPerImcuRow();
36241294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org    }
36341294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org    if (skip > 0) {
36441294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org      // Have a partial iMCU row left over to skip.
36541294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org      if (!DecodeImcuRow()) {
36641294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org        FinishDecode();
36741294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org        return LIBYUV_FALSE;
36841294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org      }
36941294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org      for (int i = 0; i < num_outbufs_; ++i) {
37041294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org        // TODO(fbarchard): Compute skip to avoid this
37141294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org        assert(skip % GetVertSubSampFactor(i) == 0);
37241294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org        int rows_to_skip = DivideAndRoundDown(skip, GetVertSubSampFactor(i));
37341294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org        int data_to_skip = rows_to_skip * GetComponentStride(i);
37441294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org        // Change our own data buffer pointers so we can pass them to the
37541294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org        // callback.
37641294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org        databuf_[i] += data_to_skip;
37741294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org      }
37841294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org      int scanlines_to_copy = GetImageScanlinesPerImcuRow() - skip;
37941294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org      (*fn)(opaque, databuf_, databuf_strides_, scanlines_to_copy);
38041294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org      // Now change them back.
38141294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org      for (int i = 0; i < num_outbufs_; ++i) {
38241294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org        int rows_to_skip = DivideAndRoundDown(skip, GetVertSubSampFactor(i));
38341294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org        int data_to_skip = rows_to_skip * GetComponentStride(i);
38441294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org        databuf_[i] -= data_to_skip;
38541294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org      }
38641294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org      lines_left -= scanlines_to_copy;
38741294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org    }
38841294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  }
38941294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  // Read full MCUs until we get to the crop point.
39041294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  for (; lines_left >= GetImageScanlinesPerImcuRow();
39141294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org         lines_left -= GetImageScanlinesPerImcuRow()) {
39241294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org    if (!DecodeImcuRow()) {
39341294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org      FinishDecode();
39441294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org      return LIBYUV_FALSE;
39541294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org    }
39641294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org    (*fn)(opaque, databuf_, databuf_strides_, GetImageScanlinesPerImcuRow());
39741294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  }
39841294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  if (lines_left > 0) {
39941294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org    // Have a partial iMCU row left over to decode.
40041294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org    if (!DecodeImcuRow()) {
40141294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org      FinishDecode();
40241294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org      return LIBYUV_FALSE;
40341294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org    }
40441294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org    (*fn)(opaque, databuf_, databuf_strides_, lines_left);
40541294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  }
40641294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  return FinishDecode();
40741294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org}
40841294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org
40941294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.orgvoid init_source(j_decompress_ptr cinfo) {
41041294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  fill_input_buffer(cinfo);
41141294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org}
41241294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org
41341294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.orgboolean fill_input_buffer(j_decompress_ptr cinfo) {
414d95585fb0ec024f6abd96f7b02e0df58019d46afjohannkoenig@chromium.org  BufferVector* buf_vec = reinterpret_cast<BufferVector*>(cinfo->client_data);
41541294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  if (buf_vec->pos >= buf_vec->len) {
41641294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org    assert(0 && "No more data");
41741294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org    // ERROR: No more data
41841294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org    return FALSE;
41941294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  }
42041294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  cinfo->src->next_input_byte = buf_vec->buffers[buf_vec->pos].data;
42141294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  cinfo->src->bytes_in_buffer = buf_vec->buffers[buf_vec->pos].len;
42241294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  ++buf_vec->pos;
42341294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  return TRUE;
42441294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org}
42541294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org
42641294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.orgvoid skip_input_data(j_decompress_ptr cinfo,
42741294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org                     long num_bytes) {  // NOLINT
42841294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  cinfo->src->next_input_byte += num_bytes;
42941294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org}
43041294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org
43141294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.orgvoid term_source(j_decompress_ptr cinfo) {
43241294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  // Nothing to do.
43341294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org}
43441294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org
43541294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org#ifdef HAVE_SETJMP
43641294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.orgvoid ErrorHandler(j_common_ptr cinfo) {
43741294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  // This is called when a jpeglib command experiences an error. Unfortunately
43841294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  // jpeglib's error handling model is not very flexible, because it expects the
43941294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  // error handler to not return--i.e., it wants the program to terminate. To
44041294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  // recover from errors we use setjmp() as shown in their example. setjmp() is
44141294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  // C's implementation for the "call with current continuation" functionality
44241294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  // seen in some functional programming languages.
44341294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  // A formatted message can be output, but is unsafe for release.
44441294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org#ifdef DEBUG
44541294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  char buf[JMSG_LENGTH_MAX];
44641294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  (*cinfo->err->format_message)(cinfo, buf);
44741294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  // ERROR: Error in jpeglib: buf
44841294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org#endif
44941294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org
450d95585fb0ec024f6abd96f7b02e0df58019d46afjohannkoenig@chromium.org  SetJmpErrorMgr* mgr = reinterpret_cast<SetJmpErrorMgr*>(cinfo->err);
45141294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  // This rewinds the call stack to the point of the corresponding setjmp()
45241294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  // and causes it to return (for a second time) with value 1.
45341294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  longjmp(mgr->setjmp_buffer, 1);
45441294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org}
45541294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org#endif
45641294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org
45741294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.orgvoid MJpegDecoder::AllocOutputBuffers(int num_outbufs) {
45841294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  if (num_outbufs != num_outbufs_) {
45941294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org    // We could perhaps optimize this case to resize the output buffers without
46041294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org    // necessarily having to delete and recreate each one, but it's not worth
46141294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org    // it.
46241294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org    DestroyOutputBuffers();
46341294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org
46441294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org    scanlines_ = new uint8** [num_outbufs];
46541294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org    scanlines_sizes_ = new int[num_outbufs];
46641294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org    databuf_ = new uint8* [num_outbufs];
46741294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org    databuf_strides_ = new int[num_outbufs];
46841294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org
46941294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org    for (int i = 0; i < num_outbufs; ++i) {
47041294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org      scanlines_[i] = NULL;
47141294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org      scanlines_sizes_[i] = 0;
47241294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org      databuf_[i] = NULL;
47341294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org      databuf_strides_[i] = 0;
47441294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org    }
47541294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org
47641294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org    num_outbufs_ = num_outbufs;
47741294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  }
47841294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org}
47941294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org
48041294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.orgvoid MJpegDecoder::DestroyOutputBuffers() {
48141294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  for (int i = 0; i < num_outbufs_; ++i) {
48241294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org    delete [] scanlines_[i];
48341294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org    delete [] databuf_[i];
48441294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  }
48541294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  delete [] scanlines_;
48641294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  delete [] databuf_;
48741294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  delete [] scanlines_sizes_;
48841294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  delete [] databuf_strides_;
48941294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  scanlines_ = NULL;
49041294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  databuf_ = NULL;
49141294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  scanlines_sizes_ = NULL;
49241294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  databuf_strides_ = NULL;
49341294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  num_outbufs_ = 0;
49441294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org}
49541294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org
49641294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org// JDCT_IFAST and do_block_smoothing improve performance substantially.
49741294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.orgLIBYUV_BOOL MJpegDecoder::StartDecode() {
49841294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  decompress_struct_->raw_data_out = TRUE;
49941294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  decompress_struct_->dct_method = JDCT_IFAST;  // JDCT_ISLOW is default
50041294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  decompress_struct_->dither_mode = JDITHER_NONE;
50141294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  // Not applicable to 'raw':
50241294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  decompress_struct_->do_fancy_upsampling = (boolean)(LIBYUV_FALSE);
50341294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  // Only for buffered mode:
50441294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  decompress_struct_->enable_2pass_quant = (boolean)(LIBYUV_FALSE);
50541294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  // Blocky but fast:
50641294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  decompress_struct_->do_block_smoothing = (boolean)(LIBYUV_FALSE);
50741294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org
50841294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  if (!jpeg_start_decompress(decompress_struct_)) {
50941294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org    // ERROR: Couldn't start JPEG decompressor";
51041294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org    return LIBYUV_FALSE;
51141294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  }
51241294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  return LIBYUV_TRUE;
51341294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org}
51441294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org
51541294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.orgLIBYUV_BOOL MJpegDecoder::FinishDecode() {
51641294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  // jpeglib considers it an error if we finish without decoding the whole
51741294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  // image, so we call "abort" rather than "finish".
51841294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  jpeg_abort_decompress(decompress_struct_);
51941294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  return LIBYUV_TRUE;
52041294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org}
52141294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org
52241294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.orgvoid MJpegDecoder::SetScanlinePointers(uint8** data) {
52341294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  for (int i = 0; i < num_outbufs_; ++i) {
52441294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org    uint8* data_i = data[i];
52541294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org    for (int j = 0; j < scanlines_sizes_[i]; ++j) {
52641294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org      scanlines_[i][j] = data_i;
52741294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org      data_i += GetComponentStride(i);
52841294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org    }
52941294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  }
53041294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org}
53141294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org
53241294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.orginline LIBYUV_BOOL MJpegDecoder::DecodeImcuRow() {
53341294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  return (unsigned int)(GetImageScanlinesPerImcuRow()) ==
53441294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org      jpeg_read_raw_data(decompress_struct_,
53541294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org                         scanlines_,
53641294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org                         GetImageScanlinesPerImcuRow());
53741294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org}
53841294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org
53941294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org// The helper function which recognizes the jpeg sub-sampling type.
54041294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.orgJpegSubsamplingType MJpegDecoder::JpegSubsamplingTypeHelper(
54141294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org    int* subsample_x, int* subsample_y, int number_of_components) {
54241294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  if (number_of_components == 3) {  // Color images.
54341294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org    if (subsample_x[0] == 1 && subsample_y[0] == 1 &&
54441294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org        subsample_x[1] == 2 && subsample_y[1] == 2 &&
54541294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org        subsample_x[2] == 2 && subsample_y[2] == 2) {
54641294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org      return kJpegYuv420;
54741294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org    } else if (subsample_x[0] == 1 && subsample_y[0] == 1 &&
54841294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org        subsample_x[1] == 2 && subsample_y[1] == 1 &&
54941294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org        subsample_x[2] == 2 && subsample_y[2] == 1) {
55041294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org      return kJpegYuv422;
55141294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org    } else if (subsample_x[0] == 1 && subsample_y[0] == 1 &&
55241294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org        subsample_x[1] == 1 && subsample_y[1] == 1 &&
55341294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org        subsample_x[2] == 1 && subsample_y[2] == 1) {
55441294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org      return kJpegYuv444;
55541294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org    }
55641294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  } else if (number_of_components == 1) {  // Grey-scale images.
55741294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org    if (subsample_x[0] == 1 && subsample_y[0] == 1) {
55841294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org      return kJpegYuv400;
55941294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org    }
56041294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  }
56141294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org  return kJpegUnknown;
56241294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org}
56341294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org
56441294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org}  // namespace libyuv
56541294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org#endif  // HAVE_JPEG
56641294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org
567