media/libyuv/source/mjpeg_decoder.cc

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

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

mercurial