LCOV - code coverage report
Current view: top level - media/libyuv/libyuv/source - mjpeg_decoder.cc (source / functions) Hit Total Coverage
Test: output.info Lines: 0 279 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 35 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  *  Copyright 2012 The LibYuv Project Authors. All rights reserved.
       3             :  *
       4             :  *  Use of this source code is governed by a BSD-style license
       5             :  *  that can be found in the LICENSE file in the root of the source
       6             :  *  tree. An additional intellectual property rights grant can be found
       7             :  *  in the file PATENTS. All contributing project authors may
       8             :  *  be found in the AUTHORS file in the root of the source tree.
       9             :  */
      10             : 
      11             : #include "libyuv/mjpeg_decoder.h"
      12             : 
      13             : #ifdef HAVE_JPEG
      14             : #include <assert.h>
      15             : 
      16             : #if !defined(__pnacl__) && !defined(__CLR_VER) && \
      17             :     !defined(COVERAGE_ENABLED) && !defined(TARGET_IPHONE_SIMULATOR)
      18             : // Must be included before jpeglib.
      19             : #include <setjmp.h>
      20             : #define HAVE_SETJMP
      21             : 
      22             : #if defined(_MSC_VER)
      23             : // disable warning 4324: structure was padded due to __declspec(align())
      24             : #pragma warning(disable : 4324)
      25             : #endif
      26             : 
      27             : #endif
      28             : struct FILE;  // For jpeglib.h.
      29             : 
      30             : // C++ build requires extern C for jpeg internals.
      31             : #ifdef __cplusplus
      32             : extern "C" {
      33             : #endif
      34             : 
      35             : #include <jpeglib.h>
      36             : 
      37             : #ifdef __cplusplus
      38             : }  // extern "C"
      39             : #endif
      40             : 
      41             : #include "libyuv/planar_functions.h"  // For CopyPlane().
      42             : 
      43             : namespace libyuv {
      44             : 
      45             : #ifdef HAVE_SETJMP
      46             : struct SetJmpErrorMgr {
      47             :   jpeg_error_mgr base;  // Must be at the top
      48             :   jmp_buf setjmp_buffer;
      49             : };
      50             : #endif
      51             : 
      52             : const int MJpegDecoder::kColorSpaceUnknown = JCS_UNKNOWN;
      53             : const int MJpegDecoder::kColorSpaceGrayscale = JCS_GRAYSCALE;
      54             : const int MJpegDecoder::kColorSpaceRgb = JCS_RGB;
      55             : const int MJpegDecoder::kColorSpaceYCbCr = JCS_YCbCr;
      56             : const int MJpegDecoder::kColorSpaceCMYK = JCS_CMYK;
      57             : const int MJpegDecoder::kColorSpaceYCCK = JCS_YCCK;
      58             : 
      59             : // Methods that are passed to jpeglib.
      60             : boolean fill_input_buffer(jpeg_decompress_struct* cinfo);
      61             : void init_source(jpeg_decompress_struct* cinfo);
      62             : void skip_input_data(jpeg_decompress_struct* cinfo, long num_bytes);  // NOLINT
      63             : void term_source(jpeg_decompress_struct* cinfo);
      64             : void ErrorHandler(jpeg_common_struct* cinfo);
      65             : void OutputHandler(jpeg_common_struct* cinfo);
      66             : 
      67           0 : MJpegDecoder::MJpegDecoder()
      68             :     : has_scanline_padding_(LIBYUV_FALSE),
      69             :       num_outbufs_(0),
      70             :       scanlines_(NULL),
      71             :       scanlines_sizes_(NULL),
      72             :       databuf_(NULL),
      73           0 :       databuf_strides_(NULL) {
      74           0 :   decompress_struct_ = new jpeg_decompress_struct;
      75           0 :   source_mgr_ = new jpeg_source_mgr;
      76             : #ifdef HAVE_SETJMP
      77           0 :   error_mgr_ = new SetJmpErrorMgr;
      78           0 :   decompress_struct_->err = jpeg_std_error(&error_mgr_->base);
      79             :   // Override standard exit()-based error handler.
      80           0 :   error_mgr_->base.error_exit = &ErrorHandler;
      81             : #ifndef DEBUG_MJPEG
      82           0 :   error_mgr_->base.output_message = &OutputHandler;
      83             : #endif
      84             : #endif
      85           0 :   decompress_struct_->client_data = NULL;
      86           0 :   source_mgr_->init_source = &init_source;
      87           0 :   source_mgr_->fill_input_buffer = &fill_input_buffer;
      88           0 :   source_mgr_->skip_input_data = &skip_input_data;
      89           0 :   source_mgr_->resync_to_restart = &jpeg_resync_to_restart;
      90           0 :   source_mgr_->term_source = &term_source;
      91           0 :   jpeg_create_decompress(decompress_struct_);
      92           0 :   decompress_struct_->src = source_mgr_;
      93           0 :   buf_vec_.buffers = &buf_;
      94           0 :   buf_vec_.len = 1;
      95           0 : }
      96             : 
      97           0 : MJpegDecoder::~MJpegDecoder() {
      98           0 :   jpeg_destroy_decompress(decompress_struct_);
      99           0 :   delete decompress_struct_;
     100           0 :   delete source_mgr_;
     101             : #ifdef HAVE_SETJMP
     102           0 :   delete error_mgr_;
     103             : #endif
     104           0 :   DestroyOutputBuffers();
     105           0 : }
     106             : 
     107           0 : LIBYUV_BOOL MJpegDecoder::LoadFrame(const uint8* src, size_t src_len) {
     108           0 :   if (!ValidateJpeg(src, src_len)) {
     109           0 :     return LIBYUV_FALSE;
     110             :   }
     111             : 
     112           0 :   buf_.data = src;
     113           0 :   buf_.len = static_cast<int>(src_len);
     114           0 :   buf_vec_.pos = 0;
     115           0 :   decompress_struct_->client_data = &buf_vec_;
     116             : #ifdef HAVE_SETJMP
     117           0 :   if (setjmp(error_mgr_->setjmp_buffer)) {
     118             :     // We called jpeg_read_header, it experienced an error, and we called
     119             :     // longjmp() and rewound the stack to here. Return error.
     120           0 :     return LIBYUV_FALSE;
     121             :   }
     122             : #endif
     123           0 :   if (jpeg_read_header(decompress_struct_, TRUE) != JPEG_HEADER_OK) {
     124             :     // ERROR: Bad MJPEG header
     125           0 :     return LIBYUV_FALSE;
     126             :   }
     127           0 :   AllocOutputBuffers(GetNumComponents());
     128           0 :   for (int i = 0; i < num_outbufs_; ++i) {
     129           0 :     int scanlines_size = GetComponentScanlinesPerImcuRow(i);
     130           0 :     if (scanlines_sizes_[i] != scanlines_size) {
     131           0 :       if (scanlines_[i]) {
     132           0 :         delete scanlines_[i];
     133             :       }
     134           0 :       scanlines_[i] = new uint8*[scanlines_size];
     135           0 :       scanlines_sizes_[i] = scanlines_size;
     136             :     }
     137             : 
     138             :     // We allocate padding for the final scanline to pad it up to DCTSIZE bytes
     139             :     // to avoid memory errors, since jpeglib only reads full MCUs blocks. For
     140             :     // the preceding scanlines, the padding is not needed/wanted because the
     141             :     // following addresses will already be valid (they are the initial bytes of
     142             :     // the next scanline) and will be overwritten when jpeglib writes out that
     143             :     // next scanline.
     144           0 :     int databuf_stride = GetComponentStride(i);
     145           0 :     int databuf_size = scanlines_size * databuf_stride;
     146           0 :     if (databuf_strides_[i] != databuf_stride) {
     147           0 :       if (databuf_[i]) {
     148           0 :         delete databuf_[i];
     149             :       }
     150           0 :       databuf_[i] = new uint8[databuf_size];
     151           0 :       databuf_strides_[i] = databuf_stride;
     152             :     }
     153             : 
     154           0 :     if (GetComponentStride(i) != GetComponentWidth(i)) {
     155           0 :       has_scanline_padding_ = LIBYUV_TRUE;
     156             :     }
     157             :   }
     158           0 :   return LIBYUV_TRUE;
     159             : }
     160             : 
     161           0 : static int DivideAndRoundUp(int numerator, int denominator) {
     162           0 :   return (numerator + denominator - 1) / denominator;
     163             : }
     164             : 
     165           0 : static int DivideAndRoundDown(int numerator, int denominator) {
     166           0 :   return numerator / denominator;
     167             : }
     168             : 
     169             : // Returns width of the last loaded frame.
     170           0 : int MJpegDecoder::GetWidth() {
     171           0 :   return decompress_struct_->image_width;
     172             : }
     173             : 
     174             : // Returns height of the last loaded frame.
     175           0 : int MJpegDecoder::GetHeight() {
     176           0 :   return decompress_struct_->image_height;
     177             : }
     178             : 
     179             : // Returns format of the last loaded frame. The return value is one of the
     180             : // kColorSpace* constants.
     181           0 : int MJpegDecoder::GetColorSpace() {
     182           0 :   return decompress_struct_->jpeg_color_space;
     183             : }
     184             : 
     185             : // Number of color components in the color space.
     186           0 : int MJpegDecoder::GetNumComponents() {
     187           0 :   return decompress_struct_->num_components;
     188             : }
     189             : 
     190             : // Sample factors of the n-th component.
     191           0 : int MJpegDecoder::GetHorizSampFactor(int component) {
     192           0 :   return decompress_struct_->comp_info[component].h_samp_factor;
     193             : }
     194             : 
     195           0 : int MJpegDecoder::GetVertSampFactor(int component) {
     196           0 :   return decompress_struct_->comp_info[component].v_samp_factor;
     197             : }
     198             : 
     199           0 : int MJpegDecoder::GetHorizSubSampFactor(int component) {
     200           0 :   return decompress_struct_->max_h_samp_factor / GetHorizSampFactor(component);
     201             : }
     202             : 
     203           0 : int MJpegDecoder::GetVertSubSampFactor(int component) {
     204           0 :   return decompress_struct_->max_v_samp_factor / GetVertSampFactor(component);
     205             : }
     206             : 
     207           0 : int MJpegDecoder::GetImageScanlinesPerImcuRow() {
     208           0 :   return decompress_struct_->max_v_samp_factor * DCTSIZE;
     209             : }
     210             : 
     211           0 : int MJpegDecoder::GetComponentScanlinesPerImcuRow(int component) {
     212           0 :   int vs = GetVertSubSampFactor(component);
     213           0 :   return DivideAndRoundUp(GetImageScanlinesPerImcuRow(), vs);
     214             : }
     215             : 
     216           0 : int MJpegDecoder::GetComponentWidth(int component) {
     217           0 :   int hs = GetHorizSubSampFactor(component);
     218           0 :   return DivideAndRoundUp(GetWidth(), hs);
     219             : }
     220             : 
     221           0 : int MJpegDecoder::GetComponentHeight(int component) {
     222           0 :   int vs = GetVertSubSampFactor(component);
     223           0 :   return DivideAndRoundUp(GetHeight(), vs);
     224             : }
     225             : 
     226             : // Get width in bytes padded out to a multiple of DCTSIZE
     227           0 : int MJpegDecoder::GetComponentStride(int component) {
     228           0 :   return (GetComponentWidth(component) + DCTSIZE - 1) & ~(DCTSIZE - 1);
     229             : }
     230             : 
     231           0 : int MJpegDecoder::GetComponentSize(int component) {
     232           0 :   return GetComponentWidth(component) * GetComponentHeight(component);
     233             : }
     234             : 
     235           0 : LIBYUV_BOOL MJpegDecoder::UnloadFrame() {
     236             : #ifdef HAVE_SETJMP
     237           0 :   if (setjmp(error_mgr_->setjmp_buffer)) {
     238             :     // We called jpeg_abort_decompress, it experienced an error, and we called
     239             :     // longjmp() and rewound the stack to here. Return error.
     240           0 :     return LIBYUV_FALSE;
     241             :   }
     242             : #endif
     243           0 :   jpeg_abort_decompress(decompress_struct_);
     244           0 :   return LIBYUV_TRUE;
     245             : }
     246             : 
     247             : // TODO(fbarchard): Allow rectangle to be specified: x, y, width, height.
     248           0 : LIBYUV_BOOL MJpegDecoder::DecodeToBuffers(uint8** planes,
     249             :                                           int dst_width,
     250             :                                           int dst_height) {
     251           0 :   if (dst_width != GetWidth() || dst_height > GetHeight()) {
     252             :     // ERROR: Bad dimensions
     253           0 :     return LIBYUV_FALSE;
     254             :   }
     255             : #ifdef HAVE_SETJMP
     256           0 :   if (setjmp(error_mgr_->setjmp_buffer)) {
     257             :     // We called into jpeglib, it experienced an error sometime during this
     258             :     // function call, and we called longjmp() and rewound the stack to here.
     259             :     // Return error.
     260           0 :     return LIBYUV_FALSE;
     261             :   }
     262             : #endif
     263           0 :   if (!StartDecode()) {
     264           0 :     return LIBYUV_FALSE;
     265             :   }
     266           0 :   SetScanlinePointers(databuf_);
     267           0 :   int lines_left = dst_height;
     268             :   // Compute amount of lines to skip to implement vertical crop.
     269             :   // TODO(fbarchard): Ensure skip is a multiple of maximum component
     270             :   // subsample. ie 2
     271           0 :   int skip = (GetHeight() - dst_height) / 2;
     272           0 :   if (skip > 0) {
     273             :     // There is no API to skip lines in the output data, so we read them
     274             :     // into the temp buffer.
     275           0 :     while (skip >= GetImageScanlinesPerImcuRow()) {
     276           0 :       if (!DecodeImcuRow()) {
     277           0 :         FinishDecode();
     278           0 :         return LIBYUV_FALSE;
     279             :       }
     280           0 :       skip -= GetImageScanlinesPerImcuRow();
     281             :     }
     282           0 :     if (skip > 0) {
     283             :       // Have a partial iMCU row left over to skip. Must read it and then
     284             :       // copy the parts we want into the destination.
     285           0 :       if (!DecodeImcuRow()) {
     286           0 :         FinishDecode();
     287           0 :         return LIBYUV_FALSE;
     288             :       }
     289           0 :       for (int i = 0; i < num_outbufs_; ++i) {
     290             :         // TODO(fbarchard): Compute skip to avoid this
     291           0 :         assert(skip % GetVertSubSampFactor(i) == 0);
     292           0 :         int rows_to_skip = DivideAndRoundDown(skip, GetVertSubSampFactor(i));
     293             :         int scanlines_to_copy =
     294           0 :             GetComponentScanlinesPerImcuRow(i) - rows_to_skip;
     295           0 :         int data_to_skip = rows_to_skip * GetComponentStride(i);
     296           0 :         CopyPlane(databuf_[i] + data_to_skip, GetComponentStride(i), planes[i],
     297             :                   GetComponentWidth(i), GetComponentWidth(i),
     298           0 :                   scanlines_to_copy);
     299           0 :         planes[i] += scanlines_to_copy * GetComponentWidth(i);
     300             :       }
     301           0 :       lines_left -= (GetImageScanlinesPerImcuRow() - skip);
     302             :     }
     303             :   }
     304             : 
     305             :   // Read full MCUs but cropped horizontally
     306           0 :   for (; lines_left > GetImageScanlinesPerImcuRow();
     307           0 :        lines_left -= GetImageScanlinesPerImcuRow()) {
     308           0 :     if (!DecodeImcuRow()) {
     309           0 :       FinishDecode();
     310           0 :       return LIBYUV_FALSE;
     311             :     }
     312           0 :     for (int i = 0; i < num_outbufs_; ++i) {
     313           0 :       int scanlines_to_copy = GetComponentScanlinesPerImcuRow(i);
     314           0 :       CopyPlane(databuf_[i], GetComponentStride(i), planes[i],
     315           0 :                 GetComponentWidth(i), GetComponentWidth(i), scanlines_to_copy);
     316           0 :       planes[i] += scanlines_to_copy * GetComponentWidth(i);
     317             :     }
     318             :   }
     319             : 
     320           0 :   if (lines_left > 0) {
     321             :     // Have a partial iMCU row left over to decode.
     322           0 :     if (!DecodeImcuRow()) {
     323           0 :       FinishDecode();
     324           0 :       return LIBYUV_FALSE;
     325             :     }
     326           0 :     for (int i = 0; i < num_outbufs_; ++i) {
     327             :       int scanlines_to_copy =
     328           0 :           DivideAndRoundUp(lines_left, GetVertSubSampFactor(i));
     329           0 :       CopyPlane(databuf_[i], GetComponentStride(i), planes[i],
     330           0 :                 GetComponentWidth(i), GetComponentWidth(i), scanlines_to_copy);
     331           0 :       planes[i] += scanlines_to_copy * GetComponentWidth(i);
     332             :     }
     333             :   }
     334           0 :   return FinishDecode();
     335             : }
     336             : 
     337           0 : LIBYUV_BOOL MJpegDecoder::DecodeToCallback(CallbackFunction fn,
     338             :                                            void* opaque,
     339             :                                            int dst_width,
     340             :                                            int dst_height) {
     341           0 :   if (dst_width != GetWidth() || dst_height > GetHeight()) {
     342             :     // ERROR: Bad dimensions
     343           0 :     return LIBYUV_FALSE;
     344             :   }
     345             : #ifdef HAVE_SETJMP
     346           0 :   if (setjmp(error_mgr_->setjmp_buffer)) {
     347             :     // We called into jpeglib, it experienced an error sometime during this
     348             :     // function call, and we called longjmp() and rewound the stack to here.
     349             :     // Return error.
     350           0 :     return LIBYUV_FALSE;
     351             :   }
     352             : #endif
     353           0 :   if (!StartDecode()) {
     354           0 :     return LIBYUV_FALSE;
     355             :   }
     356           0 :   SetScanlinePointers(databuf_);
     357           0 :   int lines_left = dst_height;
     358             :   // TODO(fbarchard): Compute amount of lines to skip to implement vertical crop
     359           0 :   int skip = (GetHeight() - dst_height) / 2;
     360           0 :   if (skip > 0) {
     361           0 :     while (skip >= GetImageScanlinesPerImcuRow()) {
     362           0 :       if (!DecodeImcuRow()) {
     363           0 :         FinishDecode();
     364           0 :         return LIBYUV_FALSE;
     365             :       }
     366           0 :       skip -= GetImageScanlinesPerImcuRow();
     367             :     }
     368           0 :     if (skip > 0) {
     369             :       // Have a partial iMCU row left over to skip.
     370           0 :       if (!DecodeImcuRow()) {
     371           0 :         FinishDecode();
     372           0 :         return LIBYUV_FALSE;
     373             :       }
     374           0 :       for (int i = 0; i < num_outbufs_; ++i) {
     375             :         // TODO(fbarchard): Compute skip to avoid this
     376           0 :         assert(skip % GetVertSubSampFactor(i) == 0);
     377           0 :         int rows_to_skip = DivideAndRoundDown(skip, GetVertSubSampFactor(i));
     378           0 :         int data_to_skip = rows_to_skip * GetComponentStride(i);
     379             :         // Change our own data buffer pointers so we can pass them to the
     380             :         // callback.
     381           0 :         databuf_[i] += data_to_skip;
     382             :       }
     383           0 :       int scanlines_to_copy = GetImageScanlinesPerImcuRow() - skip;
     384           0 :       (*fn)(opaque, databuf_, databuf_strides_, scanlines_to_copy);
     385             :       // Now change them back.
     386           0 :       for (int i = 0; i < num_outbufs_; ++i) {
     387           0 :         int rows_to_skip = DivideAndRoundDown(skip, GetVertSubSampFactor(i));
     388           0 :         int data_to_skip = rows_to_skip * GetComponentStride(i);
     389           0 :         databuf_[i] -= data_to_skip;
     390             :       }
     391           0 :       lines_left -= scanlines_to_copy;
     392             :     }
     393             :   }
     394             :   // Read full MCUs until we get to the crop point.
     395           0 :   for (; lines_left >= GetImageScanlinesPerImcuRow();
     396           0 :        lines_left -= GetImageScanlinesPerImcuRow()) {
     397           0 :     if (!DecodeImcuRow()) {
     398           0 :       FinishDecode();
     399           0 :       return LIBYUV_FALSE;
     400             :     }
     401           0 :     (*fn)(opaque, databuf_, databuf_strides_, GetImageScanlinesPerImcuRow());
     402             :   }
     403           0 :   if (lines_left > 0) {
     404             :     // Have a partial iMCU row left over to decode.
     405           0 :     if (!DecodeImcuRow()) {
     406           0 :       FinishDecode();
     407           0 :       return LIBYUV_FALSE;
     408             :     }
     409           0 :     (*fn)(opaque, databuf_, databuf_strides_, lines_left);
     410             :   }
     411           0 :   return FinishDecode();
     412             : }
     413             : 
     414           0 : void init_source(j_decompress_ptr cinfo) {
     415           0 :   fill_input_buffer(cinfo);
     416           0 : }
     417             : 
     418           0 : boolean fill_input_buffer(j_decompress_ptr cinfo) {
     419           0 :   BufferVector* buf_vec = reinterpret_cast<BufferVector*>(cinfo->client_data);
     420           0 :   if (buf_vec->pos >= buf_vec->len) {
     421           0 :     assert(0 && "No more data");
     422             :     // ERROR: No more data
     423             :     return FALSE;
     424             :   }
     425           0 :   cinfo->src->next_input_byte = buf_vec->buffers[buf_vec->pos].data;
     426           0 :   cinfo->src->bytes_in_buffer = buf_vec->buffers[buf_vec->pos].len;
     427           0 :   ++buf_vec->pos;
     428           0 :   return TRUE;
     429             : }
     430             : 
     431           0 : void skip_input_data(j_decompress_ptr cinfo, long num_bytes) {  // NOLINT
     432           0 :   cinfo->src->next_input_byte += num_bytes;
     433           0 : }
     434             : 
     435           0 : void term_source(j_decompress_ptr cinfo) {
     436             :   (void)cinfo;  // Nothing to do.
     437           0 : }
     438             : 
     439             : #ifdef HAVE_SETJMP
     440           0 : void ErrorHandler(j_common_ptr cinfo) {
     441             : // This is called when a jpeglib command experiences an error. Unfortunately
     442             : // jpeglib's error handling model is not very flexible, because it expects the
     443             : // error handler to not return--i.e., it wants the program to terminate. To
     444             : // recover from errors we use setjmp() as shown in their example. setjmp() is
     445             : // C's implementation for the "call with current continuation" functionality
     446             : // seen in some functional programming languages.
     447             : // A formatted message can be output, but is unsafe for release.
     448             : #ifdef DEBUG
     449             :   char buf[JMSG_LENGTH_MAX];
     450           0 :   (*cinfo->err->format_message)(cinfo, buf);
     451             : // ERROR: Error in jpeglib: buf
     452             : #endif
     453             : 
     454           0 :   SetJmpErrorMgr* mgr = reinterpret_cast<SetJmpErrorMgr*>(cinfo->err);
     455             :   // This rewinds the call stack to the point of the corresponding setjmp()
     456             :   // and causes it to return (for a second time) with value 1.
     457           0 :   longjmp(mgr->setjmp_buffer, 1);
     458             : }
     459             : 
     460             : #ifndef DEBUG_MJPEG
     461             : // Suppress fprintf warnings.
     462           0 : void OutputHandler(j_common_ptr cinfo) {
     463             :   (void)cinfo;
     464           0 : }
     465             : #endif
     466             : #endif  // HAVE_SETJMP
     467             : 
     468           0 : void MJpegDecoder::AllocOutputBuffers(int num_outbufs) {
     469           0 :   if (num_outbufs != num_outbufs_) {
     470             :     // We could perhaps optimize this case to resize the output buffers without
     471             :     // necessarily having to delete and recreate each one, but it's not worth
     472             :     // it.
     473           0 :     DestroyOutputBuffers();
     474             : 
     475           0 :     scanlines_ = new uint8**[num_outbufs];
     476           0 :     scanlines_sizes_ = new int[num_outbufs];
     477           0 :     databuf_ = new uint8*[num_outbufs];
     478           0 :     databuf_strides_ = new int[num_outbufs];
     479             : 
     480           0 :     for (int i = 0; i < num_outbufs; ++i) {
     481           0 :       scanlines_[i] = NULL;
     482           0 :       scanlines_sizes_[i] = 0;
     483           0 :       databuf_[i] = NULL;
     484           0 :       databuf_strides_[i] = 0;
     485             :     }
     486             : 
     487           0 :     num_outbufs_ = num_outbufs;
     488             :   }
     489           0 : }
     490             : 
     491           0 : void MJpegDecoder::DestroyOutputBuffers() {
     492           0 :   for (int i = 0; i < num_outbufs_; ++i) {
     493           0 :     delete[] scanlines_[i];
     494           0 :     delete[] databuf_[i];
     495             :   }
     496           0 :   delete[] scanlines_;
     497           0 :   delete[] databuf_;
     498           0 :   delete[] scanlines_sizes_;
     499           0 :   delete[] databuf_strides_;
     500           0 :   scanlines_ = NULL;
     501           0 :   databuf_ = NULL;
     502           0 :   scanlines_sizes_ = NULL;
     503           0 :   databuf_strides_ = NULL;
     504           0 :   num_outbufs_ = 0;
     505           0 : }
     506             : 
     507             : // JDCT_IFAST and do_block_smoothing improve performance substantially.
     508           0 : LIBYUV_BOOL MJpegDecoder::StartDecode() {
     509           0 :   decompress_struct_->raw_data_out = TRUE;
     510           0 :   decompress_struct_->dct_method = JDCT_IFAST;  // JDCT_ISLOW is default
     511           0 :   decompress_struct_->dither_mode = JDITHER_NONE;
     512             :   // Not applicable to 'raw':
     513           0 :   decompress_struct_->do_fancy_upsampling = (boolean)(LIBYUV_FALSE);
     514             :   // Only for buffered mode:
     515           0 :   decompress_struct_->enable_2pass_quant = (boolean)(LIBYUV_FALSE);
     516             :   // Blocky but fast:
     517           0 :   decompress_struct_->do_block_smoothing = (boolean)(LIBYUV_FALSE);
     518             : 
     519           0 :   if (!jpeg_start_decompress(decompress_struct_)) {
     520             :     // ERROR: Couldn't start JPEG decompressor";
     521           0 :     return LIBYUV_FALSE;
     522             :   }
     523           0 :   return LIBYUV_TRUE;
     524             : }
     525             : 
     526           0 : LIBYUV_BOOL MJpegDecoder::FinishDecode() {
     527             :   // jpeglib considers it an error if we finish without decoding the whole
     528             :   // image, so we call "abort" rather than "finish".
     529           0 :   jpeg_abort_decompress(decompress_struct_);
     530           0 :   return LIBYUV_TRUE;
     531             : }
     532             : 
     533           0 : void MJpegDecoder::SetScanlinePointers(uint8** data) {
     534           0 :   for (int i = 0; i < num_outbufs_; ++i) {
     535           0 :     uint8* data_i = data[i];
     536           0 :     for (int j = 0; j < scanlines_sizes_[i]; ++j) {
     537           0 :       scanlines_[i][j] = data_i;
     538           0 :       data_i += GetComponentStride(i);
     539             :     }
     540             :   }
     541           0 : }
     542             : 
     543           0 : inline LIBYUV_BOOL MJpegDecoder::DecodeImcuRow() {
     544           0 :   return (unsigned int)(GetImageScanlinesPerImcuRow()) ==
     545           0 :          jpeg_read_raw_data(decompress_struct_, scanlines_,
     546           0 :                             GetImageScanlinesPerImcuRow());
     547             : }
     548             : 
     549             : // The helper function which recognizes the jpeg sub-sampling type.
     550           0 : JpegSubsamplingType MJpegDecoder::JpegSubsamplingTypeHelper(
     551             :     int* subsample_x,
     552             :     int* subsample_y,
     553             :     int number_of_components) {
     554           0 :   if (number_of_components == 3) {  // Color images.
     555           0 :     if (subsample_x[0] == 1 && subsample_y[0] == 1 && subsample_x[1] == 2 &&
     556           0 :         subsample_y[1] == 2 && subsample_x[2] == 2 && subsample_y[2] == 2) {
     557           0 :       return kJpegYuv420;
     558           0 :     } else if (subsample_x[0] == 1 && subsample_y[0] == 1 &&
     559           0 :                subsample_x[1] == 2 && subsample_y[1] == 1 &&
     560           0 :                subsample_x[2] == 2 && subsample_y[2] == 1) {
     561           0 :       return kJpegYuv422;
     562           0 :     } else if (subsample_x[0] == 1 && subsample_y[0] == 1 &&
     563           0 :                subsample_x[1] == 1 && subsample_y[1] == 1 &&
     564           0 :                subsample_x[2] == 1 && subsample_y[2] == 1) {
     565           0 :       return kJpegYuv444;
     566             :     }
     567           0 :   } else if (number_of_components == 1) {  // Grey-scale images.
     568           0 :     if (subsample_x[0] == 1 && subsample_y[0] == 1) {
     569           0 :       return kJpegYuv400;
     570             :     }
     571             :   }
     572           0 :   return kJpegUnknown;
     573             : }
     574             : 
     575             : }  // namespace libyuv
     576             : #endif  // HAVE_JPEG

Generated by: LCOV version 1.13