| /* |
| * jcpipe.c |
| * |
| * Copyright (C) 1991, 1992, Thomas G. Lane. |
| * This file is part of the Independent JPEG Group's software. |
| * For conditions of distribution and use, see the accompanying README file. |
| * |
| * This file contains compression pipeline controllers. |
| * These routines are invoked via the c_pipeline_controller method. |
| * |
| * There are four basic pipeline controllers, one for each combination of: |
| * single-scan JPEG file (single component or fully interleaved) |
| * vs. multiple-scan JPEG file (noninterleaved or partially interleaved). |
| * |
| * optimization of entropy encoding parameters |
| * vs. usage of default encoding parameters. |
| * |
| * Note that these conditions determine the needs for "big" arrays: |
| * multiple scans imply a big array for splitting the color components; |
| * entropy encoding optimization needs a big array for the MCU data. |
| * |
| * All but the simplest controller (single-scan, no optimization) can be |
| * compiled out through configuration options, if you need to make a minimal |
| * implementation. |
| */ |
| |
| #include "jinclude.h" |
| |
| |
| /* |
| * About the data structures: |
| * |
| * The processing chunk size for subsampling is referred to in this file as |
| * a "row group": a row group is defined as Vk (v_samp_factor) sample rows of |
| * any component after subsampling, or Vmax (max_v_samp_factor) unsubsampled |
| * rows. In an interleaved scan each MCU row contains exactly DCTSIZE row |
| * groups of each component in the scan. In a noninterleaved scan an MCU row |
| * is one row of blocks, which might not be an integral number of row groups; |
| * for convenience we use a buffer of the same size as in interleaved scans, |
| * and process Vk MCU rows in each burst of subsampling. |
| * To provide context for the subsampling step, we have to retain the last |
| * two row groups of the previous MCU row while reading in the next MCU row |
| * (or set of Vk MCU rows). To do this without copying data about, we create |
| * a rather strange data structure. Exactly DCTSIZE+2 row groups of samples |
| * are allocated, but we create two different sets of pointers to this array. |
| * The second set swaps the last two pairs of row groups. By working |
| * alternately with the two sets of pointers, we can access the data in the |
| * desired order. |
| */ |
| |
| |
| |
| /* |
| * Utility routines: common code for pipeline controllers |
| */ |
| |
| LOCAL void |
| interleaved_scan_setup (compress_info_ptr cinfo) |
| /* Compute all derived info for an interleaved (multi-component) scan */ |
| /* On entry, cinfo->comps_in_scan and cinfo->cur_comp_info[] are set up */ |
| { |
| short ci, mcublks; |
| jpeg_component_info *compptr; |
| |
| if (cinfo->comps_in_scan > MAX_COMPS_IN_SCAN) |
| ERREXIT(cinfo->emethods, "Too many components for interleaved scan"); |
| |
| cinfo->MCUs_per_row = (cinfo->image_width |
| + cinfo->max_h_samp_factor*DCTSIZE - 1) |
| / (cinfo->max_h_samp_factor*DCTSIZE); |
| |
| cinfo->MCU_rows_in_scan = (cinfo->image_height |
| + cinfo->max_v_samp_factor*DCTSIZE - 1) |
| / (cinfo->max_v_samp_factor*DCTSIZE); |
| |
| cinfo->blocks_in_MCU = 0; |
| |
| for (ci = 0; ci < cinfo->comps_in_scan; ci++) { |
| compptr = cinfo->cur_comp_info[ci]; |
| /* for interleaved scan, sampling factors give # of blocks per component */ |
| compptr->MCU_width = compptr->h_samp_factor; |
| compptr->MCU_height = compptr->v_samp_factor; |
| compptr->MCU_blocks = compptr->MCU_width * compptr->MCU_height; |
| /* compute physical dimensions of component */ |
| compptr->subsampled_width = jround_up(compptr->true_comp_width, |
| (long) (compptr->MCU_width*DCTSIZE)); |
| compptr->subsampled_height = jround_up(compptr->true_comp_height, |
| (long) (compptr->MCU_height*DCTSIZE)); |
| /* Sanity check */ |
| if (compptr->subsampled_width != |
| (cinfo->MCUs_per_row * (compptr->MCU_width*DCTSIZE))) |
| ERREXIT(cinfo->emethods, "I'm confused about the image width"); |
| /* Prepare array describing MCU composition */ |
| mcublks = compptr->MCU_blocks; |
| if (cinfo->blocks_in_MCU + mcublks > MAX_BLOCKS_IN_MCU) |
| ERREXIT(cinfo->emethods, "Sampling factors too large for interleaved scan"); |
| while (mcublks-- > 0) { |
| cinfo->MCU_membership[cinfo->blocks_in_MCU++] = ci; |
| } |
| } |
| |
| (*cinfo->methods->c_per_scan_method_selection) (cinfo); |
| } |
| |
| |
| LOCAL void |
| noninterleaved_scan_setup (compress_info_ptr cinfo) |
| /* Compute all derived info for a noninterleaved (single-component) scan */ |
| /* On entry, cinfo->comps_in_scan = 1 and cinfo->cur_comp_info[0] is set up */ |
| { |
| jpeg_component_info *compptr = cinfo->cur_comp_info[0]; |
| |
| /* for noninterleaved scan, always one block per MCU */ |
| compptr->MCU_width = 1; |
| compptr->MCU_height = 1; |
| compptr->MCU_blocks = 1; |
| /* compute physical dimensions of component */ |
| compptr->subsampled_width = jround_up(compptr->true_comp_width, |
| (long) DCTSIZE); |
| compptr->subsampled_height = jround_up(compptr->true_comp_height, |
| (long) DCTSIZE); |
| |
| cinfo->MCUs_per_row = compptr->subsampled_width / DCTSIZE; |
| cinfo->MCU_rows_in_scan = compptr->subsampled_height / DCTSIZE; |
| |
| /* Prepare array describing MCU composition */ |
| cinfo->blocks_in_MCU = 1; |
| cinfo->MCU_membership[0] = 0; |
| |
| (*cinfo->methods->c_per_scan_method_selection) (cinfo); |
| } |
| |
| |
| |
| LOCAL void |
| alloc_sampling_buffer (compress_info_ptr cinfo, JSAMPIMAGE fullsize_data[2], |
| long fullsize_width) |
| /* Create a pre-subsampling data buffer having the desired structure */ |
| /* (see comments at head of file) */ |
| { |
| short ci, vs, i; |
| |
| vs = cinfo->max_v_samp_factor; /* row group height */ |
| |
| /* Get top-level space for array pointers */ |
| fullsize_data[0] = (JSAMPIMAGE) (*cinfo->emethods->alloc_small) |
| (cinfo->num_components * SIZEOF(JSAMPARRAY)); |
| fullsize_data[1] = (JSAMPIMAGE) (*cinfo->emethods->alloc_small) |
| (cinfo->num_components * SIZEOF(JSAMPARRAY)); |
| |
| for (ci = 0; ci < cinfo->num_components; ci++) { |
| /* Allocate the real storage */ |
| fullsize_data[0][ci] = (*cinfo->emethods->alloc_small_sarray) |
| (fullsize_width, |
| (long) (vs * (DCTSIZE+2))); |
| /* Create space for the scrambled-order pointers */ |
| fullsize_data[1][ci] = (JSAMPARRAY) (*cinfo->emethods->alloc_small) |
| (vs * (DCTSIZE+2) * SIZEOF(JSAMPROW)); |
| /* Duplicate the first DCTSIZE-2 row groups */ |
| for (i = 0; i < vs * (DCTSIZE-2); i++) { |
| fullsize_data[1][ci][i] = fullsize_data[0][ci][i]; |
| } |
| /* Copy the last four row groups in swapped order */ |
| for (i = 0; i < vs * 2; i++) { |
| fullsize_data[1][ci][vs*DCTSIZE + i] = fullsize_data[0][ci][vs*(DCTSIZE-2) + i]; |
| fullsize_data[1][ci][vs*(DCTSIZE-2) + i] = fullsize_data[0][ci][vs*DCTSIZE + i]; |
| } |
| } |
| } |
| |
| |
| #if 0 /* this routine not currently needed */ |
| |
| LOCAL void |
| free_sampling_buffer (compress_info_ptr cinfo, JSAMPIMAGE fullsize_data[2]) |
| /* Release a sampling buffer created by alloc_sampling_buffer */ |
| { |
| short ci; |
| |
| for (ci = 0; ci < cinfo->num_components; ci++) { |
| /* Free the real storage */ |
| (*cinfo->emethods->free_small_sarray) (fullsize_data[0][ci]); |
| /* Free the scrambled-order pointers */ |
| (*cinfo->emethods->free_small) ((void *) fullsize_data[1][ci]); |
| } |
| |
| /* Free the top-level space */ |
| (*cinfo->emethods->free_small) ((void *) fullsize_data[0]); |
| (*cinfo->emethods->free_small) ((void *) fullsize_data[1]); |
| } |
| |
| #endif |
| |
| |
| LOCAL void |
| subsample (compress_info_ptr cinfo, |
| JSAMPIMAGE fullsize_data, JSAMPIMAGE subsampled_data, |
| long fullsize_width, |
| short above, short current, short below, short out) |
| /* Do subsampling of a single row group (of each component). */ |
| /* above, current, below are indexes of row groups in fullsize_data; */ |
| /* out is the index of the target row group in subsampled_data. */ |
| /* Special case: above, below can be -1 to indicate top, bottom of image. */ |
| { |
| jpeg_component_info *compptr; |
| JSAMPARRAY above_ptr, below_ptr; |
| JSAMPROW dummy[MAX_SAMP_FACTOR]; /* for subsample expansion at top/bottom */ |
| short ci, vs, i; |
| |
| vs = cinfo->max_v_samp_factor; /* row group height */ |
| |
| for (ci = 0; ci < cinfo->num_components; ci++) { |
| compptr = & cinfo->comp_info[ci]; |
| |
| if (above >= 0) |
| above_ptr = fullsize_data[ci] + above * vs; |
| else { |
| /* Top of image: make a dummy above-context with copies of 1st row */ |
| /* We assume current=0 in this case */ |
| for (i = 0; i < vs; i++) |
| dummy[i] = fullsize_data[ci][0]; |
| above_ptr = (JSAMPARRAY) dummy; /* possible near->far pointer conv */ |
| } |
| |
| if (below >= 0) |
| below_ptr = fullsize_data[ci] + below * vs; |
| else { |
| /* Bot of image: make a dummy below-context with copies of last row */ |
| for (i = 0; i < vs; i++) |
| dummy[i] = fullsize_data[ci][(current+1)*vs-1]; |
| below_ptr = (JSAMPARRAY) dummy; /* possible near->far pointer conv */ |
| } |
| |
| (*cinfo->methods->subsample[ci]) |
| (cinfo, (int) ci, |
| fullsize_width, (int) vs, |
| compptr->subsampled_width, (int) compptr->v_samp_factor, |
| above_ptr, |
| fullsize_data[ci] + current * vs, |
| below_ptr, |
| subsampled_data[ci] + out * compptr->v_samp_factor); |
| } |
| } |
| |
| |
| /* These vars are initialized by the pipeline controller for use by |
| * MCU_output_catcher. |
| * To avoid a lot of row-pointer overhead, we cram as many MCUs into each |
| * row of whole_scan_MCUs as we can get without exceeding 64KB per row. |
| */ |
| |
| #define MAX_WHOLE_ROW_BLOCKS ((int) (65500 / SIZEOF(JBLOCK))) /* max blocks/row */ |
| |
| static big_barray_ptr whole_scan_MCUs; /* Big array for saving the MCUs */ |
| static int MCUs_in_big_row; /* # of MCUs in each row of whole_scan_MCUs */ |
| static long next_whole_row; /* next row to access in whole_scan_MCUs */ |
| static int next_MCU_index; /* next MCU in current row */ |
| |
| |
| METHODDEF void |
| MCU_output_catcher (compress_info_ptr cinfo, JBLOCK *MCU_data) |
| /* Output method for siphoning off extract_MCUs output into a big array */ |
| { |
| static JBLOCKARRAY rowptr; |
| |
| if (next_MCU_index >= MCUs_in_big_row) { |
| rowptr = (*cinfo->emethods->access_big_barray) (whole_scan_MCUs, |
| next_whole_row, TRUE); |
| next_whole_row++; |
| next_MCU_index = 0; |
| } |
| |
| /* |
| * note that on 80x86, the cast applied to MCU_data implies |
| * near to far pointer conversion. |
| */ |
| jcopy_block_row((JBLOCKROW) MCU_data, |
| rowptr[0] + next_MCU_index * cinfo->blocks_in_MCU, |
| (long) cinfo->blocks_in_MCU); |
| next_MCU_index++; |
| } |
| |
| |
| METHODDEF void |
| dump_scan_MCUs (compress_info_ptr cinfo, MCU_output_method_ptr output_method) |
| /* Dump the MCUs saved in whole_scan_MCUs to the output method. */ |
| /* The method may be either the entropy encoder or some routine supplied */ |
| /* by the entropy optimizer. */ |
| { |
| /* On an 80x86 machine, the entropy encoder expects the passed data block |
| * to be in NEAR memory (for performance reasons), so we have to copy it |
| * back from the big array to a local array. On less brain-damaged CPUs |
| * we needn't do that. |
| */ |
| #ifdef NEED_FAR_POINTERS |
| JBLOCK MCU_data[MAX_BLOCKS_IN_MCU]; |
| #endif |
| long mcurow, mcuindex, next_row; |
| int next_index; |
| JBLOCKARRAY rowptr = NULL; /* init only to suppress compiler complaint */ |
| |
| next_row = 0; |
| next_index = MCUs_in_big_row; |
| |
| for (mcurow = 0; mcurow < cinfo->MCU_rows_in_scan; mcurow++) { |
| (*cinfo->methods->progress_monitor) (cinfo, mcurow, |
| cinfo->MCU_rows_in_scan); |
| for (mcuindex = 0; mcuindex < cinfo->MCUs_per_row; mcuindex++) { |
| if (next_index >= MCUs_in_big_row) { |
| rowptr = (*cinfo->emethods->access_big_barray) (whole_scan_MCUs, |
| next_row, FALSE); |
| next_row++; |
| next_index = 0; |
| } |
| #ifdef NEED_FAR_POINTERS |
| jcopy_block_row(rowptr[0] + next_index * cinfo->blocks_in_MCU, |
| (JBLOCKROW) MCU_data, /* casts near to far pointer! */ |
| (long) cinfo->blocks_in_MCU); |
| (*output_method) (cinfo, MCU_data); |
| #else |
| (*output_method) (cinfo, rowptr[0] + next_index * cinfo->blocks_in_MCU); |
| #endif |
| next_index++; |
| } |
| } |
| |
| cinfo->completed_passes++; |
| } |
| |
| |
| |
| /* |
| * Compression pipeline controller used for single-scan files |
| * with no optimization of entropy parameters. |
| */ |
| |
| METHODDEF void |
| single_ccontroller (compress_info_ptr cinfo) |
| { |
| int rows_in_mem; /* # of sample rows in full-size buffers */ |
| long fullsize_width; /* # of samples per row in full-size buffers */ |
| long cur_pixel_row; /* counts # of pixel rows processed */ |
| long mcu_rows_output; /* # of MCU rows actually emitted */ |
| int mcu_rows_per_loop; /* # of MCU rows processed per outer loop */ |
| /* Work buffer for pre-subsampling data (see comments at head of file) */ |
| JSAMPIMAGE fullsize_data[2]; |
| /* Work buffer for subsampled data */ |
| JSAMPIMAGE subsampled_data; |
| int rows_this_time; |
| short ci, whichss, i; |
| |
| /* Prepare for single scan containing all components */ |
| if (cinfo->num_components > MAX_COMPS_IN_SCAN) |
| ERREXIT(cinfo->emethods, "Too many components for interleaved scan"); |
| cinfo->comps_in_scan = cinfo->num_components; |
| for (ci = 0; ci < cinfo->num_components; ci++) { |
| cinfo->cur_comp_info[ci] = &cinfo->comp_info[ci]; |
| } |
| if (cinfo->comps_in_scan == 1) { |
| noninterleaved_scan_setup(cinfo); |
| /* Vk block rows constitute the same number of MCU rows */ |
| mcu_rows_per_loop = cinfo->cur_comp_info[0]->v_samp_factor; |
| } else { |
| interleaved_scan_setup(cinfo); |
| /* in an interleaved scan, one MCU row contains Vk block rows */ |
| mcu_rows_per_loop = 1; |
| } |
| cinfo->total_passes++; |
| |
| /* Compute dimensions of full-size pixel buffers */ |
| /* Note these are the same whether interleaved or not. */ |
| rows_in_mem = cinfo->max_v_samp_factor * DCTSIZE; |
| fullsize_width = jround_up(cinfo->image_width, |
| (long) (cinfo->max_h_samp_factor * DCTSIZE)); |
| |
| /* Allocate working memory: */ |
| /* fullsize_data is sample data before subsampling */ |
| alloc_sampling_buffer(cinfo, fullsize_data, fullsize_width); |
| /* subsampled_data is sample data after subsampling */ |
| subsampled_data = (JSAMPIMAGE) (*cinfo->emethods->alloc_small) |
| (cinfo->num_components * SIZEOF(JSAMPARRAY)); |
| for (ci = 0; ci < cinfo->num_components; ci++) { |
| subsampled_data[ci] = (*cinfo->emethods->alloc_small_sarray) |
| (cinfo->comp_info[ci].subsampled_width, |
| (long) (cinfo->comp_info[ci].v_samp_factor * DCTSIZE)); |
| } |
| |
| /* Tell the memory manager to instantiate big arrays. |
| * We don't need any big arrays in this controller, |
| * but some other module (like the input file reader) may need one. |
| */ |
| (*cinfo->emethods->alloc_big_arrays) |
| ((long) 0, /* no more small sarrays */ |
| (long) 0, /* no more small barrays */ |
| (long) 0); /* no more "medium" objects */ |
| |
| /* Initialize output file & do per-scan object init */ |
| |
| (*cinfo->methods->write_scan_header) (cinfo); |
| cinfo->methods->entropy_output = cinfo->methods->write_jpeg_data; |
| (*cinfo->methods->entropy_encoder_init) (cinfo); |
| (*cinfo->methods->subsample_init) (cinfo); |
| (*cinfo->methods->extract_init) (cinfo); |
| |
| /* Loop over input image: rows_in_mem pixel rows are processed per loop */ |
| |
| mcu_rows_output = 0; |
| whichss = 1; /* arrange to start with fullsize_data[0] */ |
| |
| for (cur_pixel_row = 0; cur_pixel_row < cinfo->image_height; |
| cur_pixel_row += rows_in_mem) { |
| (*cinfo->methods->progress_monitor) (cinfo, cur_pixel_row, |
| cinfo->image_height); |
| |
| whichss ^= 1; /* switch to other fullsize_data buffer */ |
| |
| /* Obtain rows_this_time pixel rows and expand to rows_in_mem rows. */ |
| /* Then we have exactly DCTSIZE row groups for subsampling. */ |
| rows_this_time = (int) MIN((long) rows_in_mem, |
| cinfo->image_height - cur_pixel_row); |
| |
| (*cinfo->methods->get_sample_rows) (cinfo, rows_this_time, |
| fullsize_data[whichss]); |
| (*cinfo->methods->edge_expand) (cinfo, |
| cinfo->image_width, rows_this_time, |
| fullsize_width, rows_in_mem, |
| fullsize_data[whichss]); |
| |
| /* Subsample the data (all components) */ |
| /* First time through is a special case */ |
| |
| if (cur_pixel_row) { |
| /* Subsample last row group of previous set */ |
| subsample(cinfo, fullsize_data[whichss], subsampled_data, fullsize_width, |
| (short) DCTSIZE, (short) (DCTSIZE+1), (short) 0, |
| (short) (DCTSIZE-1)); |
| /* and dump the previous set's subsampled data */ |
| (*cinfo->methods->extract_MCUs) (cinfo, subsampled_data, |
| mcu_rows_per_loop, |
| cinfo->methods->entropy_encode); |
| mcu_rows_output += mcu_rows_per_loop; |
| /* Subsample first row group of this set */ |
| subsample(cinfo, fullsize_data[whichss], subsampled_data, fullsize_width, |
| (short) (DCTSIZE+1), (short) 0, (short) 1, |
| (short) 0); |
| } else { |
| /* Subsample first row group with dummy above-context */ |
| subsample(cinfo, fullsize_data[whichss], subsampled_data, fullsize_width, |
| (short) (-1), (short) 0, (short) 1, |
| (short) 0); |
| } |
| /* Subsample second through next-to-last row groups of this set */ |
| for (i = 1; i <= DCTSIZE-2; i++) { |
| subsample(cinfo, fullsize_data[whichss], subsampled_data, fullsize_width, |
| (short) (i-1), (short) i, (short) (i+1), |
| (short) i); |
| } |
| } /* end of outer loop */ |
| |
| /* Subsample the last row group with dummy below-context */ |
| /* Note whichss points to last buffer side used */ |
| subsample(cinfo, fullsize_data[whichss], subsampled_data, fullsize_width, |
| (short) (DCTSIZE-2), (short) (DCTSIZE-1), (short) (-1), |
| (short) (DCTSIZE-1)); |
| /* Dump the remaining data (may be less than full height if uninterleaved) */ |
| (*cinfo->methods->extract_MCUs) (cinfo, subsampled_data, |
| (int) (cinfo->MCU_rows_in_scan - mcu_rows_output), |
| cinfo->methods->entropy_encode); |
| |
| /* Finish output file */ |
| (*cinfo->methods->extract_term) (cinfo); |
| (*cinfo->methods->subsample_term) (cinfo); |
| (*cinfo->methods->entropy_encoder_term) (cinfo); |
| (*cinfo->methods->write_scan_trailer) (cinfo); |
| cinfo->completed_passes++; |
| |
| /* Release working memory */ |
| /* (no work -- we let free_all release what's needful) */ |
| } |
| |
| |
| /* |
| * Compression pipeline controller used for single-scan files |
| * with optimization of entropy parameters. |
| */ |
| |
| #ifdef ENTROPY_OPT_SUPPORTED |
| |
| METHODDEF void |
| single_eopt_ccontroller (compress_info_ptr cinfo) |
| { |
| int rows_in_mem; /* # of sample rows in full-size buffers */ |
| long fullsize_width; /* # of samples per row in full-size buffers */ |
| long cur_pixel_row; /* counts # of pixel rows processed */ |
| long mcu_rows_output; /* # of MCU rows actually emitted */ |
| int mcu_rows_per_loop; /* # of MCU rows processed per outer loop */ |
| /* Work buffer for pre-subsampling data (see comments at head of file) */ |
| JSAMPIMAGE fullsize_data[2]; |
| /* Work buffer for subsampled data */ |
| JSAMPIMAGE subsampled_data; |
| int rows_this_time; |
| int blocks_in_big_row; |
| short ci, whichss, i; |
| |
| /* Prepare for single scan containing all components */ |
| if (cinfo->num_components > MAX_COMPS_IN_SCAN) |
| ERREXIT(cinfo->emethods, "Too many components for interleaved scan"); |
| cinfo->comps_in_scan = cinfo->num_components; |
| for (ci = 0; ci < cinfo->num_components; ci++) { |
| cinfo->cur_comp_info[ci] = &cinfo->comp_info[ci]; |
| } |
| if (cinfo->comps_in_scan == 1) { |
| noninterleaved_scan_setup(cinfo); |
| /* Vk block rows constitute the same number of MCU rows */ |
| mcu_rows_per_loop = cinfo->cur_comp_info[0]->v_samp_factor; |
| } else { |
| interleaved_scan_setup(cinfo); |
| /* in an interleaved scan, one MCU row contains Vk block rows */ |
| mcu_rows_per_loop = 1; |
| } |
| cinfo->total_passes += 2; /* entropy encoder must add # passes it uses */ |
| |
| /* Compute dimensions of full-size pixel buffers */ |
| /* Note these are the same whether interleaved or not. */ |
| rows_in_mem = cinfo->max_v_samp_factor * DCTSIZE; |
| fullsize_width = jround_up(cinfo->image_width, |
| (long) (cinfo->max_h_samp_factor * DCTSIZE)); |
| |
| /* Allocate working memory: */ |
| /* fullsize_data is sample data before subsampling */ |
| alloc_sampling_buffer(cinfo, fullsize_data, fullsize_width); |
| /* subsampled_data is sample data after subsampling */ |
| subsampled_data = (JSAMPIMAGE) (*cinfo->emethods->alloc_small) |
| (cinfo->num_components * SIZEOF(JSAMPARRAY)); |
| for (ci = 0; ci < cinfo->num_components; ci++) { |
| subsampled_data[ci] = (*cinfo->emethods->alloc_small_sarray) |
| (cinfo->comp_info[ci].subsampled_width, |
| (long) (cinfo->comp_info[ci].v_samp_factor * DCTSIZE)); |
| } |
| |
| /* Figure # of MCUs to be packed in a row of whole_scan_MCUs */ |
| MCUs_in_big_row = MAX_WHOLE_ROW_BLOCKS / cinfo->blocks_in_MCU; |
| blocks_in_big_row = MCUs_in_big_row * cinfo->blocks_in_MCU; |
| |
| /* Request a big array: whole_scan_MCUs saves the MCU data for the scan */ |
| whole_scan_MCUs = (*cinfo->emethods->request_big_barray) |
| ((long) blocks_in_big_row, |
| (long) (cinfo->MCUs_per_row * cinfo->MCU_rows_in_scan |
| + MCUs_in_big_row-1) / MCUs_in_big_row, |
| 1L); /* unit height is 1 row */ |
| |
| next_whole_row = 0; /* init output ptr for MCU_output_catcher */ |
| next_MCU_index = MCUs_in_big_row; /* forces access on first call! */ |
| |
| /* Tell the memory manager to instantiate big arrays */ |
| (*cinfo->emethods->alloc_big_arrays) |
| ((long) 0, /* no more small sarrays */ |
| (long) 0, /* no more small barrays */ |
| (long) 0); /* no more "medium" objects */ |
| |
| /* Do per-scan object init */ |
| |
| (*cinfo->methods->subsample_init) (cinfo); |
| (*cinfo->methods->extract_init) (cinfo); |
| |
| /* Loop over input image: rows_in_mem pixel rows are processed per loop */ |
| /* MCU data goes into whole_scan_MCUs, not to the entropy encoder */ |
| |
| mcu_rows_output = 0; |
| whichss = 1; /* arrange to start with fullsize_data[0] */ |
| |
| for (cur_pixel_row = 0; cur_pixel_row < cinfo->image_height; |
| cur_pixel_row += rows_in_mem) { |
| (*cinfo->methods->progress_monitor) (cinfo, cur_pixel_row, |
| cinfo->image_height); |
| |
| whichss ^= 1; /* switch to other fullsize_data buffer */ |
| |
| /* Obtain rows_this_time pixel rows and expand to rows_in_mem rows. */ |
| /* Then we have exactly DCTSIZE row groups for subsampling. */ |
| rows_this_time = (int) MIN((long) rows_in_mem, |
| cinfo->image_height - cur_pixel_row); |
| |
| (*cinfo->methods->get_sample_rows) (cinfo, rows_this_time, |
| fullsize_data[whichss]); |
| (*cinfo->methods->edge_expand) (cinfo, |
| cinfo->image_width, rows_this_time, |
| fullsize_width, rows_in_mem, |
| fullsize_data[whichss]); |
| |
| /* Subsample the data (all components) */ |
| /* First time through is a special case */ |
| |
| if (cur_pixel_row) { |
| /* Subsample last row group of previous set */ |
| subsample(cinfo, fullsize_data[whichss], subsampled_data, fullsize_width, |
| (short) DCTSIZE, (short) (DCTSIZE+1), (short) 0, |
| (short) (DCTSIZE-1)); |
| /* and dump the previous set's subsampled data */ |
| (*cinfo->methods->extract_MCUs) (cinfo, subsampled_data, |
| mcu_rows_per_loop, |
| MCU_output_catcher); |
| mcu_rows_output += mcu_rows_per_loop; |
| /* Subsample first row group of this set */ |
| subsample(cinfo, fullsize_data[whichss], subsampled_data, fullsize_width, |
| (short) (DCTSIZE+1), (short) 0, (short) 1, |
| (short) 0); |
| } else { |
| /* Subsample first row group with dummy above-context */ |
| subsample(cinfo, fullsize_data[whichss], subsampled_data, fullsize_width, |
| (short) (-1), (short) 0, (short) 1, |
| (short) 0); |
| } |
| /* Subsample second through next-to-last row groups of this set */ |
| for (i = 1; i <= DCTSIZE-2; i++) { |
| subsample(cinfo, fullsize_data[whichss], subsampled_data, fullsize_width, |
| (short) (i-1), (short) i, (short) (i+1), |
| (short) i); |
| } |
| } /* end of outer loop */ |
| |
| /* Subsample the last row group with dummy below-context */ |
| /* Note whichss points to last buffer side used */ |
| subsample(cinfo, fullsize_data[whichss], subsampled_data, fullsize_width, |
| (short) (DCTSIZE-2), (short) (DCTSIZE-1), (short) (-1), |
| (short) (DCTSIZE-1)); |
| /* Dump the remaining data (may be less than full height if uninterleaved) */ |
| (*cinfo->methods->extract_MCUs) (cinfo, subsampled_data, |
| (int) (cinfo->MCU_rows_in_scan - mcu_rows_output), |
| MCU_output_catcher); |
| |
| /* Clean up after that stuff, then find the optimal entropy parameters */ |
| |
| (*cinfo->methods->extract_term) (cinfo); |
| (*cinfo->methods->subsample_term) (cinfo); |
| |
| cinfo->completed_passes++; |
| |
| (*cinfo->methods->entropy_optimize) (cinfo, dump_scan_MCUs); |
| |
| /* Emit scan to output file */ |
| /* Note: we can't do write_scan_header until entropy parameters are set! */ |
| |
| (*cinfo->methods->write_scan_header) (cinfo); |
| cinfo->methods->entropy_output = cinfo->methods->write_jpeg_data; |
| (*cinfo->methods->entropy_encoder_init) (cinfo); |
| dump_scan_MCUs(cinfo, cinfo->methods->entropy_encode); |
| (*cinfo->methods->entropy_encoder_term) (cinfo); |
| (*cinfo->methods->write_scan_trailer) (cinfo); |
| |
| /* Release working memory */ |
| /* (no work -- we let free_all release what's needful) */ |
| } |
| |
| #endif /* ENTROPY_OPT_SUPPORTED */ |
| |
| |
| /* |
| * Compression pipeline controller used for multiple-scan files |
| * with no optimization of entropy parameters. |
| */ |
| |
| #ifdef MULTISCAN_FILES_SUPPORTED |
| |
| METHODDEF void |
| multi_ccontroller (compress_info_ptr cinfo) |
| { |
| ERREXIT(cinfo->emethods, "Not implemented yet"); |
| } |
| |
| #endif /* MULTISCAN_FILES_SUPPORTED */ |
| |
| |
| /* |
| * Compression pipeline controller used for multiple-scan files |
| * with optimization of entropy parameters. |
| */ |
| |
| #ifdef MULTISCAN_FILES_SUPPORTED |
| #ifdef ENTROPY_OPT_SUPPORTED |
| |
| METHODDEF void |
| multi_eopt_ccontroller (compress_info_ptr cinfo) |
| { |
| ERREXIT(cinfo->emethods, "Not implemented yet"); |
| } |
| |
| #endif /* ENTROPY_OPT_SUPPORTED */ |
| #endif /* MULTISCAN_FILES_SUPPORTED */ |
| |
| |
| /* |
| * The method selection routine for compression pipeline controllers. |
| */ |
| |
| GLOBAL void |
| jselcpipeline (compress_info_ptr cinfo) |
| { |
| if (cinfo->interleave || cinfo->num_components == 1) { |
| /* single scan needed */ |
| #ifdef ENTROPY_OPT_SUPPORTED |
| if (cinfo->optimize_coding) |
| cinfo->methods->c_pipeline_controller = single_eopt_ccontroller; |
| else |
| #endif |
| cinfo->methods->c_pipeline_controller = single_ccontroller; |
| } else { |
| /* multiple scans needed */ |
| #ifdef MULTISCAN_FILES_SUPPORTED |
| #ifdef ENTROPY_OPT_SUPPORTED |
| if (cinfo->optimize_coding) |
| cinfo->methods->c_pipeline_controller = multi_eopt_ccontroller; |
| else |
| #endif |
| cinfo->methods->c_pipeline_controller = multi_ccontroller; |
| #else |
| ERREXIT(cinfo->emethods, "Multiple-scan support was not compiled"); |
| #endif |
| } |
| } |