diff options
Diffstat (limited to '')
-rw-r--r-- | src/main/jni/libyuv/source/mjpeg_decoder.cc | 566 |
1 files changed, 0 insertions, 566 deletions
diff --git a/src/main/jni/libyuv/source/mjpeg_decoder.cc b/src/main/jni/libyuv/source/mjpeg_decoder.cc deleted file mode 100644 index 36028c3cc..000000000 --- a/src/main/jni/libyuv/source/mjpeg_decoder.cc +++ /dev/null @@ -1,566 +0,0 @@ -/* - * Copyright 2012 The LibYuv Project Authors. All rights reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -#include "libyuv/mjpeg_decoder.h" - -#ifdef HAVE_JPEG -#include <assert.h> - -#if !defined(__pnacl__) && !defined(__CLR_VER) && \ - !defined(COVERAGE_ENABLED) && !defined(TARGET_IPHONE_SIMULATOR) -// Must be included before jpeglib. -#include <setjmp.h> -#define HAVE_SETJMP -#endif -struct FILE; // For jpeglib.h. - -// C++ build requires extern C for jpeg internals. -#ifdef __cplusplus -extern "C" { -#endif - -#include <jpeglib.h> - -#ifdef __cplusplus -} // extern "C" -#endif - -#include "libyuv/planar_functions.h" // For CopyPlane(). - -namespace libyuv { - -#ifdef HAVE_SETJMP -struct SetJmpErrorMgr { - jpeg_error_mgr base; // Must be at the top - jmp_buf setjmp_buffer; -}; -#endif - -const int MJpegDecoder::kColorSpaceUnknown = JCS_UNKNOWN; -const int MJpegDecoder::kColorSpaceGrayscale = JCS_GRAYSCALE; -const int MJpegDecoder::kColorSpaceRgb = JCS_RGB; -const int MJpegDecoder::kColorSpaceYCbCr = JCS_YCbCr; -const int MJpegDecoder::kColorSpaceCMYK = JCS_CMYK; -const int MJpegDecoder::kColorSpaceYCCK = JCS_YCCK; - -// Methods that are passed to jpeglib. -boolean fill_input_buffer(jpeg_decompress_struct* cinfo); -void init_source(jpeg_decompress_struct* cinfo); -void skip_input_data(jpeg_decompress_struct* cinfo, - long num_bytes); // NOLINT -void term_source(jpeg_decompress_struct* cinfo); -void ErrorHandler(jpeg_common_struct* cinfo); - -MJpegDecoder::MJpegDecoder() - : has_scanline_padding_(LIBYUV_FALSE), - num_outbufs_(0), - scanlines_(NULL), - scanlines_sizes_(NULL), - databuf_(NULL), - databuf_strides_(NULL) { - decompress_struct_ = new jpeg_decompress_struct; - source_mgr_ = new jpeg_source_mgr; -#ifdef HAVE_SETJMP - error_mgr_ = new SetJmpErrorMgr; - decompress_struct_->err = jpeg_std_error(&error_mgr_->base); - // Override standard exit()-based error handler. - error_mgr_->base.error_exit = &ErrorHandler; -#endif - decompress_struct_->client_data = NULL; - source_mgr_->init_source = &init_source; - source_mgr_->fill_input_buffer = &fill_input_buffer; - source_mgr_->skip_input_data = &skip_input_data; - source_mgr_->resync_to_restart = &jpeg_resync_to_restart; - source_mgr_->term_source = &term_source; - jpeg_create_decompress(decompress_struct_); - decompress_struct_->src = source_mgr_; - buf_vec_.buffers = &buf_; - buf_vec_.len = 1; -} - -MJpegDecoder::~MJpegDecoder() { - jpeg_destroy_decompress(decompress_struct_); - delete decompress_struct_; - delete source_mgr_; -#ifdef HAVE_SETJMP - delete error_mgr_; -#endif - DestroyOutputBuffers(); -} - -LIBYUV_BOOL MJpegDecoder::LoadFrame(const uint8* src, size_t src_len) { - if (!ValidateJpeg(src, src_len)) { - return LIBYUV_FALSE; - } - - buf_.data = src; - buf_.len = static_cast<int>(src_len); - buf_vec_.pos = 0; - decompress_struct_->client_data = &buf_vec_; -#ifdef HAVE_SETJMP - if (setjmp(error_mgr_->setjmp_buffer)) { - // We called jpeg_read_header, it experienced an error, and we called - // longjmp() and rewound the stack to here. Return error. - return LIBYUV_FALSE; - } -#endif - if (jpeg_read_header(decompress_struct_, TRUE) != JPEG_HEADER_OK) { - // ERROR: Bad MJPEG header - return LIBYUV_FALSE; - } - AllocOutputBuffers(GetNumComponents()); - for (int i = 0; i < num_outbufs_; ++i) { - int scanlines_size = GetComponentScanlinesPerImcuRow(i); - if (scanlines_sizes_[i] != scanlines_size) { - if (scanlines_[i]) { - delete scanlines_[i]; - } - scanlines_[i] = new uint8* [scanlines_size]; - scanlines_sizes_[i] = scanlines_size; - } - - // We allocate padding for the final scanline to pad it up to DCTSIZE bytes - // to avoid memory errors, since jpeglib only reads full MCUs blocks. For - // the preceding scanlines, the padding is not needed/wanted because the - // following addresses will already be valid (they are the initial bytes of - // the next scanline) and will be overwritten when jpeglib writes out that - // next scanline. - int databuf_stride = GetComponentStride(i); - int databuf_size = scanlines_size * databuf_stride; - if (databuf_strides_[i] != databuf_stride) { - if (databuf_[i]) { - delete databuf_[i]; - } - databuf_[i] = new uint8[databuf_size]; - databuf_strides_[i] = databuf_stride; - } - - if (GetComponentStride(i) != GetComponentWidth(i)) { - has_scanline_padding_ = LIBYUV_TRUE; - } - } - return LIBYUV_TRUE; -} - -static int DivideAndRoundUp(int numerator, int denominator) { - return (numerator + denominator - 1) / denominator; -} - -static int DivideAndRoundDown(int numerator, int denominator) { - return numerator / denominator; -} - -// Returns width of the last loaded frame. -int MJpegDecoder::GetWidth() { - return decompress_struct_->image_width; -} - -// Returns height of the last loaded frame. -int MJpegDecoder::GetHeight() { - return decompress_struct_->image_height; -} - -// Returns format of the last loaded frame. The return value is one of the -// kColorSpace* constants. -int MJpegDecoder::GetColorSpace() { - return decompress_struct_->jpeg_color_space; -} - -// Number of color components in the color space. -int MJpegDecoder::GetNumComponents() { - return decompress_struct_->num_components; -} - -// Sample factors of the n-th component. -int MJpegDecoder::GetHorizSampFactor(int component) { - return decompress_struct_->comp_info[component].h_samp_factor; -} - -int MJpegDecoder::GetVertSampFactor(int component) { - return decompress_struct_->comp_info[component].v_samp_factor; -} - -int MJpegDecoder::GetHorizSubSampFactor(int component) { - return decompress_struct_->max_h_samp_factor / - GetHorizSampFactor(component); -} - -int MJpegDecoder::GetVertSubSampFactor(int component) { - return decompress_struct_->max_v_samp_factor / - GetVertSampFactor(component); -} - -int MJpegDecoder::GetImageScanlinesPerImcuRow() { - return decompress_struct_->max_v_samp_factor * DCTSIZE; -} - -int MJpegDecoder::GetComponentScanlinesPerImcuRow(int component) { - int vs = GetVertSubSampFactor(component); - return DivideAndRoundUp(GetImageScanlinesPerImcuRow(), vs); -} - -int MJpegDecoder::GetComponentWidth(int component) { - int hs = GetHorizSubSampFactor(component); - return DivideAndRoundUp(GetWidth(), hs); -} - -int MJpegDecoder::GetComponentHeight(int component) { - int vs = GetVertSubSampFactor(component); - return DivideAndRoundUp(GetHeight(), vs); -} - -// Get width in bytes padded out to a multiple of DCTSIZE -int MJpegDecoder::GetComponentStride(int component) { - return (GetComponentWidth(component) + DCTSIZE - 1) & ~(DCTSIZE - 1); -} - -int MJpegDecoder::GetComponentSize(int component) { - return GetComponentWidth(component) * GetComponentHeight(component); -} - -LIBYUV_BOOL MJpegDecoder::UnloadFrame() { -#ifdef HAVE_SETJMP - if (setjmp(error_mgr_->setjmp_buffer)) { - // We called jpeg_abort_decompress, it experienced an error, and we called - // longjmp() and rewound the stack to here. Return error. - return LIBYUV_FALSE; - } -#endif - jpeg_abort_decompress(decompress_struct_); - return LIBYUV_TRUE; -} - -// TODO(fbarchard): Allow rectangle to be specified: x, y, width, height. -LIBYUV_BOOL MJpegDecoder::DecodeToBuffers( - uint8** planes, int dst_width, int dst_height) { - if (dst_width != GetWidth() || - dst_height > GetHeight()) { - // ERROR: Bad dimensions - return LIBYUV_FALSE; - } -#ifdef HAVE_SETJMP - if (setjmp(error_mgr_->setjmp_buffer)) { - // We called into jpeglib, it experienced an error sometime during this - // function call, and we called longjmp() and rewound the stack to here. - // Return error. - return LIBYUV_FALSE; - } -#endif - if (!StartDecode()) { - return LIBYUV_FALSE; - } - SetScanlinePointers(databuf_); - int lines_left = dst_height; - // Compute amount of lines to skip to implement vertical crop. - // TODO(fbarchard): Ensure skip is a multiple of maximum component - // subsample. ie 2 - int skip = (GetHeight() - dst_height) / 2; - if (skip > 0) { - // There is no API to skip lines in the output data, so we read them - // into the temp buffer. - while (skip >= GetImageScanlinesPerImcuRow()) { - if (!DecodeImcuRow()) { - FinishDecode(); - return LIBYUV_FALSE; - } - skip -= GetImageScanlinesPerImcuRow(); - } - if (skip > 0) { - // Have a partial iMCU row left over to skip. Must read it and then - // copy the parts we want into the destination. - if (!DecodeImcuRow()) { - FinishDecode(); - return LIBYUV_FALSE; - } - for (int i = 0; i < num_outbufs_; ++i) { - // TODO(fbarchard): Compute skip to avoid this - assert(skip % GetVertSubSampFactor(i) == 0); - int rows_to_skip = - DivideAndRoundDown(skip, GetVertSubSampFactor(i)); - int scanlines_to_copy = GetComponentScanlinesPerImcuRow(i) - - rows_to_skip; - int data_to_skip = rows_to_skip * GetComponentStride(i); - CopyPlane(databuf_[i] + data_to_skip, GetComponentStride(i), - planes[i], GetComponentWidth(i), - GetComponentWidth(i), scanlines_to_copy); - planes[i] += scanlines_to_copy * GetComponentWidth(i); - } - lines_left -= (GetImageScanlinesPerImcuRow() - skip); - } - } - - // Read full MCUs but cropped horizontally - for (; lines_left > GetImageScanlinesPerImcuRow(); - lines_left -= GetImageScanlinesPerImcuRow()) { - if (!DecodeImcuRow()) { - FinishDecode(); - return LIBYUV_FALSE; - } - for (int i = 0; i < num_outbufs_; ++i) { - int scanlines_to_copy = GetComponentScanlinesPerImcuRow(i); - CopyPlane(databuf_[i], GetComponentStride(i), - planes[i], GetComponentWidth(i), - GetComponentWidth(i), scanlines_to_copy); - planes[i] += scanlines_to_copy * GetComponentWidth(i); - } - } - - if (lines_left > 0) { - // Have a partial iMCU row left over to decode. - if (!DecodeImcuRow()) { - FinishDecode(); - return LIBYUV_FALSE; - } - for (int i = 0; i < num_outbufs_; ++i) { - int scanlines_to_copy = - DivideAndRoundUp(lines_left, GetVertSubSampFactor(i)); - CopyPlane(databuf_[i], GetComponentStride(i), - planes[i], GetComponentWidth(i), - GetComponentWidth(i), scanlines_to_copy); - planes[i] += scanlines_to_copy * GetComponentWidth(i); - } - } - return FinishDecode(); -} - -LIBYUV_BOOL MJpegDecoder::DecodeToCallback(CallbackFunction fn, void* opaque, - int dst_width, int dst_height) { - if (dst_width != GetWidth() || - dst_height > GetHeight()) { - // ERROR: Bad dimensions - return LIBYUV_FALSE; - } -#ifdef HAVE_SETJMP - if (setjmp(error_mgr_->setjmp_buffer)) { - // We called into jpeglib, it experienced an error sometime during this - // function call, and we called longjmp() and rewound the stack to here. - // Return error. - return LIBYUV_FALSE; - } -#endif - if (!StartDecode()) { - return LIBYUV_FALSE; - } - SetScanlinePointers(databuf_); - int lines_left = dst_height; - // TODO(fbarchard): Compute amount of lines to skip to implement vertical crop - int skip = (GetHeight() - dst_height) / 2; - if (skip > 0) { - while (skip >= GetImageScanlinesPerImcuRow()) { - if (!DecodeImcuRow()) { - FinishDecode(); - return LIBYUV_FALSE; - } - skip -= GetImageScanlinesPerImcuRow(); - } - if (skip > 0) { - // Have a partial iMCU row left over to skip. - if (!DecodeImcuRow()) { - FinishDecode(); - return LIBYUV_FALSE; - } - for (int i = 0; i < num_outbufs_; ++i) { - // TODO(fbarchard): Compute skip to avoid this - assert(skip % GetVertSubSampFactor(i) == 0); - int rows_to_skip = DivideAndRoundDown(skip, GetVertSubSampFactor(i)); - int data_to_skip = rows_to_skip * GetComponentStride(i); - // Change our own data buffer pointers so we can pass them to the - // callback. - databuf_[i] += data_to_skip; - } - int scanlines_to_copy = GetImageScanlinesPerImcuRow() - skip; - (*fn)(opaque, databuf_, databuf_strides_, scanlines_to_copy); - // Now change them back. - for (int i = 0; i < num_outbufs_; ++i) { - int rows_to_skip = DivideAndRoundDown(skip, GetVertSubSampFactor(i)); - int data_to_skip = rows_to_skip * GetComponentStride(i); - databuf_[i] -= data_to_skip; - } - lines_left -= scanlines_to_copy; - } - } - // Read full MCUs until we get to the crop point. - for (; lines_left >= GetImageScanlinesPerImcuRow(); - lines_left -= GetImageScanlinesPerImcuRow()) { - if (!DecodeImcuRow()) { - FinishDecode(); - return LIBYUV_FALSE; - } - (*fn)(opaque, databuf_, databuf_strides_, GetImageScanlinesPerImcuRow()); - } - if (lines_left > 0) { - // Have a partial iMCU row left over to decode. - if (!DecodeImcuRow()) { - FinishDecode(); - return LIBYUV_FALSE; - } - (*fn)(opaque, databuf_, databuf_strides_, lines_left); - } - return FinishDecode(); -} - -void init_source(j_decompress_ptr cinfo) { - fill_input_buffer(cinfo); -} - -boolean fill_input_buffer(j_decompress_ptr cinfo) { - BufferVector* buf_vec = reinterpret_cast<BufferVector*>(cinfo->client_data); - if (buf_vec->pos >= buf_vec->len) { - assert(0 && "No more data"); - // ERROR: No more data - return FALSE; - } - cinfo->src->next_input_byte = buf_vec->buffers[buf_vec->pos].data; - cinfo->src->bytes_in_buffer = buf_vec->buffers[buf_vec->pos].len; - ++buf_vec->pos; - return TRUE; -} - -void skip_input_data(j_decompress_ptr cinfo, - long num_bytes) { // NOLINT - cinfo->src->next_input_byte += num_bytes; -} - -void term_source(j_decompress_ptr cinfo) { - // Nothing to do. -} - -#ifdef HAVE_SETJMP -void ErrorHandler(j_common_ptr cinfo) { - // This is called when a jpeglib command experiences an error. Unfortunately - // jpeglib's error handling model is not very flexible, because it expects the - // error handler to not return--i.e., it wants the program to terminate. To - // recover from errors we use setjmp() as shown in their example. setjmp() is - // C's implementation for the "call with current continuation" functionality - // seen in some functional programming languages. - // A formatted message can be output, but is unsafe for release. -#ifdef DEBUG - char buf[JMSG_LENGTH_MAX]; - (*cinfo->err->format_message)(cinfo, buf); - // ERROR: Error in jpeglib: buf -#endif - - SetJmpErrorMgr* mgr = reinterpret_cast<SetJmpErrorMgr*>(cinfo->err); - // This rewinds the call stack to the point of the corresponding setjmp() - // and causes it to return (for a second time) with value 1. - longjmp(mgr->setjmp_buffer, 1); -} -#endif - -void MJpegDecoder::AllocOutputBuffers(int num_outbufs) { - if (num_outbufs != num_outbufs_) { - // We could perhaps optimize this case to resize the output buffers without - // necessarily having to delete and recreate each one, but it's not worth - // it. - DestroyOutputBuffers(); - - scanlines_ = new uint8** [num_outbufs]; - scanlines_sizes_ = new int[num_outbufs]; - databuf_ = new uint8* [num_outbufs]; - databuf_strides_ = new int[num_outbufs]; - - for (int i = 0; i < num_outbufs; ++i) { - scanlines_[i] = NULL; - scanlines_sizes_[i] = 0; - databuf_[i] = NULL; - databuf_strides_[i] = 0; - } - - num_outbufs_ = num_outbufs; - } -} - -void MJpegDecoder::DestroyOutputBuffers() { - for (int i = 0; i < num_outbufs_; ++i) { - delete [] scanlines_[i]; - delete [] databuf_[i]; - } - delete [] scanlines_; - delete [] databuf_; - delete [] scanlines_sizes_; - delete [] databuf_strides_; - scanlines_ = NULL; - databuf_ = NULL; - scanlines_sizes_ = NULL; - databuf_strides_ = NULL; - num_outbufs_ = 0; -} - -// JDCT_IFAST and do_block_smoothing improve performance substantially. -LIBYUV_BOOL MJpegDecoder::StartDecode() { - decompress_struct_->raw_data_out = TRUE; - decompress_struct_->dct_method = JDCT_IFAST; // JDCT_ISLOW is default - decompress_struct_->dither_mode = JDITHER_NONE; - // Not applicable to 'raw': - decompress_struct_->do_fancy_upsampling = (boolean)(LIBYUV_FALSE); - // Only for buffered mode: - decompress_struct_->enable_2pass_quant = (boolean)(LIBYUV_FALSE); - // Blocky but fast: - decompress_struct_->do_block_smoothing = (boolean)(LIBYUV_FALSE); - - if (!jpeg_start_decompress(decompress_struct_)) { - // ERROR: Couldn't start JPEG decompressor"; - return LIBYUV_FALSE; - } - return LIBYUV_TRUE; -} - -LIBYUV_BOOL MJpegDecoder::FinishDecode() { - // jpeglib considers it an error if we finish without decoding the whole - // image, so we call "abort" rather than "finish". - jpeg_abort_decompress(decompress_struct_); - return LIBYUV_TRUE; -} - -void MJpegDecoder::SetScanlinePointers(uint8** data) { - for (int i = 0; i < num_outbufs_; ++i) { - uint8* data_i = data[i]; - for (int j = 0; j < scanlines_sizes_[i]; ++j) { - scanlines_[i][j] = data_i; - data_i += GetComponentStride(i); - } - } -} - -inline LIBYUV_BOOL MJpegDecoder::DecodeImcuRow() { - return (unsigned int)(GetImageScanlinesPerImcuRow()) == - jpeg_read_raw_data(decompress_struct_, - scanlines_, - GetImageScanlinesPerImcuRow()); -} - -// The helper function which recognizes the jpeg sub-sampling type. -JpegSubsamplingType MJpegDecoder::JpegSubsamplingTypeHelper( - int* subsample_x, int* subsample_y, int number_of_components) { - if (number_of_components == 3) { // Color images. - if (subsample_x[0] == 1 && subsample_y[0] == 1 && - subsample_x[1] == 2 && subsample_y[1] == 2 && - subsample_x[2] == 2 && subsample_y[2] == 2) { - return kJpegYuv420; - } else if (subsample_x[0] == 1 && subsample_y[0] == 1 && - subsample_x[1] == 2 && subsample_y[1] == 1 && - subsample_x[2] == 2 && subsample_y[2] == 1) { - return kJpegYuv422; - } else if (subsample_x[0] == 1 && subsample_y[0] == 1 && - subsample_x[1] == 1 && subsample_y[1] == 1 && - subsample_x[2] == 1 && subsample_y[2] == 1) { - return kJpegYuv444; - } - } else if (number_of_components == 1) { // Grey-scale images. - if (subsample_x[0] == 1 && subsample_y[0] == 1) { - return kJpegYuv400; - } - } - return kJpegUnknown; -} - -} // namespace libyuv -#endif // HAVE_JPEG - |