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