media/libyuv/source/mjpeg_decoder.cc

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/media/libyuv/source/mjpeg_decoder.cc	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,558 @@
     1.4 +/*
     1.5 + *  Copyright 2012 The LibYuv Project Authors. All rights reserved.
     1.6 + *
     1.7 + *  Use of this source code is governed by a BSD-style license
     1.8 + *  that can be found in the LICENSE file in the root of the source
     1.9 + *  tree. An additional intellectual property rights grant can be found
    1.10 + *  in the file PATENTS. All contributing project authors may
    1.11 + *  be found in the AUTHORS file in the root of the source tree.
    1.12 + */
    1.13 +
    1.14 +#include "libyuv/mjpeg_decoder.h"
    1.15 +
    1.16 +#ifdef HAVE_JPEG
    1.17 +#include <assert.h>
    1.18 +
    1.19 +#if !defined(__pnacl__) && !defined(__CLR_VER) && !defined(COVERAGE_ENABLED) &&\
    1.20 +    !defined(TARGET_IPHONE_SIMULATOR)
    1.21 +// Must be included before jpeglib.
    1.22 +#include <setjmp.h>
    1.23 +#define HAVE_SETJMP
    1.24 +#endif
    1.25 +struct FILE;  // For jpeglib.h.
    1.26 +
    1.27 +// C++ build requires extern C for jpeg internals.
    1.28 +#ifdef __cplusplus
    1.29 +extern "C" {
    1.30 +#endif
    1.31 +
    1.32 +#include <jpeglib.h>
    1.33 +
    1.34 +#ifdef __cplusplus
    1.35 +}  // extern "C"
    1.36 +#endif
    1.37 +
    1.38 +#include "libyuv/planar_functions.h"  // For CopyPlane().
    1.39 +
    1.40 +namespace libyuv {
    1.41 +
    1.42 +#ifdef HAVE_SETJMP
    1.43 +struct SetJmpErrorMgr {
    1.44 +  jpeg_error_mgr base;  // Must be at the top
    1.45 +  jmp_buf setjmp_buffer;
    1.46 +};
    1.47 +#endif
    1.48 +
    1.49 +const int MJpegDecoder::kColorSpaceUnknown = JCS_UNKNOWN;
    1.50 +const int MJpegDecoder::kColorSpaceGrayscale = JCS_GRAYSCALE;
    1.51 +const int MJpegDecoder::kColorSpaceRgb = JCS_RGB;
    1.52 +const int MJpegDecoder::kColorSpaceYCbCr = JCS_YCbCr;
    1.53 +const int MJpegDecoder::kColorSpaceCMYK = JCS_CMYK;
    1.54 +const int MJpegDecoder::kColorSpaceYCCK = JCS_YCCK;
    1.55 +
    1.56 +MJpegDecoder::MJpegDecoder()
    1.57 +    : has_scanline_padding_(LIBYUV_FALSE),
    1.58 +      num_outbufs_(0),
    1.59 +      scanlines_(NULL),
    1.60 +      scanlines_sizes_(NULL),
    1.61 +      databuf_(NULL),
    1.62 +      databuf_strides_(NULL) {
    1.63 +  decompress_struct_ = new jpeg_decompress_struct;
    1.64 +  source_mgr_ = new jpeg_source_mgr;
    1.65 +#ifdef HAVE_SETJMP
    1.66 +  error_mgr_ = new SetJmpErrorMgr;
    1.67 +  decompress_struct_->err = jpeg_std_error(&error_mgr_->base);
    1.68 +  // Override standard exit()-based error handler.
    1.69 +  error_mgr_->base.error_exit = &ErrorHandler;
    1.70 +#endif
    1.71 +  decompress_struct_->client_data = NULL;
    1.72 +  source_mgr_->init_source = &init_source;
    1.73 +  source_mgr_->fill_input_buffer = &fill_input_buffer;
    1.74 +  source_mgr_->skip_input_data = &skip_input_data;
    1.75 +  source_mgr_->resync_to_restart = &jpeg_resync_to_restart;
    1.76 +  source_mgr_->term_source = &term_source;
    1.77 +  jpeg_create_decompress(decompress_struct_);
    1.78 +  decompress_struct_->src = source_mgr_;
    1.79 +  buf_vec_.buffers = &buf_;
    1.80 +  buf_vec_.len = 1;
    1.81 +}
    1.82 +
    1.83 +MJpegDecoder::~MJpegDecoder() {
    1.84 +  jpeg_destroy_decompress(decompress_struct_);
    1.85 +  delete decompress_struct_;
    1.86 +  delete source_mgr_;
    1.87 +#ifdef HAVE_SETJMP
    1.88 +  delete error_mgr_;
    1.89 +#endif
    1.90 +  DestroyOutputBuffers();
    1.91 +}
    1.92 +
    1.93 +LIBYUV_BOOL MJpegDecoder::LoadFrame(const uint8* src, size_t src_len) {
    1.94 +  if (!ValidateJpeg(src, src_len)) {
    1.95 +    return LIBYUV_FALSE;
    1.96 +  }
    1.97 +
    1.98 +  buf_.data = src;
    1.99 +  buf_.len = (int)(src_len);
   1.100 +  buf_vec_.pos = 0;
   1.101 +  decompress_struct_->client_data = &buf_vec_;
   1.102 +#ifdef HAVE_SETJMP
   1.103 +  if (setjmp(error_mgr_->setjmp_buffer)) {
   1.104 +    // We called jpeg_read_header, it experienced an error, and we called
   1.105 +    // longjmp() and rewound the stack to here. Return error.
   1.106 +    return LIBYUV_FALSE;
   1.107 +  }
   1.108 +#endif
   1.109 +  if (jpeg_read_header(decompress_struct_, TRUE) != JPEG_HEADER_OK) {
   1.110 +    // ERROR: Bad MJPEG header
   1.111 +    return LIBYUV_FALSE;
   1.112 +  }
   1.113 +  AllocOutputBuffers(GetNumComponents());
   1.114 +  for (int i = 0; i < num_outbufs_; ++i) {
   1.115 +    int scanlines_size = GetComponentScanlinesPerImcuRow(i);
   1.116 +    if (scanlines_sizes_[i] != scanlines_size) {
   1.117 +      if (scanlines_[i]) {
   1.118 +        delete scanlines_[i];
   1.119 +      }
   1.120 +      scanlines_[i] = new uint8* [scanlines_size];
   1.121 +      scanlines_sizes_[i] = scanlines_size;
   1.122 +    }
   1.123 +
   1.124 +    // We allocate padding for the final scanline to pad it up to DCTSIZE bytes
   1.125 +    // to avoid memory errors, since jpeglib only reads full MCUs blocks. For
   1.126 +    // the preceding scanlines, the padding is not needed/wanted because the
   1.127 +    // following addresses will already be valid (they are the initial bytes of
   1.128 +    // the next scanline) and will be overwritten when jpeglib writes out that
   1.129 +    // next scanline.
   1.130 +    int databuf_stride = GetComponentStride(i);
   1.131 +    int databuf_size = scanlines_size * databuf_stride;
   1.132 +    if (databuf_strides_[i] != databuf_stride) {
   1.133 +      if (databuf_[i]) {
   1.134 +        delete databuf_[i];
   1.135 +      }
   1.136 +      databuf_[i] = new uint8[databuf_size];
   1.137 +      databuf_strides_[i] = databuf_stride;
   1.138 +    }
   1.139 +
   1.140 +    if (GetComponentStride(i) != GetComponentWidth(i)) {
   1.141 +      has_scanline_padding_ = LIBYUV_TRUE;
   1.142 +    }
   1.143 +  }
   1.144 +  return LIBYUV_TRUE;
   1.145 +}
   1.146 +
   1.147 +static int DivideAndRoundUp(int numerator, int denominator) {
   1.148 +  return (numerator + denominator - 1) / denominator;
   1.149 +}
   1.150 +
   1.151 +static int DivideAndRoundDown(int numerator, int denominator) {
   1.152 +  return numerator / denominator;
   1.153 +}
   1.154 +
   1.155 +// Returns width of the last loaded frame.
   1.156 +int MJpegDecoder::GetWidth() {
   1.157 +  return decompress_struct_->image_width;
   1.158 +}
   1.159 +
   1.160 +// Returns height of the last loaded frame.
   1.161 +int MJpegDecoder::GetHeight() {
   1.162 +  return decompress_struct_->image_height;
   1.163 +}
   1.164 +
   1.165 +// Returns format of the last loaded frame. The return value is one of the
   1.166 +// kColorSpace* constants.
   1.167 +int MJpegDecoder::GetColorSpace() {
   1.168 +  return decompress_struct_->jpeg_color_space;
   1.169 +}
   1.170 +
   1.171 +// Number of color components in the color space.
   1.172 +int MJpegDecoder::GetNumComponents() {
   1.173 +  return decompress_struct_->num_components;
   1.174 +}
   1.175 +
   1.176 +// Sample factors of the n-th component.
   1.177 +int MJpegDecoder::GetHorizSampFactor(int component) {
   1.178 +  return decompress_struct_->comp_info[component].h_samp_factor;
   1.179 +}
   1.180 +
   1.181 +int MJpegDecoder::GetVertSampFactor(int component) {
   1.182 +  return decompress_struct_->comp_info[component].v_samp_factor;
   1.183 +}
   1.184 +
   1.185 +int MJpegDecoder::GetHorizSubSampFactor(int component) {
   1.186 +  return decompress_struct_->max_h_samp_factor /
   1.187 +      GetHorizSampFactor(component);
   1.188 +}
   1.189 +
   1.190 +int MJpegDecoder::GetVertSubSampFactor(int component) {
   1.191 +  return decompress_struct_->max_v_samp_factor /
   1.192 +      GetVertSampFactor(component);
   1.193 +}
   1.194 +
   1.195 +int MJpegDecoder::GetImageScanlinesPerImcuRow() {
   1.196 +  return decompress_struct_->max_v_samp_factor * DCTSIZE;
   1.197 +}
   1.198 +
   1.199 +int MJpegDecoder::GetComponentScanlinesPerImcuRow(int component) {
   1.200 +  int vs = GetVertSubSampFactor(component);
   1.201 +  return DivideAndRoundUp(GetImageScanlinesPerImcuRow(), vs);
   1.202 +}
   1.203 +
   1.204 +int MJpegDecoder::GetComponentWidth(int component) {
   1.205 +  int hs = GetHorizSubSampFactor(component);
   1.206 +  return DivideAndRoundUp(GetWidth(), hs);
   1.207 +}
   1.208 +
   1.209 +int MJpegDecoder::GetComponentHeight(int component) {
   1.210 +  int vs = GetVertSubSampFactor(component);
   1.211 +  return DivideAndRoundUp(GetHeight(), vs);
   1.212 +}
   1.213 +
   1.214 +// Get width in bytes padded out to a multiple of DCTSIZE
   1.215 +int MJpegDecoder::GetComponentStride(int component) {
   1.216 +  return (GetComponentWidth(component) + DCTSIZE - 1) & ~(DCTSIZE - 1);
   1.217 +}
   1.218 +
   1.219 +int MJpegDecoder::GetComponentSize(int component) {
   1.220 +  return GetComponentWidth(component) * GetComponentHeight(component);
   1.221 +}
   1.222 +
   1.223 +LIBYUV_BOOL MJpegDecoder::UnloadFrame() {
   1.224 +#ifdef HAVE_SETJMP
   1.225 +  if (setjmp(error_mgr_->setjmp_buffer)) {
   1.226 +    // We called jpeg_abort_decompress, it experienced an error, and we called
   1.227 +    // longjmp() and rewound the stack to here. Return error.
   1.228 +    return LIBYUV_FALSE;
   1.229 +  }
   1.230 +#endif
   1.231 +  jpeg_abort_decompress(decompress_struct_);
   1.232 +  return LIBYUV_TRUE;
   1.233 +}
   1.234 +
   1.235 +// TODO(fbarchard): Allow rectangle to be specified: x, y, width, height.
   1.236 +LIBYUV_BOOL MJpegDecoder::DecodeToBuffers(
   1.237 +    uint8** planes, int dst_width, int dst_height) {
   1.238 +  if (dst_width != GetWidth() ||
   1.239 +      dst_height > GetHeight()) {
   1.240 +    // ERROR: Bad dimensions
   1.241 +    return LIBYUV_FALSE;
   1.242 +  }
   1.243 +#ifdef HAVE_SETJMP
   1.244 +  if (setjmp(error_mgr_->setjmp_buffer)) {
   1.245 +    // We called into jpeglib, it experienced an error sometime during this
   1.246 +    // function call, and we called longjmp() and rewound the stack to here.
   1.247 +    // Return error.
   1.248 +    return LIBYUV_FALSE;
   1.249 +  }
   1.250 +#endif
   1.251 +  if (!StartDecode()) {
   1.252 +    return LIBYUV_FALSE;
   1.253 +  }
   1.254 +  SetScanlinePointers(databuf_);
   1.255 +  int lines_left = dst_height;
   1.256 +  // Compute amount of lines to skip to implement vertical crop.
   1.257 +  // TODO(fbarchard): Ensure skip is a multiple of maximum component
   1.258 +  // subsample. ie 2
   1.259 +  int skip = (GetHeight() - dst_height) / 2;
   1.260 +  if (skip > 0) {
   1.261 +    // There is no API to skip lines in the output data, so we read them
   1.262 +    // into the temp buffer.
   1.263 +    while (skip >= GetImageScanlinesPerImcuRow()) {
   1.264 +      if (!DecodeImcuRow()) {
   1.265 +        FinishDecode();
   1.266 +        return LIBYUV_FALSE;
   1.267 +      }
   1.268 +      skip -= GetImageScanlinesPerImcuRow();
   1.269 +    }
   1.270 +    if (skip > 0) {
   1.271 +      // Have a partial iMCU row left over to skip. Must read it and then
   1.272 +      // copy the parts we want into the destination.
   1.273 +      if (!DecodeImcuRow()) {
   1.274 +        FinishDecode();
   1.275 +        return LIBYUV_FALSE;
   1.276 +      }
   1.277 +      for (int i = 0; i < num_outbufs_; ++i) {
   1.278 +        // TODO(fbarchard): Compute skip to avoid this
   1.279 +        assert(skip % GetVertSubSampFactor(i) == 0);
   1.280 +        int rows_to_skip =
   1.281 +            DivideAndRoundDown(skip, GetVertSubSampFactor(i));
   1.282 +        int scanlines_to_copy = GetComponentScanlinesPerImcuRow(i) -
   1.283 +                                rows_to_skip;
   1.284 +        int data_to_skip = rows_to_skip * GetComponentStride(i);
   1.285 +        CopyPlane(databuf_[i] + data_to_skip, GetComponentStride(i),
   1.286 +                  planes[i], GetComponentWidth(i),
   1.287 +                  GetComponentWidth(i), scanlines_to_copy);
   1.288 +        planes[i] += scanlines_to_copy * GetComponentWidth(i);
   1.289 +      }
   1.290 +      lines_left -= (GetImageScanlinesPerImcuRow() - skip);
   1.291 +    }
   1.292 +  }
   1.293 +
   1.294 +  // Read full MCUs but cropped horizontally
   1.295 +  for (; lines_left > GetImageScanlinesPerImcuRow();
   1.296 +         lines_left -= GetImageScanlinesPerImcuRow()) {
   1.297 +    if (!DecodeImcuRow()) {
   1.298 +      FinishDecode();
   1.299 +      return LIBYUV_FALSE;
   1.300 +    }
   1.301 +    for (int i = 0; i < num_outbufs_; ++i) {
   1.302 +      int scanlines_to_copy = GetComponentScanlinesPerImcuRow(i);
   1.303 +      CopyPlane(databuf_[i], GetComponentStride(i),
   1.304 +                planes[i], GetComponentWidth(i),
   1.305 +                GetComponentWidth(i), scanlines_to_copy);
   1.306 +      planes[i] += scanlines_to_copy * GetComponentWidth(i);
   1.307 +    }
   1.308 +  }
   1.309 +
   1.310 +  if (lines_left > 0) {
   1.311 +    // Have a partial iMCU row left over to decode.
   1.312 +    if (!DecodeImcuRow()) {
   1.313 +      FinishDecode();
   1.314 +      return LIBYUV_FALSE;
   1.315 +    }
   1.316 +    for (int i = 0; i < num_outbufs_; ++i) {
   1.317 +      int scanlines_to_copy =
   1.318 +          DivideAndRoundUp(lines_left, GetVertSubSampFactor(i));
   1.319 +      CopyPlane(databuf_[i], GetComponentStride(i),
   1.320 +                planes[i], GetComponentWidth(i),
   1.321 +                GetComponentWidth(i), scanlines_to_copy);
   1.322 +      planes[i] += scanlines_to_copy * GetComponentWidth(i);
   1.323 +    }
   1.324 +  }
   1.325 +  return FinishDecode();
   1.326 +}
   1.327 +
   1.328 +LIBYUV_BOOL MJpegDecoder::DecodeToCallback(CallbackFunction fn, void* opaque,
   1.329 +    int dst_width, int dst_height) {
   1.330 +  if (dst_width != GetWidth() ||
   1.331 +      dst_height > GetHeight()) {
   1.332 +    // ERROR: Bad dimensions
   1.333 +    return LIBYUV_FALSE;
   1.334 +  }
   1.335 +#ifdef HAVE_SETJMP
   1.336 +  if (setjmp(error_mgr_->setjmp_buffer)) {
   1.337 +    // We called into jpeglib, it experienced an error sometime during this
   1.338 +    // function call, and we called longjmp() and rewound the stack to here.
   1.339 +    // Return error.
   1.340 +    return LIBYUV_FALSE;
   1.341 +  }
   1.342 +#endif
   1.343 +  if (!StartDecode()) {
   1.344 +    return LIBYUV_FALSE;
   1.345 +  }
   1.346 +  SetScanlinePointers(databuf_);
   1.347 +  int lines_left = dst_height;
   1.348 +  // TODO(fbarchard): Compute amount of lines to skip to implement vertical crop
   1.349 +  int skip = (GetHeight() - dst_height) / 2;
   1.350 +  if (skip > 0) {
   1.351 +    while (skip >= GetImageScanlinesPerImcuRow()) {
   1.352 +      if (!DecodeImcuRow()) {
   1.353 +        FinishDecode();
   1.354 +        return LIBYUV_FALSE;
   1.355 +      }
   1.356 +      skip -= GetImageScanlinesPerImcuRow();
   1.357 +    }
   1.358 +    if (skip > 0) {
   1.359 +      // Have a partial iMCU row left over to skip.
   1.360 +      if (!DecodeImcuRow()) {
   1.361 +        FinishDecode();
   1.362 +        return LIBYUV_FALSE;
   1.363 +      }
   1.364 +      for (int i = 0; i < num_outbufs_; ++i) {
   1.365 +        // TODO(fbarchard): Compute skip to avoid this
   1.366 +        assert(skip % GetVertSubSampFactor(i) == 0);
   1.367 +        int rows_to_skip = DivideAndRoundDown(skip, GetVertSubSampFactor(i));
   1.368 +        int data_to_skip = rows_to_skip * GetComponentStride(i);
   1.369 +        // Change our own data buffer pointers so we can pass them to the
   1.370 +        // callback.
   1.371 +        databuf_[i] += data_to_skip;
   1.372 +      }
   1.373 +      int scanlines_to_copy = GetImageScanlinesPerImcuRow() - skip;
   1.374 +      (*fn)(opaque, databuf_, databuf_strides_, scanlines_to_copy);
   1.375 +      // Now change them back.
   1.376 +      for (int i = 0; i < num_outbufs_; ++i) {
   1.377 +        int rows_to_skip = DivideAndRoundDown(skip, GetVertSubSampFactor(i));
   1.378 +        int data_to_skip = rows_to_skip * GetComponentStride(i);
   1.379 +        databuf_[i] -= data_to_skip;
   1.380 +      }
   1.381 +      lines_left -= scanlines_to_copy;
   1.382 +    }
   1.383 +  }
   1.384 +  // Read full MCUs until we get to the crop point.
   1.385 +  for (; lines_left >= GetImageScanlinesPerImcuRow();
   1.386 +         lines_left -= GetImageScanlinesPerImcuRow()) {
   1.387 +    if (!DecodeImcuRow()) {
   1.388 +      FinishDecode();
   1.389 +      return LIBYUV_FALSE;
   1.390 +    }
   1.391 +    (*fn)(opaque, databuf_, databuf_strides_, GetImageScanlinesPerImcuRow());
   1.392 +  }
   1.393 +  if (lines_left > 0) {
   1.394 +    // Have a partial iMCU row left over to decode.
   1.395 +    if (!DecodeImcuRow()) {
   1.396 +      FinishDecode();
   1.397 +      return LIBYUV_FALSE;
   1.398 +    }
   1.399 +    (*fn)(opaque, databuf_, databuf_strides_, lines_left);
   1.400 +  }
   1.401 +  return FinishDecode();
   1.402 +}
   1.403 +
   1.404 +void MJpegDecoder::init_source(j_decompress_ptr cinfo) {
   1.405 +  fill_input_buffer(cinfo);
   1.406 +}
   1.407 +
   1.408 +boolean MJpegDecoder::fill_input_buffer(j_decompress_ptr cinfo) {
   1.409 +  BufferVector* buf_vec = (BufferVector*)(cinfo->client_data);
   1.410 +  if (buf_vec->pos >= buf_vec->len) {
   1.411 +    assert(0 && "No more data");
   1.412 +    // ERROR: No more data
   1.413 +    return FALSE;
   1.414 +  }
   1.415 +  cinfo->src->next_input_byte = buf_vec->buffers[buf_vec->pos].data;
   1.416 +  cinfo->src->bytes_in_buffer = buf_vec->buffers[buf_vec->pos].len;
   1.417 +  ++buf_vec->pos;
   1.418 +  return TRUE;
   1.419 +}
   1.420 +
   1.421 +void MJpegDecoder::skip_input_data(j_decompress_ptr cinfo,
   1.422 +                                   long num_bytes) {  // NOLINT
   1.423 +  cinfo->src->next_input_byte += num_bytes;
   1.424 +}
   1.425 +
   1.426 +void MJpegDecoder::term_source(j_decompress_ptr cinfo) {
   1.427 +  // Nothing to do.
   1.428 +}
   1.429 +
   1.430 +#ifdef HAVE_SETJMP
   1.431 +void MJpegDecoder::ErrorHandler(j_common_ptr cinfo) {
   1.432 +  // This is called when a jpeglib command experiences an error. Unfortunately
   1.433 +  // jpeglib's error handling model is not very flexible, because it expects the
   1.434 +  // error handler to not return--i.e., it wants the program to terminate. To
   1.435 +  // recover from errors we use setjmp() as shown in their example. setjmp() is
   1.436 +  // C's implementation for the "call with current continuation" functionality
   1.437 +  // seen in some functional programming languages.
   1.438 +  // A formatted message can be output, but is unsafe for release.
   1.439 +#ifdef DEBUG
   1.440 +  char buf[JMSG_LENGTH_MAX];
   1.441 +  (*cinfo->err->format_message)(cinfo, buf);
   1.442 +  // ERROR: Error in jpeglib: buf
   1.443 +#endif
   1.444 +
   1.445 +  SetJmpErrorMgr* mgr = (SetJmpErrorMgr*)(cinfo->err);
   1.446 +  // This rewinds the call stack to the point of the corresponding setjmp()
   1.447 +  // and causes it to return (for a second time) with value 1.
   1.448 +  longjmp(mgr->setjmp_buffer, 1);
   1.449 +}
   1.450 +#endif
   1.451 +
   1.452 +void MJpegDecoder::AllocOutputBuffers(int num_outbufs) {
   1.453 +  if (num_outbufs != num_outbufs_) {
   1.454 +    // We could perhaps optimize this case to resize the output buffers without
   1.455 +    // necessarily having to delete and recreate each one, but it's not worth
   1.456 +    // it.
   1.457 +    DestroyOutputBuffers();
   1.458 +
   1.459 +    scanlines_ = new uint8** [num_outbufs];
   1.460 +    scanlines_sizes_ = new int[num_outbufs];
   1.461 +    databuf_ = new uint8* [num_outbufs];
   1.462 +    databuf_strides_ = new int[num_outbufs];
   1.463 +
   1.464 +    for (int i = 0; i < num_outbufs; ++i) {
   1.465 +      scanlines_[i] = NULL;
   1.466 +      scanlines_sizes_[i] = 0;
   1.467 +      databuf_[i] = NULL;
   1.468 +      databuf_strides_[i] = 0;
   1.469 +    }
   1.470 +
   1.471 +    num_outbufs_ = num_outbufs;
   1.472 +  }
   1.473 +}
   1.474 +
   1.475 +void MJpegDecoder::DestroyOutputBuffers() {
   1.476 +  for (int i = 0; i < num_outbufs_; ++i) {
   1.477 +    delete [] scanlines_[i];
   1.478 +    delete [] databuf_[i];
   1.479 +  }
   1.480 +  delete [] scanlines_;
   1.481 +  delete [] databuf_;
   1.482 +  delete [] scanlines_sizes_;
   1.483 +  delete [] databuf_strides_;
   1.484 +  scanlines_ = NULL;
   1.485 +  databuf_ = NULL;
   1.486 +  scanlines_sizes_ = NULL;
   1.487 +  databuf_strides_ = NULL;
   1.488 +  num_outbufs_ = 0;
   1.489 +}
   1.490 +
   1.491 +// JDCT_IFAST and do_block_smoothing improve performance substantially.
   1.492 +LIBYUV_BOOL MJpegDecoder::StartDecode() {
   1.493 +  decompress_struct_->raw_data_out = TRUE;
   1.494 +  decompress_struct_->dct_method = JDCT_IFAST;  // JDCT_ISLOW is default
   1.495 +  decompress_struct_->dither_mode = JDITHER_NONE;
   1.496 +  // Not applicable to 'raw':
   1.497 +  decompress_struct_->do_fancy_upsampling = LIBYUV_FALSE;
   1.498 +  // Only for buffered mode:
   1.499 +  decompress_struct_->enable_2pass_quant = LIBYUV_FALSE;
   1.500 +  // Blocky but fast:
   1.501 +  decompress_struct_->do_block_smoothing = LIBYUV_FALSE;
   1.502 +
   1.503 +  if (!jpeg_start_decompress(decompress_struct_)) {
   1.504 +    // ERROR: Couldn't start JPEG decompressor";
   1.505 +    return LIBYUV_FALSE;
   1.506 +  }
   1.507 +  return LIBYUV_TRUE;
   1.508 +}
   1.509 +
   1.510 +LIBYUV_BOOL MJpegDecoder::FinishDecode() {
   1.511 +  // jpeglib considers it an error if we finish without decoding the whole
   1.512 +  // image, so we call "abort" rather than "finish".
   1.513 +  jpeg_abort_decompress(decompress_struct_);
   1.514 +  return LIBYUV_TRUE;
   1.515 +}
   1.516 +
   1.517 +void MJpegDecoder::SetScanlinePointers(uint8** data) {
   1.518 +  for (int i = 0; i < num_outbufs_; ++i) {
   1.519 +    uint8* data_i = data[i];
   1.520 +    for (int j = 0; j < scanlines_sizes_[i]; ++j) {
   1.521 +      scanlines_[i][j] = data_i;
   1.522 +      data_i += GetComponentStride(i);
   1.523 +    }
   1.524 +  }
   1.525 +}
   1.526 +
   1.527 +inline LIBYUV_BOOL MJpegDecoder::DecodeImcuRow() {
   1.528 +  return (unsigned int)(GetImageScanlinesPerImcuRow()) ==
   1.529 +      jpeg_read_raw_data(decompress_struct_,
   1.530 +                         scanlines_,
   1.531 +                         GetImageScanlinesPerImcuRow());
   1.532 +}
   1.533 +
   1.534 +// The helper function which recognizes the jpeg sub-sampling type.
   1.535 +JpegSubsamplingType MJpegDecoder::JpegSubsamplingTypeHelper(
   1.536 +    int* subsample_x, int* subsample_y, int number_of_components) {
   1.537 +  if (number_of_components == 3) {  // Color images.
   1.538 +    if (subsample_x[0] == 1 && subsample_y[0] == 1 &&
   1.539 +        subsample_x[1] == 2 && subsample_y[1] == 2 &&
   1.540 +        subsample_x[2] == 2 && subsample_y[2] == 2) {
   1.541 +      return kJpegYuv420;
   1.542 +    } else if (subsample_x[0] == 1 && subsample_y[0] == 1 &&
   1.543 +        subsample_x[1] == 2 && subsample_y[1] == 1 &&
   1.544 +        subsample_x[2] == 2 && subsample_y[2] == 1) {
   1.545 +      return kJpegYuv422;
   1.546 +    } else if (subsample_x[0] == 1 && subsample_y[0] == 1 &&
   1.547 +        subsample_x[1] == 1 && subsample_y[1] == 1 &&
   1.548 +        subsample_x[2] == 1 && subsample_y[2] == 1) {
   1.549 +      return kJpegYuv444;
   1.550 +    }
   1.551 +  } else if (number_of_components == 1) {  // Grey-scale images.
   1.552 +    if (subsample_x[0] == 1 && subsample_y[0] == 1) {
   1.553 +      return kJpegYuv400;
   1.554 +    }
   1.555 +  }
   1.556 +  return kJpegUnknown;
   1.557 +}
   1.558 +
   1.559 +}  // namespace libyuv
   1.560 +#endif  // HAVE_JPEG
   1.561 +

mercurial