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