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