169fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com/*
2b0c97975894a5eebebf9d93147cdd941a3accb63fbarchard@google.com *  Copyright 2012 The LibYuv Project Authors. All rights reserved.
369fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com *
469fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com *  Use of this source code is governed by a BSD-style license
569fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com *  that can be found in the LICENSE file in the root of the source
669fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com *  tree. An additional intellectual property rights grant can be found
7cde587092fef0dbed2c35602f30b79e7b892e766fbarchard@google.com *  in the file PATENTS. All contributing project authors may
869fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com *  be found in the AUTHORS file in the root of the source tree.
969fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com */
1069fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com
1169fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com#include "libyuv/mjpeg_decoder.h"
1269fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com
1364ce0ab544591b1e26ae6d276932cacdb8137071fbarchard@google.com#ifdef HAVE_JPEG
1469fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com#include <assert.h>
152c8108e6c2c6fa0c62670a70be7ef6f59cf03848fbarchard@google.com
162c8108e6c2c6fa0c62670a70be7ef6f59cf03848fbarchard@google.com#if !defined(__pnacl__) && !defined(__CLR_VER) && !defined(COVERAGE_ENABLED) &&\
172c8108e6c2c6fa0c62670a70be7ef6f59cf03848fbarchard@google.com    !defined(TARGET_IPHONE_SIMULATOR)
18d7c7bfac57ce1775d6424865d8d4ec8b278070bafbarchard@google.com// Must be included before jpeglib.
1969fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com#include <setjmp.h>
20133adc46470722b24fdac30d7537d5009e61ef0cfbarchard@google.com#define HAVE_SETJMP
21133adc46470722b24fdac30d7537d5009e61ef0cfbarchard@google.com#endif
22d7c7bfac57ce1775d6424865d8d4ec8b278070bafbarchard@google.comstruct FILE;  // For jpeglib.h.
23ae997018e5c5f909e5400664052cb71ab097aa35fbarchard@google.com
24ae997018e5c5f909e5400664052cb71ab097aa35fbarchard@google.com// C++ build requires extern C for jpeg internals.
25ae997018e5c5f909e5400664052cb71ab097aa35fbarchard@google.com#ifdef __cplusplus
26ae997018e5c5f909e5400664052cb71ab097aa35fbarchard@google.comextern "C" {
27ae997018e5c5f909e5400664052cb71ab097aa35fbarchard@google.com#endif
28ae997018e5c5f909e5400664052cb71ab097aa35fbarchard@google.com
2969fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com#include <jpeglib.h>
3069fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com
31ae997018e5c5f909e5400664052cb71ab097aa35fbarchard@google.com#ifdef __cplusplus
32ae997018e5c5f909e5400664052cb71ab097aa35fbarchard@google.com}  // extern "C"
33ae997018e5c5f909e5400664052cb71ab097aa35fbarchard@google.com#endif
34ae997018e5c5f909e5400664052cb71ab097aa35fbarchard@google.com
35d7c7bfac57ce1775d6424865d8d4ec8b278070bafbarchard@google.com#include "libyuv/planar_functions.h"  // For CopyPlane().
36e2a55aff59ffa81d553a31c0f0b735f9baa40749fbarchard@google.com
3769fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.comnamespace libyuv {
3869fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com
39133adc46470722b24fdac30d7537d5009e61ef0cfbarchard@google.com#ifdef HAVE_SETJMP
4069fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.comstruct SetJmpErrorMgr {
4169fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  jpeg_error_mgr base;  // Must be at the top
4269fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  jmp_buf setjmp_buffer;
4369fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com};
44133adc46470722b24fdac30d7537d5009e61ef0cfbarchard@google.com#endif
4569fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com
4669fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.comconst int MJpegDecoder::kColorSpaceUnknown = JCS_UNKNOWN;
4769fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.comconst int MJpegDecoder::kColorSpaceGrayscale = JCS_GRAYSCALE;
4869fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.comconst int MJpegDecoder::kColorSpaceRgb = JCS_RGB;
4969fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.comconst int MJpegDecoder::kColorSpaceYCbCr = JCS_YCbCr;
5069fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.comconst int MJpegDecoder::kColorSpaceCMYK = JCS_CMYK;
5169fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.comconst int MJpegDecoder::kColorSpaceYCCK = JCS_YCCK;
5269fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com
538b857c0ac6f0e8cb0fc0b9410ea0d15b3afda4abfbarchard@google.com// Methods that are passed to jpeglib.
548b857c0ac6f0e8cb0fc0b9410ea0d15b3afda4abfbarchard@google.comboolean fill_input_buffer(jpeg_decompress_struct* cinfo);
558b857c0ac6f0e8cb0fc0b9410ea0d15b3afda4abfbarchard@google.comvoid init_source(jpeg_decompress_struct* cinfo);
568b857c0ac6f0e8cb0fc0b9410ea0d15b3afda4abfbarchard@google.comvoid skip_input_data(jpeg_decompress_struct* cinfo,
578b857c0ac6f0e8cb0fc0b9410ea0d15b3afda4abfbarchard@google.com                     long num_bytes);  // NOLINT
588b857c0ac6f0e8cb0fc0b9410ea0d15b3afda4abfbarchard@google.comvoid term_source(jpeg_decompress_struct* cinfo);
598b857c0ac6f0e8cb0fc0b9410ea0d15b3afda4abfbarchard@google.comvoid ErrorHandler(jpeg_common_struct* cinfo);
608b857c0ac6f0e8cb0fc0b9410ea0d15b3afda4abfbarchard@google.com
6169fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.comMJpegDecoder::MJpegDecoder()
62db73518b19f73a3975b4fd58e9d17c8215a39d98fbarchard@google.com    : has_scanline_padding_(LIBYUV_FALSE),
6369fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com      num_outbufs_(0),
6469fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com      scanlines_(NULL),
6569fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com      scanlines_sizes_(NULL),
6669fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com      databuf_(NULL),
6769fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com      databuf_strides_(NULL) {
68e2a55aff59ffa81d553a31c0f0b735f9baa40749fbarchard@google.com  decompress_struct_ = new jpeg_decompress_struct;
69e2a55aff59ffa81d553a31c0f0b735f9baa40749fbarchard@google.com  source_mgr_ = new jpeg_source_mgr;
70133adc46470722b24fdac30d7537d5009e61ef0cfbarchard@google.com#ifdef HAVE_SETJMP
71e2a55aff59ffa81d553a31c0f0b735f9baa40749fbarchard@google.com  error_mgr_ = new SetJmpErrorMgr;
7269fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  decompress_struct_->err = jpeg_std_error(&error_mgr_->base);
7369fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  // Override standard exit()-based error handler.
7469fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  error_mgr_->base.error_exit = &ErrorHandler;
75133adc46470722b24fdac30d7537d5009e61ef0cfbarchard@google.com#endif
7669fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  decompress_struct_->client_data = NULL;
7769fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  source_mgr_->init_source = &init_source;
7869fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  source_mgr_->fill_input_buffer = &fill_input_buffer;
7969fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  source_mgr_->skip_input_data = &skip_input_data;
8069fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  source_mgr_->resync_to_restart = &jpeg_resync_to_restart;
8169fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  source_mgr_->term_source = &term_source;
82e2a55aff59ffa81d553a31c0f0b735f9baa40749fbarchard@google.com  jpeg_create_decompress(decompress_struct_);
83e2a55aff59ffa81d553a31c0f0b735f9baa40749fbarchard@google.com  decompress_struct_->src = source_mgr_;
8469fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  buf_vec_.buffers = &buf_;
8569fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  buf_vec_.len = 1;
8669fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com}
8769fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com
8869fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.comMJpegDecoder::~MJpegDecoder() {
89e2a55aff59ffa81d553a31c0f0b735f9baa40749fbarchard@google.com  jpeg_destroy_decompress(decompress_struct_);
90e2a55aff59ffa81d553a31c0f0b735f9baa40749fbarchard@google.com  delete decompress_struct_;
91e2a55aff59ffa81d553a31c0f0b735f9baa40749fbarchard@google.com  delete source_mgr_;
92133adc46470722b24fdac30d7537d5009e61ef0cfbarchard@google.com#ifdef HAVE_SETJMP
93e2a55aff59ffa81d553a31c0f0b735f9baa40749fbarchard@google.com  delete error_mgr_;
94133adc46470722b24fdac30d7537d5009e61ef0cfbarchard@google.com#endif
9569fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  DestroyOutputBuffers();
9669fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com}
9769fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com
98db73518b19f73a3975b4fd58e9d17c8215a39d98fbarchard@google.comLIBYUV_BOOL MJpegDecoder::LoadFrame(const uint8* src, size_t src_len) {
9969fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  if (!ValidateJpeg(src, src_len)) {
100db73518b19f73a3975b4fd58e9d17c8215a39d98fbarchard@google.com    return LIBYUV_FALSE;
10169fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  }
10269fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com
10369fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  buf_.data = src;
104a1f5254a955c5c32484b56822596a4e3368e8eb7fbarchard@google.com  buf_.len = (int)(src_len);
10569fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  buf_vec_.pos = 0;
10669fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  decompress_struct_->client_data = &buf_vec_;
107133adc46470722b24fdac30d7537d5009e61ef0cfbarchard@google.com#ifdef HAVE_SETJMP
10869fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  if (setjmp(error_mgr_->setjmp_buffer)) {
10969fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com    // We called jpeg_read_header, it experienced an error, and we called
11069fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com    // longjmp() and rewound the stack to here. Return error.
111db73518b19f73a3975b4fd58e9d17c8215a39d98fbarchard@google.com    return LIBYUV_FALSE;
11269fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  }
113133adc46470722b24fdac30d7537d5009e61ef0cfbarchard@google.com#endif
114e2a55aff59ffa81d553a31c0f0b735f9baa40749fbarchard@google.com  if (jpeg_read_header(decompress_struct_, TRUE) != JPEG_HEADER_OK) {
11569fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com    // ERROR: Bad MJPEG header
116db73518b19f73a3975b4fd58e9d17c8215a39d98fbarchard@google.com    return LIBYUV_FALSE;
11769fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  }
11869fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  AllocOutputBuffers(GetNumComponents());
11969fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  for (int i = 0; i < num_outbufs_; ++i) {
12069fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com    int scanlines_size = GetComponentScanlinesPerImcuRow(i);
12169fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com    if (scanlines_sizes_[i] != scanlines_size) {
12269fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com      if (scanlines_[i]) {
12369fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com        delete scanlines_[i];
12469fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com      }
12569fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com      scanlines_[i] = new uint8* [scanlines_size];
12669fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com      scanlines_sizes_[i] = scanlines_size;
12769fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com    }
12869fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com
12969fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com    // We allocate padding for the final scanline to pad it up to DCTSIZE bytes
13069fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com    // to avoid memory errors, since jpeglib only reads full MCUs blocks. For
13169fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com    // the preceding scanlines, the padding is not needed/wanted because the
13269fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com    // following addresses will already be valid (they are the initial bytes of
13369fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com    // the next scanline) and will be overwritten when jpeglib writes out that
13469fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com    // next scanline.
13569fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com    int databuf_stride = GetComponentStride(i);
13669fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com    int databuf_size = scanlines_size * databuf_stride;
13769fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com    if (databuf_strides_[i] != databuf_stride) {
13869fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com      if (databuf_[i]) {
13969fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com        delete databuf_[i];
14069fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com      }
14169fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com      databuf_[i] = new uint8[databuf_size];
14269fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com      databuf_strides_[i] = databuf_stride;
14369fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com    }
14469fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com
14569fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com    if (GetComponentStride(i) != GetComponentWidth(i)) {
146db73518b19f73a3975b4fd58e9d17c8215a39d98fbarchard@google.com      has_scanline_padding_ = LIBYUV_TRUE;
14769fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com    }
14869fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  }
149db73518b19f73a3975b4fd58e9d17c8215a39d98fbarchard@google.com  return LIBYUV_TRUE;
15069fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com}
15169fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com
15269fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.comstatic int DivideAndRoundUp(int numerator, int denominator) {
15369fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  return (numerator + denominator - 1) / denominator;
15469fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com}
15569fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com
15669fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.comstatic int DivideAndRoundDown(int numerator, int denominator) {
15769fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  return numerator / denominator;
15869fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com}
15969fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com
16069fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com// Returns width of the last loaded frame.
16169fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.comint MJpegDecoder::GetWidth() {
16269fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  return decompress_struct_->image_width;
16369fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com}
16469fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com
16569fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com// Returns height of the last loaded frame.
16669fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.comint MJpegDecoder::GetHeight() {
16769fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  return decompress_struct_->image_height;
16869fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com}
16969fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com
17069fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com// Returns format of the last loaded frame. The return value is one of the
17169fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com// kColorSpace* constants.
17269fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.comint MJpegDecoder::GetColorSpace() {
17369fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  return decompress_struct_->jpeg_color_space;
17469fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com}
17569fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com
17669fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com// Number of color components in the color space.
17769fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.comint MJpegDecoder::GetNumComponents() {
17869fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  return decompress_struct_->num_components;
17969fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com}
18069fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com
18169fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com// Sample factors of the n-th component.
18269fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.comint MJpegDecoder::GetHorizSampFactor(int component) {
18369fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  return decompress_struct_->comp_info[component].h_samp_factor;
18469fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com}
18569fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com
18669fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.comint MJpegDecoder::GetVertSampFactor(int component) {
18769fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  return decompress_struct_->comp_info[component].v_samp_factor;
18869fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com}
18969fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com
19069fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.comint MJpegDecoder::GetHorizSubSampFactor(int component) {
19169fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  return decompress_struct_->max_h_samp_factor /
19269fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com      GetHorizSampFactor(component);
19369fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com}
19469fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com
19569fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.comint MJpegDecoder::GetVertSubSampFactor(int component) {
19669fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  return decompress_struct_->max_v_samp_factor /
19769fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com      GetVertSampFactor(component);
19869fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com}
19969fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com
20069fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.comint MJpegDecoder::GetImageScanlinesPerImcuRow() {
20169fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  return decompress_struct_->max_v_samp_factor * DCTSIZE;
20269fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com}
20369fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com
20469fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.comint MJpegDecoder::GetComponentScanlinesPerImcuRow(int component) {
20569fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  int vs = GetVertSubSampFactor(component);
20669fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  return DivideAndRoundUp(GetImageScanlinesPerImcuRow(), vs);
20769fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com}
20869fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com
20969fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.comint MJpegDecoder::GetComponentWidth(int component) {
21069fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  int hs = GetHorizSubSampFactor(component);
21169fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  return DivideAndRoundUp(GetWidth(), hs);
21269fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com}
21369fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com
21469fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.comint MJpegDecoder::GetComponentHeight(int component) {
21569fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  int vs = GetVertSubSampFactor(component);
21669fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  return DivideAndRoundUp(GetHeight(), vs);
21769fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com}
21869fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com
21969fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com// Get width in bytes padded out to a multiple of DCTSIZE
22069fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.comint MJpegDecoder::GetComponentStride(int component) {
22169fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  return (GetComponentWidth(component) + DCTSIZE - 1) & ~(DCTSIZE - 1);
22269fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com}
22369fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com
22469fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.comint MJpegDecoder::GetComponentSize(int component) {
22569fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  return GetComponentWidth(component) * GetComponentHeight(component);
22669fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com}
22769fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com
228db73518b19f73a3975b4fd58e9d17c8215a39d98fbarchard@google.comLIBYUV_BOOL MJpegDecoder::UnloadFrame() {
229133adc46470722b24fdac30d7537d5009e61ef0cfbarchard@google.com#ifdef HAVE_SETJMP
23069fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  if (setjmp(error_mgr_->setjmp_buffer)) {
23169fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com    // We called jpeg_abort_decompress, it experienced an error, and we called
23269fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com    // longjmp() and rewound the stack to here. Return error.
233db73518b19f73a3975b4fd58e9d17c8215a39d98fbarchard@google.com    return LIBYUV_FALSE;
23469fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  }
235133adc46470722b24fdac30d7537d5009e61ef0cfbarchard@google.com#endif
236e2a55aff59ffa81d553a31c0f0b735f9baa40749fbarchard@google.com  jpeg_abort_decompress(decompress_struct_);
237db73518b19f73a3975b4fd58e9d17c8215a39d98fbarchard@google.com  return LIBYUV_TRUE;
23869fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com}
23969fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com
24069fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com// TODO(fbarchard): Allow rectangle to be specified: x, y, width, height.
241db73518b19f73a3975b4fd58e9d17c8215a39d98fbarchard@google.comLIBYUV_BOOL MJpegDecoder::DecodeToBuffers(
24269fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com    uint8** planes, int dst_width, int dst_height) {
24369fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  if (dst_width != GetWidth() ||
24469fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com      dst_height > GetHeight()) {
24569fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com    // ERROR: Bad dimensions
246db73518b19f73a3975b4fd58e9d17c8215a39d98fbarchard@google.com    return LIBYUV_FALSE;
24769fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  }
248133adc46470722b24fdac30d7537d5009e61ef0cfbarchard@google.com#ifdef HAVE_SETJMP
24969fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  if (setjmp(error_mgr_->setjmp_buffer)) {
25069fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com    // We called into jpeglib, it experienced an error sometime during this
25169fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com    // function call, and we called longjmp() and rewound the stack to here.
25269fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com    // Return error.
253db73518b19f73a3975b4fd58e9d17c8215a39d98fbarchard@google.com    return LIBYUV_FALSE;
25469fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  }
255133adc46470722b24fdac30d7537d5009e61ef0cfbarchard@google.com#endif
25669fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  if (!StartDecode()) {
257db73518b19f73a3975b4fd58e9d17c8215a39d98fbarchard@google.com    return LIBYUV_FALSE;
25869fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  }
25969fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  SetScanlinePointers(databuf_);
26069fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  int lines_left = dst_height;
26169fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  // Compute amount of lines to skip to implement vertical crop.
26269fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  // TODO(fbarchard): Ensure skip is a multiple of maximum component
26369fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  // subsample. ie 2
26469fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  int skip = (GetHeight() - dst_height) / 2;
26569fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  if (skip > 0) {
26669fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com    // There is no API to skip lines in the output data, so we read them
26769fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com    // into the temp buffer.
26869fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com    while (skip >= GetImageScanlinesPerImcuRow()) {
26969fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com      if (!DecodeImcuRow()) {
27069fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com        FinishDecode();
271db73518b19f73a3975b4fd58e9d17c8215a39d98fbarchard@google.com        return LIBYUV_FALSE;
27269fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com      }
27369fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com      skip -= GetImageScanlinesPerImcuRow();
27469fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com    }
27569fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com    if (skip > 0) {
27669fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com      // Have a partial iMCU row left over to skip. Must read it and then
27769fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com      // copy the parts we want into the destination.
27869fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com      if (!DecodeImcuRow()) {
27969fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com        FinishDecode();
280db73518b19f73a3975b4fd58e9d17c8215a39d98fbarchard@google.com        return LIBYUV_FALSE;
28169fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com      }
28269fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com      for (int i = 0; i < num_outbufs_; ++i) {
28369fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com        // TODO(fbarchard): Compute skip to avoid this
28469fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com        assert(skip % GetVertSubSampFactor(i) == 0);
285e2a55aff59ffa81d553a31c0f0b735f9baa40749fbarchard@google.com        int rows_to_skip =
28669fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com            DivideAndRoundDown(skip, GetVertSubSampFactor(i));
28769fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com        int scanlines_to_copy = GetComponentScanlinesPerImcuRow(i) -
288e2a55aff59ffa81d553a31c0f0b735f9baa40749fbarchard@google.com                                rows_to_skip;
289e2a55aff59ffa81d553a31c0f0b735f9baa40749fbarchard@google.com        int data_to_skip = rows_to_skip * GetComponentStride(i);
2909e4e12352a4b390632986e3075e5cfa5cc08865dfbarchard@google.com        CopyPlane(databuf_[i] + data_to_skip, GetComponentStride(i),
2919e4e12352a4b390632986e3075e5cfa5cc08865dfbarchard@google.com                  planes[i], GetComponentWidth(i),
2929e4e12352a4b390632986e3075e5cfa5cc08865dfbarchard@google.com                  GetComponentWidth(i), scanlines_to_copy);
29369fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com        planes[i] += scanlines_to_copy * GetComponentWidth(i);
29469fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com      }
29569fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com      lines_left -= (GetImageScanlinesPerImcuRow() - skip);
29669fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com    }
29769fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  }
29869fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com
29969fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  // Read full MCUs but cropped horizontally
30069fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  for (; lines_left > GetImageScanlinesPerImcuRow();
30169fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com         lines_left -= GetImageScanlinesPerImcuRow()) {
30269fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com    if (!DecodeImcuRow()) {
30369fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com      FinishDecode();
304db73518b19f73a3975b4fd58e9d17c8215a39d98fbarchard@google.com      return LIBYUV_FALSE;
30569fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com    }
30669fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com    for (int i = 0; i < num_outbufs_; ++i) {
30769fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com      int scanlines_to_copy = GetComponentScanlinesPerImcuRow(i);
3089e4e12352a4b390632986e3075e5cfa5cc08865dfbarchard@google.com      CopyPlane(databuf_[i], GetComponentStride(i),
3099e4e12352a4b390632986e3075e5cfa5cc08865dfbarchard@google.com                planes[i], GetComponentWidth(i),
3109e4e12352a4b390632986e3075e5cfa5cc08865dfbarchard@google.com                GetComponentWidth(i), scanlines_to_copy);
31169fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com      planes[i] += scanlines_to_copy * GetComponentWidth(i);
31269fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com    }
31369fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  }
31469fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com
31569fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  if (lines_left > 0) {
31669fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com    // Have a partial iMCU row left over to decode.
31769fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com    if (!DecodeImcuRow()) {
31869fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com      FinishDecode();
319db73518b19f73a3975b4fd58e9d17c8215a39d98fbarchard@google.com      return LIBYUV_FALSE;
32069fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com    }
32169fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com    for (int i = 0; i < num_outbufs_; ++i) {
32269fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com      int scanlines_to_copy =
32369fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com          DivideAndRoundUp(lines_left, GetVertSubSampFactor(i));
3249e4e12352a4b390632986e3075e5cfa5cc08865dfbarchard@google.com      CopyPlane(databuf_[i], GetComponentStride(i),
3259e4e12352a4b390632986e3075e5cfa5cc08865dfbarchard@google.com                planes[i], GetComponentWidth(i),
3269e4e12352a4b390632986e3075e5cfa5cc08865dfbarchard@google.com                GetComponentWidth(i), scanlines_to_copy);
32769fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com      planes[i] += scanlines_to_copy * GetComponentWidth(i);
32869fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com    }
32969fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  }
33069fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  return FinishDecode();
33169fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com}
33269fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com
333db73518b19f73a3975b4fd58e9d17c8215a39d98fbarchard@google.comLIBYUV_BOOL MJpegDecoder::DecodeToCallback(CallbackFunction fn, void* opaque,
33469fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com    int dst_width, int dst_height) {
33569fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  if (dst_width != GetWidth() ||
33669fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com      dst_height > GetHeight()) {
33769fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com    // ERROR: Bad dimensions
338db73518b19f73a3975b4fd58e9d17c8215a39d98fbarchard@google.com    return LIBYUV_FALSE;
33969fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  }
340133adc46470722b24fdac30d7537d5009e61ef0cfbarchard@google.com#ifdef HAVE_SETJMP
34169fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  if (setjmp(error_mgr_->setjmp_buffer)) {
34269fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com    // We called into jpeglib, it experienced an error sometime during this
34369fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com    // function call, and we called longjmp() and rewound the stack to here.
34469fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com    // Return error.
345db73518b19f73a3975b4fd58e9d17c8215a39d98fbarchard@google.com    return LIBYUV_FALSE;
34669fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  }
347133adc46470722b24fdac30d7537d5009e61ef0cfbarchard@google.com#endif
34869fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  if (!StartDecode()) {
349db73518b19f73a3975b4fd58e9d17c8215a39d98fbarchard@google.com    return LIBYUV_FALSE;
35069fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  }
35169fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  SetScanlinePointers(databuf_);
35269fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  int lines_left = dst_height;
35369fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  // TODO(fbarchard): Compute amount of lines to skip to implement vertical crop
35469fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  int skip = (GetHeight() - dst_height) / 2;
35569fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  if (skip > 0) {
35669fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com    while (skip >= GetImageScanlinesPerImcuRow()) {
35769fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com      if (!DecodeImcuRow()) {
35869fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com        FinishDecode();
359db73518b19f73a3975b4fd58e9d17c8215a39d98fbarchard@google.com        return LIBYUV_FALSE;
36069fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com      }
36169fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com      skip -= GetImageScanlinesPerImcuRow();
36269fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com    }
36369fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com    if (skip > 0) {
36469fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com      // Have a partial iMCU row left over to skip.
36569fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com      if (!DecodeImcuRow()) {
36669fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com        FinishDecode();
367db73518b19f73a3975b4fd58e9d17c8215a39d98fbarchard@google.com        return LIBYUV_FALSE;
36869fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com      }
36969fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com      for (int i = 0; i < num_outbufs_; ++i) {
37069fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com        // TODO(fbarchard): Compute skip to avoid this
37169fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com        assert(skip % GetVertSubSampFactor(i) == 0);
372e2a55aff59ffa81d553a31c0f0b735f9baa40749fbarchard@google.com        int rows_to_skip = DivideAndRoundDown(skip, GetVertSubSampFactor(i));
373e2a55aff59ffa81d553a31c0f0b735f9baa40749fbarchard@google.com        int data_to_skip = rows_to_skip * GetComponentStride(i);
37469fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com        // Change our own data buffer pointers so we can pass them to the
37569fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com        // callback.
37669fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com        databuf_[i] += data_to_skip;
37769fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com      }
37869fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com      int scanlines_to_copy = GetImageScanlinesPerImcuRow() - skip;
37969fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com      (*fn)(opaque, databuf_, databuf_strides_, scanlines_to_copy);
38069fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com      // Now change them back.
38169fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com      for (int i = 0; i < num_outbufs_; ++i) {
382e2a55aff59ffa81d553a31c0f0b735f9baa40749fbarchard@google.com        int rows_to_skip = DivideAndRoundDown(skip, GetVertSubSampFactor(i));
383e2a55aff59ffa81d553a31c0f0b735f9baa40749fbarchard@google.com        int data_to_skip = rows_to_skip * GetComponentStride(i);
38469fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com        databuf_[i] -= data_to_skip;
38569fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com      }
38669fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com      lines_left -= scanlines_to_copy;
38769fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com    }
38869fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  }
38969fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  // Read full MCUs until we get to the crop point.
39069fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  for (; lines_left >= GetImageScanlinesPerImcuRow();
39169fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com         lines_left -= GetImageScanlinesPerImcuRow()) {
39269fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com    if (!DecodeImcuRow()) {
39369fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com      FinishDecode();
394db73518b19f73a3975b4fd58e9d17c8215a39d98fbarchard@google.com      return LIBYUV_FALSE;
39569fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com    }
39669fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com    (*fn)(opaque, databuf_, databuf_strides_, GetImageScanlinesPerImcuRow());
39769fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  }
39869fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  if (lines_left > 0) {
39969fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com    // Have a partial iMCU row left over to decode.
40069fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com    if (!DecodeImcuRow()) {
40169fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com      FinishDecode();
402db73518b19f73a3975b4fd58e9d17c8215a39d98fbarchard@google.com      return LIBYUV_FALSE;
40369fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com    }
40469fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com    (*fn)(opaque, databuf_, databuf_strides_, lines_left);
40569fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  }
40669fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  return FinishDecode();
40769fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com}
40869fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com
4098b857c0ac6f0e8cb0fc0b9410ea0d15b3afda4abfbarchard@google.comvoid init_source(j_decompress_ptr cinfo) {
41069fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  fill_input_buffer(cinfo);
41169fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com}
41269fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com
4138b857c0ac6f0e8cb0fc0b9410ea0d15b3afda4abfbarchard@google.comboolean fill_input_buffer(j_decompress_ptr cinfo) {
414a1f5254a955c5c32484b56822596a4e3368e8eb7fbarchard@google.com  BufferVector* buf_vec = (BufferVector*)(cinfo->client_data);
41569fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  if (buf_vec->pos >= buf_vec->len) {
41669fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com    assert(0 && "No more data");
41769fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com    // ERROR: No more data
41869fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com    return FALSE;
41969fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  }
42069fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  cinfo->src->next_input_byte = buf_vec->buffers[buf_vec->pos].data;
42169fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  cinfo->src->bytes_in_buffer = buf_vec->buffers[buf_vec->pos].len;
42269fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  ++buf_vec->pos;
42369fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  return TRUE;
42469fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com}
42569fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com
4268b857c0ac6f0e8cb0fc0b9410ea0d15b3afda4abfbarchard@google.comvoid skip_input_data(j_decompress_ptr cinfo,
4278b857c0ac6f0e8cb0fc0b9410ea0d15b3afda4abfbarchard@google.com                     long num_bytes) {  // NOLINT
42869fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  cinfo->src->next_input_byte += num_bytes;
42969fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com}
43069fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com
4318b857c0ac6f0e8cb0fc0b9410ea0d15b3afda4abfbarchard@google.comvoid term_source(j_decompress_ptr cinfo) {
43269fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  // Nothing to do.
43369fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com}
43469fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com
435133adc46470722b24fdac30d7537d5009e61ef0cfbarchard@google.com#ifdef HAVE_SETJMP
4368b857c0ac6f0e8cb0fc0b9410ea0d15b3afda4abfbarchard@google.comvoid ErrorHandler(j_common_ptr cinfo) {
43769fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  // This is called when a jpeglib command experiences an error. Unfortunately
43869fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  // jpeglib's error handling model is not very flexible, because it expects the
43969fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  // error handler to not return--i.e., it wants the program to terminate. To
44069fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  // recover from errors we use setjmp() as shown in their example. setjmp() is
44169fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  // C's implementation for the "call with current continuation" functionality
44269fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  // seen in some functional programming languages.
4436368c10c9c11e7151c9b3c727c18d25c36df6cc6fbarchard@google.com  // A formatted message can be output, but is unsafe for release.
4446368c10c9c11e7151c9b3c727c18d25c36df6cc6fbarchard@google.com#ifdef DEBUG
44569fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  char buf[JMSG_LENGTH_MAX];
44669fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  (*cinfo->err->format_message)(cinfo, buf);
44769fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  // ERROR: Error in jpeglib: buf
4486368c10c9c11e7151c9b3c727c18d25c36df6cc6fbarchard@google.com#endif
44969fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com
450a1f5254a955c5c32484b56822596a4e3368e8eb7fbarchard@google.com  SetJmpErrorMgr* mgr = (SetJmpErrorMgr*)(cinfo->err);
45169fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  // This rewinds the call stack to the point of the corresponding setjmp()
45269fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  // and causes it to return (for a second time) with value 1.
45369fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  longjmp(mgr->setjmp_buffer, 1);
45469fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com}
455133adc46470722b24fdac30d7537d5009e61ef0cfbarchard@google.com#endif
45669fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com
45769fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.comvoid MJpegDecoder::AllocOutputBuffers(int num_outbufs) {
45869fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  if (num_outbufs != num_outbufs_) {
45969fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com    // We could perhaps optimize this case to resize the output buffers without
46069fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com    // necessarily having to delete and recreate each one, but it's not worth
46169fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com    // it.
46269fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com    DestroyOutputBuffers();
46369fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com
46469fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com    scanlines_ = new uint8** [num_outbufs];
46569fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com    scanlines_sizes_ = new int[num_outbufs];
46669fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com    databuf_ = new uint8* [num_outbufs];
46769fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com    databuf_strides_ = new int[num_outbufs];
46869fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com
46969fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com    for (int i = 0; i < num_outbufs; ++i) {
47069fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com      scanlines_[i] = NULL;
47169fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com      scanlines_sizes_[i] = 0;
47269fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com      databuf_[i] = NULL;
47369fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com      databuf_strides_[i] = 0;
47469fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com    }
47569fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com
47669fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com    num_outbufs_ = num_outbufs;
47769fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  }
47869fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com}
47969fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com
48069fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.comvoid MJpegDecoder::DestroyOutputBuffers() {
48169fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  for (int i = 0; i < num_outbufs_; ++i) {
48269fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com    delete [] scanlines_[i];
48369fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com    delete [] databuf_[i];
48469fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  }
48569fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  delete [] scanlines_;
48669fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  delete [] databuf_;
48769fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  delete [] scanlines_sizes_;
48869fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  delete [] databuf_strides_;
48969fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  scanlines_ = NULL;
49069fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  databuf_ = NULL;
49169fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  scanlines_sizes_ = NULL;
49269fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  databuf_strides_ = NULL;
49369fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  num_outbufs_ = 0;
49469fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com}
49569fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com
49669fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com// JDCT_IFAST and do_block_smoothing improve performance substantially.
497db73518b19f73a3975b4fd58e9d17c8215a39d98fbarchard@google.comLIBYUV_BOOL MJpegDecoder::StartDecode() {
49869fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  decompress_struct_->raw_data_out = TRUE;
49969fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  decompress_struct_->dct_method = JDCT_IFAST;  // JDCT_ISLOW is default
50069fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  decompress_struct_->dither_mode = JDITHER_NONE;
501db73518b19f73a3975b4fd58e9d17c8215a39d98fbarchard@google.com  // Not applicable to 'raw':
5028b857c0ac6f0e8cb0fc0b9410ea0d15b3afda4abfbarchard@google.com  decompress_struct_->do_fancy_upsampling = (boolean)(LIBYUV_FALSE);
503db73518b19f73a3975b4fd58e9d17c8215a39d98fbarchard@google.com  // Only for buffered mode:
5048b857c0ac6f0e8cb0fc0b9410ea0d15b3afda4abfbarchard@google.com  decompress_struct_->enable_2pass_quant = (boolean)(LIBYUV_FALSE);
505db73518b19f73a3975b4fd58e9d17c8215a39d98fbarchard@google.com  // Blocky but fast:
5068b857c0ac6f0e8cb0fc0b9410ea0d15b3afda4abfbarchard@google.com  decompress_struct_->do_block_smoothing = (boolean)(LIBYUV_FALSE);
50769fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com
508e2a55aff59ffa81d553a31c0f0b735f9baa40749fbarchard@google.com  if (!jpeg_start_decompress(decompress_struct_)) {
50969fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com    // ERROR: Couldn't start JPEG decompressor";
510db73518b19f73a3975b4fd58e9d17c8215a39d98fbarchard@google.com    return LIBYUV_FALSE;
51169fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  }
512db73518b19f73a3975b4fd58e9d17c8215a39d98fbarchard@google.com  return LIBYUV_TRUE;
51369fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com}
51469fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com
515db73518b19f73a3975b4fd58e9d17c8215a39d98fbarchard@google.comLIBYUV_BOOL MJpegDecoder::FinishDecode() {
51669fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  // jpeglib considers it an error if we finish without decoding the whole
51769fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  // image, so we call "abort" rather than "finish".
518e2a55aff59ffa81d553a31c0f0b735f9baa40749fbarchard@google.com  jpeg_abort_decompress(decompress_struct_);
519db73518b19f73a3975b4fd58e9d17c8215a39d98fbarchard@google.com  return LIBYUV_TRUE;
52069fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com}
52169fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com
52269fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.comvoid MJpegDecoder::SetScanlinePointers(uint8** data) {
52369fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  for (int i = 0; i < num_outbufs_; ++i) {
52469fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com    uint8* data_i = data[i];
52569fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com    for (int j = 0; j < scanlines_sizes_[i]; ++j) {
52669fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com      scanlines_[i][j] = data_i;
52769fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com      data_i += GetComponentStride(i);
52869fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com    }
52969fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  }
53069fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com}
53169fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com
532db73518b19f73a3975b4fd58e9d17c8215a39d98fbarchard@google.cominline LIBYUV_BOOL MJpegDecoder::DecodeImcuRow() {
533a1f5254a955c5c32484b56822596a4e3368e8eb7fbarchard@google.com  return (unsigned int)(GetImageScanlinesPerImcuRow()) ==
534e2a55aff59ffa81d553a31c0f0b735f9baa40749fbarchard@google.com      jpeg_read_raw_data(decompress_struct_,
53569fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com                         scanlines_,
53669fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com                         GetImageScanlinesPerImcuRow());
53769fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com}
53869fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com
53969fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com// The helper function which recognizes the jpeg sub-sampling type.
54069fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.comJpegSubsamplingType MJpegDecoder::JpegSubsamplingTypeHelper(
54169fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com    int* subsample_x, int* subsample_y, int number_of_components) {
54269fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  if (number_of_components == 3) {  // Color images.
54369fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com    if (subsample_x[0] == 1 && subsample_y[0] == 1 &&
54469fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com        subsample_x[1] == 2 && subsample_y[1] == 2 &&
54569fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com        subsample_x[2] == 2 && subsample_y[2] == 2) {
54669fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com      return kJpegYuv420;
54769fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com    } else if (subsample_x[0] == 1 && subsample_y[0] == 1 &&
54869fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com        subsample_x[1] == 2 && subsample_y[1] == 1 &&
54969fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com        subsample_x[2] == 2 && subsample_y[2] == 1) {
55069fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com      return kJpegYuv422;
55169fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com    } else if (subsample_x[0] == 1 && subsample_y[0] == 1 &&
55269fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com        subsample_x[1] == 1 && subsample_y[1] == 1 &&
55369fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com        subsample_x[2] == 1 && subsample_y[2] == 1) {
55469fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com      return kJpegYuv444;
55569fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com    }
55669fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  } else if (number_of_components == 1) {  // Grey-scale images.
55769fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com    if (subsample_x[0] == 1 && subsample_y[0] == 1) {
55869fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com      return kJpegYuv400;
55969fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com    }
56069fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  }
56169fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com  return kJpegUnknown;
56269fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com}
56369fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com
56469fe6bd1ff8234b3535a3fe9266d2f973fd5e414fbarchard@google.com}  // namespace libyuv
56564ce0ab544591b1e26ae6d276932cacdb8137071fbarchard@google.com#endif  // HAVE_JPEG
56664ce0ab544591b1e26ae6d276932cacdb8137071fbarchard@google.com
567