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