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