diff --git a/ChangeLog.txt b/ChangeLog.txt index 890720fe..d9df904c 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -8,6 +8,9 @@ to the compiler vs. x86, it was still possible to speed up compression by about 3-4x and decompression by about 2-2.5x (relative to libjpeg v6b) through the use of AltiVec instructions. +[2] Added a new libjpeg API function (jpeg_skip_scanlines()) that can be used +to partially decode a JPEG image. See libjpeg.txt for more details. + 1.4.1 ===== diff --git a/djpeg.c b/djpeg.c index 8ddff96e..20821cec 100644 --- a/djpeg.c +++ b/djpeg.c @@ -4,7 +4,8 @@ * This file was part of the Independent JPEG Group's software: * Copyright (C) 1991-1997, Thomas G. Lane. * libjpeg-turbo Modifications: - * Copyright (C) 2010-2011, 2013-2014, D. R. Commander. + * Copyright (C) 2010-2011, 2013-2015, D. R. Commander. + * Copyright (C) 2015, Google, Inc. * For conditions of distribution and use, see the accompanying README file. * * This file contains a command-line user interface for the JPEG decompressor. @@ -88,6 +89,8 @@ static IMAGE_FORMATS requested_fmt; static const char * progname; /* program name for error messages */ static char * outfilename; /* for -outfile switch */ boolean memsrc; /* for -memsrc switch */ +boolean stripe; +JDIMENSION startY, endY; #define INPUT_BUF_SIZE 4096 @@ -164,6 +167,7 @@ usage (void) fprintf(stderr, " -memsrc Load input file into memory before decompressing\n"); #endif + fprintf(stderr, " -stripe Y0,Y1 Decode a horizontal stripe of the image [Y0, Y1)\n"); fprintf(stderr, " -verbose or -debug Emit debug output\n"); fprintf(stderr, " -version Print version information and exit\n"); exit(EXIT_FAILURE); @@ -189,6 +193,7 @@ parse_switches (j_decompress_ptr cinfo, int argc, char **argv, requested_fmt = DEFAULT_FMT; /* set default output file format */ outfilename = NULL; memsrc = FALSE; + stripe = FALSE; cinfo->err->trace_level = 0; /* Scan command line options, adjust parameters */ @@ -361,7 +366,7 @@ parse_switches (j_decompress_ptr cinfo, int argc, char **argv, /* RLE output format. */ requested_fmt = FMT_RLE; - } else if (keymatch(arg, "scale", 1)) { + } else if (keymatch(arg, "scale", 2)) { /* Scale the output image by a fraction M/N. */ if (++argn >= argc) /* advance to next argument */ usage(); @@ -369,6 +374,13 @@ parse_switches (j_decompress_ptr cinfo, int argc, char **argv, &cinfo->scale_num, &cinfo->scale_denom) != 2) usage(); + } else if (keymatch(arg, "stripe", 2)) { + if (++argn >= argc) + usage(); + if (sscanf(argv[argn], "%d,%d", &startY, &endY) != 2 || startY > endY) + usage(); + stripe = TRUE; + } else if (keymatch(arg, "targa", 1)) { /* Targa output format. */ requested_fmt = FMT_TARGA; @@ -634,14 +646,48 @@ main (int argc, char **argv) /* Start decompressor */ (void) jpeg_start_decompress(&cinfo); - /* Write output file header */ - (*dest_mgr->start_output) (&cinfo, dest_mgr); + /* Stripe decode */ + if (stripe) { + JDIMENSION tmp; - /* Process data */ - while (cinfo.output_scanline < cinfo.output_height) { - num_scanlines = jpeg_read_scanlines(&cinfo, dest_mgr->buffer, - dest_mgr->buffer_height); - (*dest_mgr->put_pixel_rows) (&cinfo, dest_mgr, num_scanlines); + /* Check for valid endY. We cannot check this value until after + * jpeg_start_decompress() is called. Note that we have already verified + * that startY <= endY. + */ + if (endY > cinfo.output_height) { + fprintf(stderr, "%s: stripe %d-%d exceeds image height %d\n", progname, + startY, endY, cinfo.output_height); + exit(EXIT_FAILURE); + } + + /* Write output file header. This is a hack to ensure that the destination + * manager creates an image of the proper size for the partial decode. + */ + tmp = cinfo.output_height; + cinfo.output_height = endY - startY; + (*dest_mgr->start_output) (&cinfo, dest_mgr); + cinfo.output_height = tmp; + + /* Process data */ + (void) jpeg_skip_scanlines(&cinfo, startY); + while (cinfo.output_scanline < endY) { + num_scanlines = jpeg_read_scanlines(&cinfo, dest_mgr->buffer, + dest_mgr->buffer_height); + (*dest_mgr->put_pixel_rows) (&cinfo, dest_mgr, num_scanlines); + } + (void) jpeg_skip_scanlines(&cinfo, cinfo.output_height - endY); + + /* Normal full image decode */ + } else { + /* Write output file header */ + (*dest_mgr->start_output) (&cinfo, dest_mgr); + + /* Process data */ + while (cinfo.output_scanline < cinfo.output_height) { + num_scanlines = jpeg_read_scanlines(&cinfo, dest_mgr->buffer, + dest_mgr->buffer_height); + (*dest_mgr->put_pixel_rows) (&cinfo, dest_mgr, num_scanlines); + } } #ifdef PROGRESS_REPORT diff --git a/jdapistd.c b/jdapistd.c index 3be527cb..51b7dc63 100644 --- a/jdapistd.c +++ b/jdapistd.c @@ -4,7 +4,8 @@ * This file was part of the Independent JPEG Group's software: * Copyright (C) 1994-1996, Thomas G. Lane. * libjpeg-turbo Modifications: - * Copyright (C) 2010, D. R. Commander. + * Copyright (C) 2010, 2015, D. R. Commander. + * Copyright (C) 2015, Google, Inc. * For conditions of distribution and use, see the accompanying README file. * * This file contains application interface code for the decompression half @@ -16,11 +17,10 @@ * whole decompression library into a transcoder. */ -#define JPEG_INTERNALS -#include "jinclude.h" -#include "jpeglib.h" -#include "jpegcomp.h" - +#include "jdmainct.h" +#include "jdcoefct.h" +#include "jdsample.h" +#include "jmemsys.h" /* Forward declarations */ LOCAL(boolean) output_pass_setup (j_decompress_ptr cinfo); @@ -179,6 +179,242 @@ jpeg_read_scanlines (j_decompress_ptr cinfo, JSAMPARRAY scanlines, } +/* Prepare temporary row buffer */ + +LOCAL(void) +dummy_buffer_setup (j_decompress_ptr cinfo) +{ + int nc; + + if (!cinfo->master || cinfo->master->dummy_row_buffer) + return; + + nc = (cinfo->out_color_space == JCS_RGB565) ? + 2 : cinfo->out_color_components; + cinfo->master->dummy_row_buffer = + jpeg_get_small((j_common_ptr) cinfo, + cinfo->output_width * nc * sizeof(JSAMPLE)); +} + + +/* + * Called by jpeg_skip_scanlines(). This partially skips a decompress block by + * incrementing the rowgroup counter. + */ + +LOCAL(void) +increment_simple_rowgroup_ctr (j_decompress_ptr cinfo, JDIMENSION rows) +{ + int i; + JDIMENSION rows_left; + my_main_ptr main_ptr = (my_main_ptr) cinfo->main; + + /* Increment the counter to the next row group after the skipped rows. */ + main_ptr->rowgroup_ctr += rows / cinfo->max_v_samp_factor; + + /* Partially skipping a row group would involve modifying the internal state + * of the upsampler, so read the remaining rows into a dummy buffer instead. + */ + rows_left = rows % cinfo->max_v_samp_factor; + cinfo->output_scanline += rows - rows_left; + + dummy_buffer_setup(cinfo); + for (i = 0; i < rows_left; i++) + jpeg_read_scanlines(cinfo, &(cinfo->master->dummy_row_buffer), 1); +} + + +/* + * Called by jpeg_skip_scanlines(). When we skip iMCU rows, we must update the + * iMCU row counter. + */ + +LOCAL(void) +increment_iMCU_ctr (j_decompress_ptr cinfo, JDIMENSION iMCU_rows) +{ + my_main_ptr main_ptr = (my_main_ptr) cinfo->main; + if (main_ptr->iMCU_row_ctr == 0 && iMCU_rows > 0) + set_wraparound_pointers(cinfo); + main_ptr->iMCU_row_ctr += iMCU_rows; +} + + +/* + * Skips some scanlines of data from the JPEG decompressor. + * + * The return value will be the number of lines actually skipped. If skipping + * num_lines would move beyond the end of the image, then the actual number of + * lines remaining in the image is returned. Otherwise, the return value will + * be equal to num_lines. + * + * Refer to libjpeg.txt for more information. + */ + +GLOBAL(JDIMENSION) +jpeg_skip_scanlines (j_decompress_ptr cinfo, JDIMENSION num_lines) +{ + my_main_ptr main_ptr = (my_main_ptr) cinfo->main; + my_coef_ptr coef = (my_coef_ptr) cinfo->coef; + my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; + int i, y, x; + JDIMENSION lines_per_iMCU_row, lines_left_in_iMCU_row, lines_after_iMCU_row; + JDIMENSION lines_to_skip, lines_to_read; + + if (cinfo->global_state != DSTATE_SCANNING) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + + /* Do not skip past the bottom of the image. */ + if (cinfo->output_scanline + num_lines >= cinfo->output_height) { + cinfo->output_scanline = cinfo->output_height; + return cinfo->output_height - cinfo->output_scanline; + } + + if (num_lines == 0) + return 0; + + lines_per_iMCU_row = cinfo->_min_DCT_scaled_size * cinfo->max_v_samp_factor; + lines_left_in_iMCU_row = + (lines_per_iMCU_row - (cinfo->output_scanline % lines_per_iMCU_row)) % + lines_per_iMCU_row; + lines_after_iMCU_row = num_lines - lines_left_in_iMCU_row; + + /* Skip the lines remaining in the current iMCU row. When upsampling + * requires context rows, we need the previous and next rows in order to read + * the current row. This adds some complexity. + */ + if (cinfo->upsample->need_context_rows) { + /* If the skipped lines would not move us past the current iMCU row, we + * read the lines and ignore them. There might be a faster way of doing + * this, but we are facing increasing complexity for diminishing returns. + * The increasing complexity would be a by-product of meddling with the + * state machine used to skip context rows. Near the end of an iMCU row, + * the next iMCU row may have already been entropy-decoded. In this unique + * case, we will read the next iMCU row if we cannot skip past it as well. + */ + if ((num_lines < lines_left_in_iMCU_row + 1) || + (lines_left_in_iMCU_row <= 1 && main_ptr->buffer_full && + lines_after_iMCU_row < lines_per_iMCU_row + 1)) { + dummy_buffer_setup(cinfo); + for (i = 0; i < num_lines; i++) + jpeg_read_scanlines(cinfo, &(cinfo->master->dummy_row_buffer), 1); + return num_lines; + } + + /* If the next iMCU row has already been entropy-decoded, make sure that + * we do not skip too far. + */ + if (lines_left_in_iMCU_row <= 1 && main_ptr->buffer_full) { + cinfo->output_scanline += lines_left_in_iMCU_row + lines_per_iMCU_row; + lines_after_iMCU_row -= lines_per_iMCU_row; + } else { + cinfo->output_scanline += lines_left_in_iMCU_row; + } + main_ptr->buffer_full = FALSE; + main_ptr->rowgroup_ctr = 0; + main_ptr->context_state = CTX_PREPARE_FOR_IMCU; + upsample->next_row_out = cinfo->max_v_samp_factor; + upsample->rows_to_go = cinfo->output_height - cinfo->output_scanline; + } + + /* Skipping is much simpler when context rows are not required. */ + else { + if (num_lines < lines_left_in_iMCU_row) { + increment_simple_rowgroup_ctr(cinfo, num_lines); + return num_lines; + } else { + cinfo->output_scanline += lines_left_in_iMCU_row; + main_ptr->buffer_full = FALSE; + main_ptr->rowgroup_ctr = 0; + upsample->next_row_out = cinfo->max_v_samp_factor; + upsample->rows_to_go = cinfo->output_height - cinfo->output_scanline; + } + } + + /* Calculate how many full iMCU rows we can skip. */ + if (cinfo->upsample->need_context_rows) + lines_to_skip = ((lines_after_iMCU_row - 1) / lines_per_iMCU_row) * + lines_per_iMCU_row; + else + lines_to_skip = (lines_after_iMCU_row / lines_per_iMCU_row) * + lines_per_iMCU_row; + /* Calculate the number of lines that remain to be skipped after skipping all + * of the full iMCU rows that we can. We will not read these lines unless we + * have to. + */ + lines_to_read = lines_after_iMCU_row - lines_to_skip; + + /* For images requiring multiple scans (progressive, non-interleaved, etc.), + * all of the entropy decoding occurs in jpeg_start_decompress(), assuming + * that the input data source is non-suspending. This makes skipping easy. + */ + if (cinfo->inputctl->has_multiple_scans) { + if (cinfo->upsample->need_context_rows) { + cinfo->output_scanline += lines_to_skip; + cinfo->output_iMCU_row += lines_to_skip / lines_per_iMCU_row; + increment_iMCU_ctr(cinfo, lines_after_iMCU_row / lines_per_iMCU_row); + /* It is complex to properly move to the middle of a context block, so + * read the remaining lines instead of skipping them. + */ + dummy_buffer_setup(cinfo); + for (i = 0; i < lines_to_read; i++) + jpeg_read_scanlines(cinfo, &(cinfo->master->dummy_row_buffer), 1); + } else { + cinfo->output_scanline += lines_to_skip; + cinfo->output_iMCU_row += lines_to_skip / lines_per_iMCU_row; + increment_simple_rowgroup_ctr(cinfo, lines_to_read); + } + upsample->rows_to_go = cinfo->output_height - cinfo->output_scanline; + return num_lines; + } + + /* Skip the iMCU rows that we can safely skip. */ + for (i = 0; i < lines_to_skip; i += lines_per_iMCU_row) { + for (y = 0; y < coef->MCU_rows_per_iMCU_row; y++) { + for (x = 0; x < cinfo->MCUs_per_row; x++) { + /* Calling decode_mcu() with a NULL pointer causes it to discard the + * decoded coefficients. This is ~5% faster for large subsets, but + * it's tough to tell a difference for smaller images. Another + * advantage of discarding coefficients is that it allows us to avoid + * accessing the private field cinfo->coef->MCU_buffer (which would + * normally be a parameter to decode_mcu().) + */ + (*cinfo->entropy->decode_mcu) (cinfo, NULL); + } + } + cinfo->input_iMCU_row++; + cinfo->output_iMCU_row++; + if (cinfo->input_iMCU_row < cinfo->total_iMCU_rows) + start_iMCU_row(cinfo); + else + (*cinfo->inputctl->finish_input_pass) (cinfo); + } + cinfo->output_scanline += lines_to_skip; + + if (cinfo->upsample->need_context_rows) { + /* Context-based upsampling keeps track of iMCU rows. */ + increment_iMCU_ctr(cinfo, lines_to_skip / lines_per_iMCU_row); + + /* It is complex to properly move to the middle of a context block, so + * read the remaining lines instead of skipping them. + */ + dummy_buffer_setup(cinfo); + for (i = 0; i < lines_to_read; i++) + jpeg_read_scanlines(cinfo, &(cinfo->master->dummy_row_buffer), 1); + } else { + increment_simple_rowgroup_ctr(cinfo, lines_to_read); + } + + /* Since skipping lines involves skipping the upsampling step, the value of + * "rows_to_go" will become invalid unless we set it here. NOTE: This is a + * bit odd, since "rows_to_go" seems to be redundantly keeping track of + * output_scanline. + */ + upsample->rows_to_go = cinfo->output_height - cinfo->output_scanline; + + /* Always skip the requested number of lines. */ + return num_lines; +} + /* * Alternate entry point to read raw data. * Processes exactly one iMCU row per call, unless suspended. @@ -271,6 +507,13 @@ jpeg_finish_output (j_decompress_ptr cinfo) if ((*cinfo->inputctl->consume_input) (cinfo) == JPEG_SUSPENDED) return FALSE; /* Suspend, come back later */ } + /* Clean up row buffer */ + if (cinfo->master->dummy_row_buffer) { + int nc = (cinfo->out_color_space == JCS_RGB565) ? + 2 : cinfo->out_color_components; + jpeg_free_small((j_common_ptr) cinfo, cinfo->master->dummy_row_buffer, + cinfo->output_width * nc * sizeof(JSAMPLE)); + } cinfo->global_state = DSTATE_BUFIMAGE; return TRUE; } diff --git a/jdarith.c b/jdarith.c index c6a1a99a..24e67fbe 100644 --- a/jdarith.c +++ b/jdarith.c @@ -3,8 +3,8 @@ * * This file was part of the Independent JPEG Group's software: * Developed 1997-2009 by Guido Vollbeding. - * It was modified by The libjpeg-turbo Project to include only code relevant - * to libjpeg-turbo. + * libjpeg-turbo Modifications: + * Copyright (C) 2015, D. R. Commander. * For conditions of distribution and use, see the accompanying README file. * * This file contains portable arithmetic entropy decoding routines for JPEG @@ -516,7 +516,7 @@ decode_mcu (j_decompress_ptr cinfo, JBLOCKROW *MCU_data) /* Outer loop handles each block in the MCU */ for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) { - block = MCU_data[blkn]; + block = MCU_data ? MCU_data[blkn] : NULL; ci = cinfo->MCU_membership[blkn]; compptr = cinfo->cur_comp_info[ci]; @@ -563,7 +563,8 @@ decode_mcu (j_decompress_ptr cinfo, JBLOCKROW *MCU_data) entropy->last_dc_val[ci] += v; } - (*block)[0] = (JCOEF) entropy->last_dc_val[ci]; + if (block) + (*block)[0] = (JCOEF) entropy->last_dc_val[ci]; /* Sections F.2.4.2 & F.1.4.4.2: Decoding of AC coefficients */ @@ -607,7 +608,8 @@ decode_mcu (j_decompress_ptr cinfo, JBLOCKROW *MCU_data) while (m >>= 1) if (arith_decode(cinfo, st)) v |= m; v += 1; if (sign) v = -v; - (*block)[jpeg_natural_order[k]] = (JCOEF) v; + if (block) + (*block)[jpeg_natural_order[k]] = (JCOEF) v; } } diff --git a/jdcoefct.c b/jdcoefct.c index 199a628b..17a97b1b 100644 --- a/jdcoefct.c +++ b/jdcoefct.c @@ -4,6 +4,7 @@ * This file was part of the Independent JPEG Group's software: * Copyright (C) 1994-1997, Thomas G. Lane. * libjpeg-turbo Modifications: + * Copyright 2009 Pierre Ossman for Cendio AB * Copyright (C) 2010, D. R. Commander. * For conditions of distribution and use, see the accompanying README file. * @@ -16,53 +17,9 @@ * Also, the input side (only) is used when reading a file for transcoding. */ -#define JPEG_INTERNALS -#include "jinclude.h" -#include "jpeglib.h" +#include "jdcoefct.h" #include "jpegcomp.h" -/* Block smoothing is only applicable for progressive JPEG, so: */ -#ifndef D_PROGRESSIVE_SUPPORTED -#undef BLOCK_SMOOTHING_SUPPORTED -#endif - -/* Private buffer controller object */ - -typedef struct { - struct jpeg_d_coef_controller pub; /* public fields */ - - /* These variables keep track of the current location of the input side. */ - /* cinfo->input_iMCU_row is also used for this. */ - JDIMENSION MCU_ctr; /* counts MCUs processed in current row */ - int MCU_vert_offset; /* counts MCU rows within iMCU row */ - int MCU_rows_per_iMCU_row; /* number of such rows needed */ - - /* The output side's location is represented by cinfo->output_iMCU_row. */ - - /* In single-pass modes, it's sufficient to buffer just one MCU. - * We allocate a workspace of D_MAX_BLOCKS_IN_MCU coefficient blocks, - * and let the entropy decoder write into that workspace each time. - * In multi-pass modes, this array points to the current MCU's blocks - * within the virtual arrays; it is used only by the input side. - */ - JBLOCKROW MCU_buffer[D_MAX_BLOCKS_IN_MCU]; - - /* Temporary workspace for one MCU */ - JCOEF * workspace; - -#ifdef D_MULTISCAN_FILES_SUPPORTED - /* In multi-pass modes, we need a virtual block array for each component. */ - jvirt_barray_ptr whole_image[MAX_COMPONENTS]; -#endif - -#ifdef BLOCK_SMOOTHING_SUPPORTED - /* When doing block smoothing, we latch coefficient Al values here */ - int * coef_bits_latch; -#define SAVED_COEFS 6 /* we save coef_bits[0..5] */ -#endif -} my_coef_controller; - -typedef my_coef_controller * my_coef_ptr; /* Forward declarations */ METHODDEF(int) decompress_onepass @@ -78,30 +35,6 @@ METHODDEF(int) decompress_smooth_data #endif -LOCAL(void) -start_iMCU_row (j_decompress_ptr cinfo) -/* Reset within-iMCU-row counters for a new row (input side) */ -{ - my_coef_ptr coef = (my_coef_ptr) cinfo->coef; - - /* In an interleaved scan, an MCU row is the same as an iMCU row. - * In a noninterleaved scan, an iMCU row has v_samp_factor MCU rows. - * But at the bottom of the image, process only what's left. - */ - if (cinfo->comps_in_scan > 1) { - coef->MCU_rows_per_iMCU_row = 1; - } else { - if (cinfo->input_iMCU_row < (cinfo->total_iMCU_rows-1)) - coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->v_samp_factor; - else - coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->last_row_height; - } - - coef->MCU_ctr = 0; - coef->MCU_vert_offset = 0; -} - - /* * Initialize for an input processing pass. */ diff --git a/jdcoefct.h b/jdcoefct.h new file mode 100644 index 00000000..2f7bbe5e --- /dev/null +++ b/jdcoefct.h @@ -0,0 +1,82 @@ +/* + * jdcoefct.h + * + * This file was part of the Independent JPEG Group's software: + * Copyright (C) 1994-1997, Thomas G. Lane. + * libjpeg-turbo Modifications: + * Copyright 2009 Pierre Ossman for Cendio AB + * For conditions of distribution and use, see the accompanying README file. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* Block smoothing is only applicable for progressive JPEG, so: */ +#ifndef D_PROGRESSIVE_SUPPORTED +#undef BLOCK_SMOOTHING_SUPPORTED +#endif + + +/* Private buffer controller object */ + +typedef struct { + struct jpeg_d_coef_controller pub; /* public fields */ + + /* These variables keep track of the current location of the input side. */ + /* cinfo->input_iMCU_row is also used for this. */ + JDIMENSION MCU_ctr; /* counts MCUs processed in current row */ + int MCU_vert_offset; /* counts MCU rows within iMCU row */ + int MCU_rows_per_iMCU_row; /* number of such rows needed */ + + /* The output side's location is represented by cinfo->output_iMCU_row. */ + + /* In single-pass modes, it's sufficient to buffer just one MCU. + * We allocate a workspace of D_MAX_BLOCKS_IN_MCU coefficient blocks, + * and let the entropy decoder write into that workspace each time. + * In multi-pass modes, this array points to the current MCU's blocks + * within the virtual arrays; it is used only by the input side. + */ + JBLOCKROW MCU_buffer[D_MAX_BLOCKS_IN_MCU]; + + /* Temporary workspace for one MCU */ + JCOEF * workspace; + +#ifdef D_MULTISCAN_FILES_SUPPORTED + /* In multi-pass modes, we need a virtual block array for each component. */ + jvirt_barray_ptr whole_image[MAX_COMPONENTS]; +#endif + +#ifdef BLOCK_SMOOTHING_SUPPORTED + /* When doing block smoothing, we latch coefficient Al values here */ + int * coef_bits_latch; +#define SAVED_COEFS 6 /* we save coef_bits[0..5] */ +#endif +} my_coef_controller; + +typedef my_coef_controller * my_coef_ptr; + + +LOCAL(void) +start_iMCU_row (j_decompress_ptr cinfo) +/* Reset within-iMCU-row counters for a new row (input side) */ +{ + my_coef_ptr coef = (my_coef_ptr) cinfo->coef; + + /* In an interleaved scan, an MCU row is the same as an iMCU row. + * In a noninterleaved scan, an iMCU row has v_samp_factor MCU rows. + * But at the bottom of the image, process only what's left. + */ + if (cinfo->comps_in_scan > 1) { + coef->MCU_rows_per_iMCU_row = 1; + } else { + if (cinfo->input_iMCU_row < (cinfo->total_iMCU_rows-1)) + coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->v_samp_factor; + else + coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->last_row_height; + } + + coef->MCU_ctr = 0; + coef->MCU_vert_offset = 0; +} diff --git a/jdhuff.c b/jdhuff.c index cbdce7d4..877ff10e 100644 --- a/jdhuff.c +++ b/jdhuff.c @@ -4,7 +4,7 @@ * This file was part of the Independent JPEG Group's software: * Copyright (C) 1991-1997, Thomas G. Lane. * libjpeg-turbo Modifications: - * Copyright (C) 2009-2011, D. R. Commander. + * Copyright (C) 2009-2011, 2015, D. R. Commander. * For conditions of distribution and use, see the accompanying README file. * * This file contains Huffman entropy decoding routines. @@ -562,7 +562,7 @@ decode_mcu_slow (j_decompress_ptr cinfo, JBLOCKROW *MCU_data) ASSIGN_STATE(state, entropy->saved); for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) { - JBLOCKROW block = MCU_data[blkn]; + JBLOCKROW block = MCU_data ? MCU_data[blkn] : NULL; d_derived_tbl * dctbl = entropy->dc_cur_tbls[blkn]; d_derived_tbl * actbl = entropy->ac_cur_tbls[blkn]; register int s, k, r; @@ -582,11 +582,13 @@ decode_mcu_slow (j_decompress_ptr cinfo, JBLOCKROW *MCU_data) int ci = cinfo->MCU_membership[blkn]; s += state.last_dc_val[ci]; state.last_dc_val[ci] = s; - /* Output the DC coefficient (assumes jpeg_natural_order[0] = 0) */ - (*block)[0] = (JCOEF) s; + if (block) { + /* Output the DC coefficient (assumes jpeg_natural_order[0] = 0) */ + (*block)[0] = (JCOEF) s; + } } - if (entropy->ac_needed[blkn]) { + if (entropy->ac_needed[blkn] && block) { /* Section F.2.2.2: decode the AC coefficients */ /* Since zeroes are skipped, output area must be cleared beforehand */ @@ -659,7 +661,7 @@ decode_mcu_fast (j_decompress_ptr cinfo, JBLOCKROW *MCU_data) ASSIGN_STATE(state, entropy->saved); for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) { - JBLOCKROW block = MCU_data[blkn]; + JBLOCKROW block = MCU_data ? MCU_data[blkn] : NULL; d_derived_tbl * dctbl = entropy->dc_cur_tbls[blkn]; d_derived_tbl * actbl = entropy->ac_cur_tbls[blkn]; register int s, k, r, l; @@ -675,10 +677,11 @@ decode_mcu_fast (j_decompress_ptr cinfo, JBLOCKROW *MCU_data) int ci = cinfo->MCU_membership[blkn]; s += state.last_dc_val[ci]; state.last_dc_val[ci] = s; - (*block)[0] = (JCOEF) s; + if (block) + (*block)[0] = (JCOEF) s; } - if (entropy->ac_needed[blkn]) { + if (entropy->ac_needed[blkn] && block) { for (k = 1; k < DCTSIZE2; k++) { HUFF_DECODE_FAST(s, l, actbl); diff --git a/jdmainct.c b/jdmainct.c index 7f7bd33e..e4ba1c4f 100644 --- a/jdmainct.c +++ b/jdmainct.c @@ -15,10 +15,7 @@ * supplies the equivalent of the main buffer in that case. */ -#define JPEG_INTERNALS -#include "jinclude.h" -#include "jpeglib.h" -#include "jpegcomp.h" +#include "jdmainct.h" /* @@ -112,36 +109,6 @@ */ -/* Private buffer controller object */ - -typedef struct { - struct jpeg_d_main_controller pub; /* public fields */ - - /* Pointer to allocated workspace (M or M+2 row groups). */ - JSAMPARRAY buffer[MAX_COMPONENTS]; - - boolean buffer_full; /* Have we gotten an iMCU row from decoder? */ - JDIMENSION rowgroup_ctr; /* counts row groups output to postprocessor */ - - /* Remaining fields are only used in the context case. */ - - /* These are the master pointers to the funny-order pointer lists. */ - JSAMPIMAGE xbuffer[2]; /* pointers to weird pointer lists */ - - int whichptr; /* indicates which pointer set is now in use */ - int context_state; /* process_data state machine status */ - JDIMENSION rowgroups_avail; /* row groups available to postprocessor */ - JDIMENSION iMCU_row_ctr; /* counts iMCU rows to detect image top/bot */ -} my_main_controller; - -typedef my_main_controller * my_main_ptr; - -/* context_state values: */ -#define CTX_PREPARE_FOR_IMCU 0 /* need to prepare for MCU row */ -#define CTX_PROCESS_IMCU 1 /* feeding iMCU to postprocessor */ -#define CTX_POSTPONED_ROW 2 /* feeding postponed row group */ - - /* Forward declarations */ METHODDEF(void) process_data_simple_main (j_decompress_ptr cinfo, JSAMPARRAY output_buf, @@ -237,34 +204,6 @@ make_funny_pointers (j_decompress_ptr cinfo) } -LOCAL(void) -set_wraparound_pointers (j_decompress_ptr cinfo) -/* Set up the "wraparound" pointers at top and bottom of the pointer lists. - * This changes the pointer list state from top-of-image to the normal state. - */ -{ - my_main_ptr main_ptr = (my_main_ptr) cinfo->main; - int ci, i, rgroup; - int M = cinfo->_min_DCT_scaled_size; - jpeg_component_info *compptr; - JSAMPARRAY xbuf0, xbuf1; - - for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; - ci++, compptr++) { - rgroup = (compptr->v_samp_factor * compptr->_DCT_scaled_size) / - cinfo->_min_DCT_scaled_size; /* height of a row group of component */ - xbuf0 = main_ptr->xbuffer[0][ci]; - xbuf1 = main_ptr->xbuffer[1][ci]; - for (i = 0; i < rgroup; i++) { - xbuf0[i - rgroup] = xbuf0[rgroup*(M+1) + i]; - xbuf1[i - rgroup] = xbuf1[rgroup*(M+1) + i]; - xbuf0[rgroup*(M+2) + i] = xbuf0[i]; - xbuf1[rgroup*(M+2) + i] = xbuf1[i]; - } - } -} - - LOCAL(void) set_bottom_pointers (j_decompress_ptr cinfo) /* Change the pointer lists to duplicate the last sample row at the bottom diff --git a/jdmainct.h b/jdmainct.h new file mode 100644 index 00000000..37ab27d9 --- /dev/null +++ b/jdmainct.h @@ -0,0 +1,71 @@ +/* + * jdmainct.h + * + * This file was part of the Independent JPEG Group's software: + * Copyright (C) 1994-1996, Thomas G. Lane. + * For conditions of distribution and use, see the accompanying README file. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jpegcomp.h" + + +/* Private buffer controller object */ + +typedef struct { + struct jpeg_d_main_controller pub; /* public fields */ + + /* Pointer to allocated workspace (M or M+2 row groups). */ + JSAMPARRAY buffer[MAX_COMPONENTS]; + + boolean buffer_full; /* Have we gotten an iMCU row from decoder? */ + JDIMENSION rowgroup_ctr; /* counts row groups output to postprocessor */ + + /* Remaining fields are only used in the context case. */ + + /* These are the master pointers to the funny-order pointer lists. */ + JSAMPIMAGE xbuffer[2]; /* pointers to weird pointer lists */ + + int whichptr; /* indicates which pointer set is now in use */ + int context_state; /* process_data state machine status */ + JDIMENSION rowgroups_avail; /* row groups available to postprocessor */ + JDIMENSION iMCU_row_ctr; /* counts iMCU rows to detect image top/bot */ +} my_main_controller; + +typedef my_main_controller * my_main_ptr; + + +/* context_state values: */ +#define CTX_PREPARE_FOR_IMCU 0 /* need to prepare for MCU row */ +#define CTX_PROCESS_IMCU 1 /* feeding iMCU to postprocessor */ +#define CTX_POSTPONED_ROW 2 /* feeding postponed row group */ + + +LOCAL(void) +set_wraparound_pointers (j_decompress_ptr cinfo) +/* Set up the "wraparound" pointers at top and bottom of the pointer lists. + * This changes the pointer list state from top-of-image to the normal state. + */ +{ + my_main_ptr main_ptr = (my_main_ptr) cinfo->main; + int ci, i, rgroup; + int M = cinfo->_min_DCT_scaled_size; + jpeg_component_info *compptr; + JSAMPARRAY xbuf0, xbuf1; + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + rgroup = (compptr->v_samp_factor * compptr->_DCT_scaled_size) / + cinfo->_min_DCT_scaled_size; /* height of a row group of component */ + xbuf0 = main_ptr->xbuffer[0][ci]; + xbuf1 = main_ptr->xbuffer[1][ci]; + for (i = 0; i < rgroup; i++) { + xbuf0[i - rgroup] = xbuf0[rgroup*(M+1) + i]; + xbuf1[i - rgroup] = xbuf1[rgroup*(M+1) + i]; + xbuf0[rgroup*(M+2) + i] = xbuf0[i]; + xbuf1[rgroup*(M+2) + i] = xbuf1[i]; + } + } +} diff --git a/jdsample.c b/jdsample.c index 27529667..5738c2fd 100644 --- a/jdsample.c +++ b/jdsample.c @@ -22,51 +22,11 @@ * Pub. by IEEE Computer Society Press, Los Alamitos, CA. ISBN 0-8186-8944-7. */ -#define JPEG_INTERNALS -#include "jinclude.h" -#include "jpeglib.h" +#include "jdsample.h" #include "jsimd.h" #include "jpegcomp.h" -/* Pointer to routine to upsample a single component */ -typedef void (*upsample1_ptr) (j_decompress_ptr cinfo, - jpeg_component_info * compptr, - JSAMPARRAY input_data, - JSAMPARRAY * output_data_ptr); - -/* Private subobject */ - -typedef struct { - struct jpeg_upsampler pub; /* public fields */ - - /* Color conversion buffer. When using separate upsampling and color - * conversion steps, this buffer holds one upsampled row group until it - * has been color converted and output. - * Note: we do not allocate any storage for component(s) which are full-size, - * ie do not need rescaling. The corresponding entry of color_buf[] is - * simply set to point to the input data array, thereby avoiding copying. - */ - JSAMPARRAY color_buf[MAX_COMPONENTS]; - - /* Per-component upsampling method pointers */ - upsample1_ptr methods[MAX_COMPONENTS]; - - int next_row_out; /* counts rows emitted from color_buf */ - JDIMENSION rows_to_go; /* counts rows remaining in image */ - - /* Height of an input row group for each component. */ - int rowgroup_height[MAX_COMPONENTS]; - - /* These arrays save pixel expansion factors so that int_expand need not - * recompute them each time. They are unused for other upsampling methods. - */ - UINT8 h_expand[MAX_COMPONENTS]; - UINT8 v_expand[MAX_COMPONENTS]; -} my_upsampler; - -typedef my_upsampler * my_upsample_ptr; - /* * Initialize for an upsampling pass. diff --git a/jdsample.h b/jdsample.h new file mode 100644 index 00000000..5226f268 --- /dev/null +++ b/jdsample.h @@ -0,0 +1,50 @@ +/* + * jdsample.h + * + * This file was part of the Independent JPEG Group's software: + * Copyright (C) 1991-1996, Thomas G. Lane. + * For conditions of distribution and use, see the accompanying README file. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* Pointer to routine to upsample a single component */ +typedef void (*upsample1_ptr) (j_decompress_ptr cinfo, + jpeg_component_info * compptr, + JSAMPARRAY input_data, + JSAMPARRAY * output_data_ptr); + +/* Private subobject */ + +typedef struct { + struct jpeg_upsampler pub; /* public fields */ + + /* Color conversion buffer. When using separate upsampling and color + * conversion steps, this buffer holds one upsampled row group until it + * has been color converted and output. + * Note: we do not allocate any storage for component(s) which are full-size, + * ie do not need rescaling. The corresponding entry of color_buf[] is + * simply set to point to the input data array, thereby avoiding copying. + */ + JSAMPARRAY color_buf[MAX_COMPONENTS]; + + /* Per-component upsampling method pointers */ + upsample1_ptr methods[MAX_COMPONENTS]; + + int next_row_out; /* counts rows emitted from color_buf */ + JDIMENSION rows_to_go; /* counts rows remaining in image */ + + /* Height of an input row group for each component. */ + int rowgroup_height[MAX_COMPONENTS]; + + /* These arrays save pixel expansion factors so that int_expand need not + * recompute them each time. They are unused for other upsampling methods. + */ + UINT8 h_expand[MAX_COMPONENTS]; + UINT8 v_expand[MAX_COMPONENTS]; +} my_upsampler; + +typedef my_upsampler * my_upsample_ptr; diff --git a/jpegint.h b/jpegint.h index 025accd9..0e4dafe0 100644 --- a/jpegint.h +++ b/jpegint.h @@ -4,8 +4,8 @@ * This file was part of the Independent JPEG Group's software: * Copyright (C) 1991-1997, Thomas G. Lane. * Modified 1997-2009 by Guido Vollbeding. - * It was modified by The libjpeg-turbo Project to include only code relevant - * to libjpeg-turbo. + * libjpeg-turbo Modifications: + * Copyright (C) 2015, Google, Inc. * For conditions of distribution and use, see the accompanying README file. * * This file provides common declarations for the various JPEG modules. @@ -137,6 +137,12 @@ struct jpeg_decomp_master { /* State variables made visible to other modules */ boolean is_dummy_pass; /* True during 1st pass for 2-pass quant */ + + /* Buffer large enough to store an output row. This is used when + * jpeg_skip_scanlines() chooses to "skip" a row by reading it into this + * dummy buffer. + */ + JSAMPROW dummy_row_buffer; }; /* Input control module */ diff --git a/jpeglib.h b/jpeglib.h index 9615c5d0..a41bec44 100644 --- a/jpeglib.h +++ b/jpeglib.h @@ -6,6 +6,7 @@ * Modified 2002-2009 by Guido Vollbeding. * libjpeg-turbo Modifications: * Copyright (C) 2009-2011, 2013-2014, D. R. Commander. + * Copyright (C) 2015, Google, Inc. * For conditions of distribution and use, see the accompanying README file. * * This file defines the application interface for the JPEG library. @@ -990,6 +991,8 @@ EXTERN(boolean) jpeg_start_decompress (j_decompress_ptr cinfo); EXTERN(JDIMENSION) jpeg_read_scanlines (j_decompress_ptr cinfo, JSAMPARRAY scanlines, JDIMENSION max_lines); +EXTERN(JDIMENSION) jpeg_skip_scanlines (j_decompress_ptr cinfo, + JDIMENSION num_lines); EXTERN(boolean) jpeg_finish_decompress (j_decompress_ptr cinfo); /* Replaces jpeg_read_scanlines when reading raw downsampled data. */ diff --git a/libjpeg.txt b/libjpeg.txt index 7dbb3542..52b6d8b8 100644 --- a/libjpeg.txt +++ b/libjpeg.txt @@ -3,7 +3,8 @@ USING THE IJG JPEG LIBRARY This file was part of the Independent JPEG Group's software: Copyright (C) 1994-2011, Thomas G. Lane, Guido Vollbeding. libjpeg-turbo Modifications: -Copyright (C) 2010, 2014, D. R. Commander. +Copyright (C) 2010, 2014, 2015, D. R. Commander. +Copyright (C) 2015, Google, Inc. For conditions of distribution and use, see the accompanying README file. @@ -729,6 +730,49 @@ jpeg_abort_decompress() or jpeg_abort() if you want to reuse the object. The previous discussion of aborting compression cycles applies here too. +Skipping rows when decompressing +-------------------------------- + +jpeg_skip_scanlines(j_decompress_ptr cinfo, JDIMENSION num_lines); + +This function provides application programmers with the ability to skip over +multiple rows in the JPEG image, thus decoding only a subset of the image data. +This is convenient for performance-critical applications that wish to view only +a portion of a large JPEG image without decompressing the whole thing. It it +also useful in memory-constrained environments (such as on mobile devices.) + +Suspending data sources are not supported by this function. Calling +jpeg_skip_scanlines() with a suspending data source will result in undefined +behavior. + +jpeg_skip_scanlines() will not allow skipping past the bottom of the image. If +the value of num_lines is large enough to skip past the bottom of the image, +then the function will skip to the end of the image instead. + +If the value of num_lines is valid, then jpeg_skip_scanlines() will always +skip all of the input rows requested. There is no need to inspect the return +value of the function in that case. + +Best results will be achieved by calling jpeg_skip_scanlines() for large chunks +of rows. The function should be viewed as a way to quickly jump to a +particular vertical offset in the JPEG image in order to decode a subset of the +image. Used in this manner, it will provide significant performance +improvements. + +Calling jpeg_skip_scanlines() for small values of num_lines has several +potential drawbacks: + 1) JPEG decompression occurs in blocks, so if jpeg_skip_scanlines() is + called from the middle of a decompression block, then it is likely that + much of the decompression work has already been done for the first + couple of rows that need to be skipped. + 2) When this function returns, it must leave the decompressor in a state + such that it is ready to read the next line. This may involve + decompressing a block that must be partially skipped. +These issues are especially tricky for cases in which upsampling requires +context rows. In the worst case, jpeg_skip_scanlines() will perform similarly +to jpeg_read_scanlines() (since it will actually call jpeg_read_scanlines().) + + Mechanics of usage: include files, linking, etc -----------------------------------------------