/* * jdpipe.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 decompression pipeline controllers. * These routines are invoked via the d_pipeline_controller method. * * There are two basic pipeline controllers. The simpler one handles a * single-scan JPEG file (single component or fully interleaved) with no * color quantization or 1-pass quantization. In this case, the file can * be processed in one top-to-bottom pass. The more complex controller is * used when 2-pass color quantization is requested and/or the JPEG file * has multiple scans (noninterleaved or partially interleaved). In this * case, the entire image must be buffered up in a "big" array. * * If you need to make a minimal implementation, the more complex controller * can be compiled out by disabling the appropriate configuration options. * We don't recommend this, since then you can't handle all legal JPEG files. */ #include "jinclude.h" #include "jglobstr.h" #include "oierror.h" #include "taskdata.h" // 9505.02 jar #define LOCAL static /* a function used only in its module */ extern char FAR *decmp_buf_ptr; #ifdef D_MULTISCAN_FILES_SUPPORTED /* wish we could assume ANSI's defined() */ #define NEED_COMPLEX_CONTROLLER #else #ifdef QUANT_2PASS_SUPPORTED #define NEED_COMPLEX_CONTROLLER #endif #endif /* * About the data structures: * * The processing chunk size for upsampling 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 while downsampled, 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; * therefore, we read in Vk MCU rows to obtain the same amount of data as we'd * have in an interleaved scan. * To provide context for the upsampling 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. * * Cross-block smoothing also needs context above and below the "current" row. * Since this is an optional feature, I've implemented it in a way that is * much simpler but requires more than the minimum amount of memory. We * simply allocate three extra MCU rows worth of coefficient blocks and use * them to "read ahead" one MCU row in the file. For a typical 1000-pixel-wide * image with 2x2,1x1,1x1 sampling, each MCU row is about 50Kb; an 80x86 * machine may be unable to apply cross-block smoothing to wider images. */ /* * These variables are logically local to the pipeline controller, * but we make them static so that scan_big_image can use them * without having to pass them through the quantization routines. */ // hjg moved to lpGlobStruct static int rows_in_mem_jdpipe; /* # of sample rows in full-size buffers */ /* Work buffer for data being passed to output module. */ /* This has color_out_comps components if not quantizing, */ /* but only one component when quantizing. */ // hjg moved to lpGlobStruct static JSAMPIMAGE output_workspace_jdpipe; #ifdef NEED_COMPLEX_CONTROLLER /* Full-size image array holding upsampled, but not color-processed data. */ // hjg moved to lpGlobStruct static big_sarray_ptr *fullsize_image; // hjg moved to lpGlobStruct static JSAMPIMAGE fullsize_ptrs; /* workspace for access_big_sarray() result */ #endif // 9509.27 jar define the static memory token! extern DWORD dwTlsIndex; /* * Utility routines: common code for pipeline controllers */ LOCAL void interleaved_scan_setup (decompress_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 FAR *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->downsampled_width = jround_up(compptr->true_comp_width, (long) (compptr->MCU_width*DCTSIZE)); compptr->downsampled_height = jround_up(compptr->true_comp_height, (long) (compptr->MCU_height*DCTSIZE)); /* Sanity check */ if (compptr->downsampled_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->d_per_scan_method_selection) (cinfo); } LOCAL void noninterleaved_scan_setup (decompress_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 FAR *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->downsampled_width = jround_up(compptr->true_comp_width, (long) DCTSIZE); compptr->downsampled_height = jround_up(compptr->true_comp_height, (long) DCTSIZE); cinfo->MCUs_per_row = compptr->downsampled_width / DCTSIZE; cinfo->MCU_rows_in_scan = compptr->downsampled_height / DCTSIZE; /* Prepare array describing MCU composition */ cinfo->blocks_in_MCU = 1; cinfo->MCU_membership[0] = 0; (*cinfo->methods->d_per_scan_method_selection) (cinfo); } LOCAL JSAMPIMAGE alloc_sampimage (decompress_info_ptr cinfo, int num_comps, long num_rows, long num_cols) /* Allocate an in-memory sample image (all components same size) */ { JSAMPIMAGE image; int ci; image = (JSAMPIMAGE) (*cinfo->emethods->alloc_small) (num_comps * SIZEOF(JSAMPARRAY)); for (ci = 0; ci < num_comps; ci++) { image[ci] = (*cinfo->emethods->alloc_small_sarray) (num_cols, num_rows); } return image; } #if 0 /* this routine not currently needed */ LOCAL void free_sampimage (decompress_info_ptr cinfo, JSAMPIMAGE image, int num_comps) /* Release a sample image created by alloc_sampimage */ { int ci; for (ci = 0; ci < num_comps; ci++) { (*cinfo->emethods->free_small_sarray) (image[ci]); } (*cinfo->emethods->free_small) ((void *) image); } #endif LOCAL JBLOCKIMAGE alloc_MCU_row (decompress_info_ptr cinfo) /* Allocate one MCU row's worth of coefficient blocks */ { JBLOCKIMAGE image; int ci; image = (JBLOCKIMAGE) (*cinfo->emethods->alloc_small) (cinfo->comps_in_scan * SIZEOF(JBLOCKARRAY)); for (ci = 0; ci < cinfo->comps_in_scan; ci++) { image[ci] = (*cinfo->emethods->alloc_small_barray) (cinfo->cur_comp_info[ci]->downsampled_width / DCTSIZE, (long) cinfo->cur_comp_info[ci]->MCU_height); } return image; } #ifdef NEED_COMPLEX_CONTROLLER /* not used by simple controller */ LOCAL void free_MCU_row (decompress_info_ptr cinfo, JBLOCKIMAGE image) /* Release a coefficient block array created by alloc_MCU_row */ { int ci; for (ci = 0; ci < cinfo->comps_in_scan; ci++) { (*cinfo->emethods->free_small_barray) (image[ci]); } (*cinfo->emethods->free_small) ((void FAR *) image); } #endif LOCAL void alloc_sampling_buffer (decompress_info_ptr cinfo, JSAMPIMAGE sampled_data2[2]) /* Create a downsampled-data buffer having the desired structure */ /* (see comments at head of file) */ { short ci, vs, i; /* Get top-level space for array pointers */ sampled_data2[0] = (JSAMPIMAGE) (*cinfo->emethods->alloc_small) (cinfo->comps_in_scan * SIZEOF(JSAMPARRAY)); sampled_data2[1] = (JSAMPIMAGE) (*cinfo->emethods->alloc_small) (cinfo->comps_in_scan * SIZEOF(JSAMPARRAY)); for (ci = 0; ci < cinfo->comps_in_scan; ci++) { vs = cinfo->cur_comp_info[ci]->v_samp_factor; /* row group height */ /* Allocate the real storage */ sampled_data2[0][ci] = (*cinfo->emethods->alloc_small_sarray) (cinfo->cur_comp_info[ci]->downsampled_width, (long) (vs * (DCTSIZE+2))); /* Create space for the scrambled-order pointers */ sampled_data2[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++) { sampled_data2[1][ci][i] = sampled_data2[0][ci][i]; } /* Copy the last four row groups in swapped order */ for (i = 0; i < vs * 2; i++) { sampled_data2[1][ci][vs*DCTSIZE + i] = sampled_data2[0][ci][vs*(DCTSIZE-2) + i]; sampled_data2[1][ci][vs*(DCTSIZE-2) + i] = sampled_data2[0][ci][vs*DCTSIZE + i]; } } } #ifdef NEED_COMPLEX_CONTROLLER /* not used by simple controller */ LOCAL void free_sampling_buffer (decompress_info_ptr cinfo, JSAMPIMAGE sampled_data2[2]) /* Release a sampling buffer created by alloc_sampling_buffer */ { short ci; for (ci = 0; ci < cinfo->comps_in_scan; ci++) { /* Free the real storage */ (*cinfo->emethods->free_small_sarray) (sampled_data2[0][ci]); /* Free the scrambled-order pointers */ (*cinfo->emethods->free_small) ((void FAR *) sampled_data2[1][ci]); } /* Free the top-level space */ (*cinfo->emethods->free_small) ((void FAR *) sampled_data2[0]); (*cinfo->emethods->free_small) ((void FAR *) sampled_data2[1]); } #endif /* * Several decompression processes need to range-limit values to the range * 0..MAXJSAMPLE; the input value may fall somewhat outside this range * due to noise introduced by quantization, roundoff error, etc. These * processes are inner loops and need to be as fast as possible. On most * machines, particularly CPUs with pipelines or instruction prefetch, * a (range-check-less) C table lookup * x = sample_range_limit[x]; * is faster than explicit tests * if (x < 0) x = 0; * else if (x > MAXJSAMPLE) x = MAXJSAMPLE; * These processes all use a common table prepared by the routine below. * * The table will work correctly for x within MAXJSAMPLE+1 of the legal * range. This is a much wider range than is needed for most cases, * but the wide range is handy for color quantization. * Note that the table is allocated in near data space on PCs; it's small * enough and used often enough to justify this. */ LOCAL void prepare_range_limit_table (decompress_info_ptr cinfo) /* Allocate and fill in the sample_range_limit table */ { JSAMPLE * table; int i; table = (JSAMPLE *) (*cinfo->emethods->alloc_small) (3 * (MAXJSAMPLE+1) * SIZEOF(JSAMPLE)); cinfo->sample_range_limit = table + (MAXJSAMPLE+1); for (i = 0; i <= MAXJSAMPLE; i++) { table[i] = 0; /* sample_range_limit[x] = 0 for x<0 */ table[i+(MAXJSAMPLE+1)] = (JSAMPLE) i; /* sample_range_limit[x] = x */ table[i+(MAXJSAMPLE+1)*2] = (char)MAXJSAMPLE; /* x beyond MAXJSAMPLE */ } } LOCAL void duplicate_row (JSAMPARRAY image_data, long num_cols, int source_row, int num_rows) /* Duplicate the source_row at source_row+1 .. source_row+num_rows */ /* This happens only at the bottom of the image, */ /* so it needn't be super-efficient */ { register int row; for (row = 1; row <= num_rows; row++) { jcopy_sample_rows(image_data, source_row, image_data, source_row + row, 1, num_cols); } } // (HJG moved to lpGlobStruct) static JSAMPARRAY above_ptr, below_ptr; // (HJG moved to lpGlobStruct) static JSAMPROW dummy[MAX_SAMP_FACTOR]; /* for downsample expansion at top/bottom */ LOCAL void expand (decompress_info_ptr cinfo, JSAMPIMAGE sampled_data2, JSAMPIMAGE fullsize_data, long fullsize_width, short above, short current, short below, short out) /* Do upsampling expansion of a single row group (of each component). */ /* above, current, below are indexes of row groups in sampled_data2; */ /* out is the index of the target row group in fullsize_data. */ /* Special case: above, below can be -1 to indicate top, bottom of image. */ { jpeg_component_info FAR *compptr; // JSAMPARRAY above_ptr, below_ptr; // JSAMPROW dummy[MAX_SAMP_FACTOR]; /* for downsample expansion at top/bottom */ short ci, vs, i; // 9509.21 jar use Thread Local Storage to manage JPEG Globals LPOI_JPEG_GLOBALS_STRUCT lpGlobStruct; lpGlobStruct = ( LPOI_JPEG_GLOBALS_STRUCT)TlsGetValue( dwTlsIndex); // 9509.21 jar if null, we'll alloc and set for this thread if ( lpGlobStruct == NULL) { lpGlobStruct = ( LPOI_JPEG_GLOBALS_STRUCT)LocalAlloc( LPTR, sizeof( OI_JPEG_GLOBALS_STRUCT)); if (lpGlobStruct != NULL) { TlsSetValue( dwTlsIndex, lpGlobStruct); } } for (ci = 0; ci < cinfo->comps_in_scan; ci++) { compptr = cinfo->cur_comp_info[ci]; vs = compptr->v_samp_factor; /* row group height */ if (above >= 0) lpGlobStruct->above_ptr = sampled_data2[ci] + above * vs; else { /* Top of image: make a lpGlobStruct->dummy above-context with copies of 1st row */ /* We assume current=0 in this case */ for (i = 0; i < vs; i++) lpGlobStruct->dummy[i] = sampled_data2[ci][0]; lpGlobStruct->above_ptr = (JSAMPARRAY) lpGlobStruct->dummy; /* possible near->far pointer conv */ } if (below >= 0) lpGlobStruct->below_ptr = sampled_data2[ci] + below * vs; else { /* Bot of image: make a lpGlobStruct->dummy below-context with copies of last row */ for (i = 0; i < vs; i++) lpGlobStruct->dummy[i] = sampled_data2[ci][(current+1)*vs-1]; lpGlobStruct->below_ptr = (JSAMPARRAY) lpGlobStruct->dummy; /* possible near->far pointer conv */ } (*cinfo->methods->upsample[ci]) (cinfo, (int) ci, compptr->downsampled_width, (int) vs, fullsize_width, (int) cinfo->max_v_samp_factor, lpGlobStruct->above_ptr, sampled_data2[ci] + current * vs, lpGlobStruct->below_ptr, fullsize_data[ci] + out * cinfo->max_v_samp_factor); } } LOCAL int emit_1pass (decompress_info_ptr cinfo, int num_rows, JSAMPIMAGE fullsize_data, JSAMPARRAY dummy) /* Do color processing and output of num_rows full-size rows. */ /* This is not used when doing 2-pass color quantization. */ /* The dummy argument simply lets this be called via scan_big_image. */ { int error_write_decmp; // 9509.21 jar use Thread Local Storage to manage JPEG Globals LPOI_JPEG_GLOBALS_STRUCT lpGlobStruct; lpGlobStruct = ( LPOI_JPEG_GLOBALS_STRUCT)TlsGetValue( dwTlsIndex); // 9509.21 jar if null, we'll alloc and set for this thread if ( lpGlobStruct == NULL) { lpGlobStruct = ( LPOI_JPEG_GLOBALS_STRUCT)LocalAlloc( LPTR, sizeof( OI_JPEG_GLOBALS_STRUCT)); if (lpGlobStruct != NULL) { TlsSetValue( dwTlsIndex, lpGlobStruct); } } if (cinfo->quantize_colors) { (*cinfo->methods->color_quantize) (cinfo, num_rows, fullsize_data, lpGlobStruct->output_workspace_jdpipe[0]); } else { (*cinfo->methods->color_convert) (cinfo, num_rows, cinfo->image_width, fullsize_data, lpGlobStruct->output_workspace_jdpipe); } error_write_decmp = (*cinfo->methods->put_pixel_rows) (cinfo, num_rows, lpGlobStruct->output_workspace_jdpipe); /* The above line is changed for our implementation */ /* error_write_decmp = (*cinfo->methods->output_decmp_data) (num_rows); */ return(error_write_decmp); } /* * Support routines for complex controller. */ #ifdef NEED_COMPLEX_CONTROLLER METHODDEF void scan_big_image (decompress_info_ptr cinfo, quantize_method_ptr quantize_method) /* Apply quantize_method to entire image stored in fullsize_image[]. */ /* This is the "iterator" routine used by the 2-pass color quantizer. */ /* We also use it directly in some cases. */ { long pixel_rows_output; short ci; // 9509.21 jar use Thread Local Storage to manage JPEG Globals LPOI_JPEG_GLOBALS_STRUCT lpGlobStruct; lpGlobStruct = ( LPOI_JPEG_GLOBALS_STRUCT)TlsGetValue( dwTlsIndex); // 9509.21 jar if null, we'll alloc and set for this thread if ( lpGlobStruct == NULL) { lpGlobStruct = ( LPOI_JPEG_GLOBALS_STRUCT)LocalAlloc( LPTR, sizeof( OI_JPEG_GLOBALS_STRUCT)); if (lpGlobStruct != NULL) { TlsSetValue( dwTlsIndex, lpGlobStruct); } } for (pixel_rows_output = 0; pixel_rows_output < cinfo->image_height; pixel_rows_output += lpGlobStruct->rows_in_mem_jdpipe) { (*cinfo->methods->progress_monitor) (cinfo, pixel_rows_output, cinfo->image_height); /* Realign the big buffers */ for (ci = 0; ci < cinfo->num_components; ci++) { lpGlobStruct->fullsize_ptrs[ci] = (*cinfo->emethods->access_big_sarray) (lpGlobStruct->fullsize_image[ci], pixel_rows_output, FALSE); } /* Let the quantizer have its way with the data. * Note that output_workspace_jdpipe is simply workspace for the quantizer; * when it's ready to output, it must call put_pixel_rows itself. */ (*quantize_method) (cinfo, (int) MIN((long) lpGlobStruct->rows_in_mem_jdpipe, cinfo->image_height - pixel_rows_output), lpGlobStruct->fullsize_ptrs, lpGlobStruct->output_workspace_jdpipe[0]); } cinfo->completed_passes++; } #endif /* NEED_COMPLEX_CONTROLLER */ /* * Support routines for cross-block smoothing. */ #ifdef BLOCK_SMOOTHING_SUPPORTED LOCAL void smooth_mcu_row (decompress_info_ptr cinfo, JBLOCKIMAGE above, JBLOCKIMAGE input, JBLOCKIMAGE below, JBLOCKIMAGE output) /* Apply cross-block smoothing to one MCU row's worth of coefficient blocks. */ /* above,below are NULL if at top/bottom of image. */ { jpeg_component_info FAR *compptr; short ci, ri, last; JBLOCKROW prev; for (ci = 0; ci < cinfo->comps_in_scan; ci++) { compptr = cinfo->cur_comp_info[ci]; last = compptr->MCU_height - 1; if (above == NULL) prev = NULL; else prev = above[ci][last]; for (ri = 0; ri < last; ri++) { (*cinfo->methods->smooth_coefficients) (cinfo, compptr, prev, input[ci][ri], input[ci][ri+1], output[ci][ri]); prev = input[ci][ri]; } if (below == NULL) (*cinfo->methods->smooth_coefficients) (cinfo, compptr, prev, input[ci][last], (JBLOCKROW) NULL, output[ci][last]); else (*cinfo->methods->smooth_coefficients) (cinfo, compptr, prev, input[ci][last], below[ci][0], output[ci][last]); } } LOCAL void get_smoothed_row (decompress_info_ptr cinfo, JBLOCKIMAGE coeff_data, JBLOCKIMAGE bsmooth[3], int * whichb, long cur_mcu_row) /* Get an MCU row of coefficients, applying cross-block smoothing. */ /* The output row is placed in coeff_data. bsmooth and whichb hold */ /* working state, and cur_row is needed to check for image top/bottom. */ /* This routine just takes care of the buffering logic. */ { int prev, cur, next; /* Special case for top of image: need to pre-fetch a row & init whichb */ if (cur_mcu_row == 0) { (*cinfo->methods->disassemble_MCU) (cinfo, bsmooth[0]); if (cinfo->MCU_rows_in_scan > 1) { (*cinfo->methods->disassemble_MCU) (cinfo, bsmooth[1]); smooth_mcu_row(cinfo, (JBLOCKIMAGE) NULL, bsmooth[0], bsmooth[1], coeff_data); } else { smooth_mcu_row(cinfo, (JBLOCKIMAGE) NULL, bsmooth[0], (JBLOCKIMAGE) NULL, coeff_data); } *whichb = 1; /* points to next bsmooth[] element to use */ return; } cur = *whichb; /* set up references */ prev = (cur == 0 ? 2 : cur - 1); next = (cur == 2 ? 0 : cur + 1); *whichb = next; /* advance whichb for next time */ /* Special case for bottom of image: don't read another row */ if (cur_mcu_row >= cinfo->MCU_rows_in_scan - 1) { smooth_mcu_row(cinfo, bsmooth[prev], bsmooth[cur], (JBLOCKIMAGE) NULL, coeff_data); return; } /* Normal case: read ahead a new row, smooth the one I got before */ (*cinfo->methods->disassemble_MCU) (cinfo, bsmooth[next]); smooth_mcu_row(cinfo, bsmooth[prev], bsmooth[cur], bsmooth[next], coeff_data); } #endif /* BLOCK_SMOOTHING_SUPPORTED */ /* * Decompression pipeline controller used for single-scan files * without 2-pass color quantization. */ // hjg moved to lpGlobStruct static JSAMPIMAGE sampled_data_jdpipe_common[2]; METHODDEF int simple_dcontroller (decompress_info_ptr cinfo) { long fullsize_width; /* # of samples per row in full-size buffers */ long cur_mcu_row; /* counts # of MCU rows processed */ long pixel_rows_output; /* # of pixel rows actually emitted */ int mcu_rows_per_loop; /* # of MCU rows processed per outer loop */ /* Work buffer for dequantized coefficients (IDCT input) */ // (HJG moved to lpGlobStruct) static JBLOCKIMAGE coeff_data; /* Work buffer for cross-block smoothing input */ #ifdef BLOCK_SMOOTHING_SUPPORTED // (HJG moved to lpGlobStruct) static JBLOCKIMAGE bsmooth[3]; /* this is optional */ // (HJG moved to lpGlobStruct) static int whichb; int error_write_pipe; #endif /* Work buffer for downsampled image data (see comments at head of file) */ // JSAMPIMAGE sampled_data2[2]; /* Work buffer for upsampled data */ JSAMPIMAGE fullsize_data; int whichss, ri; short i; // 9509.21 jar use Thread Local Storage to manage JPEG Globals LPOI_JPEG_GLOBALS_STRUCT lpGlobStruct; lpGlobStruct = ( LPOI_JPEG_GLOBALS_STRUCT)TlsGetValue( dwTlsIndex); // 9509.21 jar if null, we'll alloc and set for this thread if ( lpGlobStruct == NULL) { lpGlobStruct = ( LPOI_JPEG_GLOBALS_STRUCT)LocalAlloc( LPTR, sizeof( OI_JPEG_GLOBALS_STRUCT)); if (lpGlobStruct != NULL) { TlsSetValue( dwTlsIndex, lpGlobStruct); } } /* Compute dimensions of full-size pixel buffers */ /* Note these are the same whether interleaved or not. */ lpGlobStruct->rows_in_mem_jdpipe = cinfo->max_v_samp_factor * DCTSIZE; fullsize_width = jround_up(cinfo->image_width, (long) (cinfo->max_h_samp_factor * DCTSIZE)); /* Prepare for single scan containing all components */ if (cinfo->comps_in_scan == 1) { noninterleaved_scan_setup(cinfo); /* Need to read Vk MCU rows to obtain Vk block 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 provides Vk block rows */ mcu_rows_per_loop = 1; } cinfo->total_passes++; /* Allocate working memory: */ /* lpGlobStruct->coeff_data holds a single MCU row of coefficient blocks */ lpGlobStruct->coeff_data = alloc_MCU_row(cinfo); /* if doing cross-block smoothing, need extra space for its input */ #ifdef BLOCK_SMOOTHING_SUPPORTED if (cinfo->do_block_smoothing) { lpGlobStruct->bsmooth_1[0] = alloc_MCU_row(cinfo); lpGlobStruct->bsmooth_1[1] = alloc_MCU_row(cinfo); lpGlobStruct->bsmooth_1[2] = alloc_MCU_row(cinfo); } #endif /* sampled_data2 is sample data before upsampling */ alloc_sampling_buffer(cinfo, lpGlobStruct->sampled_data_jdpipe_common); /* fullsize_data is sample data after upsampling */ fullsize_data = alloc_sampimage(cinfo, (int) cinfo->num_components, (long) lpGlobStruct->rows_in_mem_jdpipe, fullsize_width); /* output_workspace_jdpipe is the color-processed data */ lpGlobStruct->output_workspace_jdpipe = alloc_sampimage(cinfo, (int) cinfo->final_out_comps, (long) lpGlobStruct->rows_in_mem_jdpipe, fullsize_width); prepare_range_limit_table(cinfo); /* Tell the memory manager to instantiate big arrays. * We don't need any big arrays in this controller, * but some other module (like the output file writer) 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 */ /* NB: if quantizer needs any "medium" size objects, it must get them */ /* at color_quant_init time */ /* Initialize to read scan data */ (*cinfo->methods->entropy_decode_init) (cinfo); (*cinfo->methods->upsample_init) (cinfo); (*cinfo->methods->disassemble_init) (cinfo); /* Loop over scan's data: rows_in_mem_jdpipe pixel rows are processed per loop */ pixel_rows_output = 0; whichss = 1; /* arrange to start with lpGlobStruct->sampled_data_jdpipe_common[0] */ for (cur_mcu_row = 0; cur_mcu_row < cinfo->MCU_rows_in_scan; cur_mcu_row += mcu_rows_per_loop) { (*cinfo->methods->progress_monitor) (cinfo, cur_mcu_row, cinfo->MCU_rows_in_scan); whichss ^= 1; /* switch to other downsampled-data buffer */ /* Obtain v_samp_factor block rows of each component in the scan. */ /* This is a single MCU row if interleaved, multiple MCU rows if not. */ /* In the noninterleaved case there might be fewer than v_samp_factor */ /* block rows remaining; if so, pad with copies of the last pixel row */ /* so that upsampling doesn't have to treat it as a special case. */ for (ri = 0; ri < mcu_rows_per_loop; ri++) { if (cur_mcu_row + ri < cinfo->MCU_rows_in_scan) { /* OK to actually read an MCU row. */ #ifdef BLOCK_SMOOTHING_SUPPORTED if (cinfo->do_block_smoothing) get_smoothed_row(cinfo, lpGlobStruct->coeff_data, lpGlobStruct->bsmooth_1, &(lpGlobStruct->whichb_1), cur_mcu_row + ri); else #endif (*cinfo->methods->disassemble_MCU) (cinfo, lpGlobStruct->coeff_data); (*cinfo->methods->reverse_DCT) (cinfo, lpGlobStruct->coeff_data, lpGlobStruct->sampled_data_jdpipe_common[whichss], ri * DCTSIZE); } else { /* Need to pad out with copies of the last downsampled row. */ /* This can only happen if there is just one component. */ duplicate_row(lpGlobStruct->sampled_data_jdpipe_common[whichss][0], cinfo->cur_comp_info[0]->downsampled_width, ri * DCTSIZE - 1, DCTSIZE); } } /* Upsample the data */ /* First time through is a special case */ if (cur_mcu_row) { /* Expand last row group of previous set */ expand(cinfo, lpGlobStruct->sampled_data_jdpipe_common[whichss], fullsize_data, fullsize_width, (short) DCTSIZE, (short) (DCTSIZE+1), (short) 0, (short) (DCTSIZE-1)); /* and dump the previous set's expanded data */ error_write_pipe = emit_1pass (cinfo, lpGlobStruct->rows_in_mem_jdpipe, fullsize_data, (JSAMPARRAY) NULL); if (error_write_pipe > 0 ) { return(error_write_pipe); } pixel_rows_output += lpGlobStruct->rows_in_mem_jdpipe; /* Expand first row group of this set */ expand(cinfo, lpGlobStruct->sampled_data_jdpipe_common[whichss], fullsize_data, fullsize_width, (short) (DCTSIZE+1), (short) 0, (short) 1, (short) 0); } else { /* Expand first row group with dummy above-context */ expand(cinfo, lpGlobStruct->sampled_data_jdpipe_common[whichss], fullsize_data, fullsize_width, (short) (-1), (short) 0, (short) 1, (short) 0); } /* Expand second through next-to-last row groups of this set */ for (i = 1; i <= DCTSIZE-2; i++) { expand(cinfo, lpGlobStruct->sampled_data_jdpipe_common[whichss], fullsize_data, fullsize_width, (short) (i-1), (short) i, (short) (i+1), (short) i); } } /* end of outer loop */ /* Expand the last row group with dummy below-context */ /* Note whichss points to last buffer side used */ expand(cinfo, lpGlobStruct->sampled_data_jdpipe_common[whichss], fullsize_data, fullsize_width, (short) (DCTSIZE-2), (short) (DCTSIZE-1), (short) (-1), (short) (DCTSIZE-1)); /* and dump the remaining data (may be less than full height) */ lpGlobStruct->all_done = 1; /* Inform write routine that it is all done */ error_write_pipe = emit_1pass (cinfo, (int) (cinfo->image_height - pixel_rows_output), fullsize_data, (JSAMPARRAY) NULL); lpGlobStruct->all_done = 0; /* Reset all done flag */ if (error_write_pipe > 0 ) { return(error_write_pipe); } /* Clean up after the scan */ (*cinfo->methods->disassemble_term) (cinfo); (*cinfo->methods->upsample_term) (cinfo); (*cinfo->methods->entropy_decode_term) (cinfo); (*cinfo->methods->read_scan_trailer) (cinfo); cinfo->completed_passes++; /* Verify that we've seen the whole input file */ /* if ((*cinfo->methods->read_scan_header) (cinfo)) WARNMS(cinfo->emethods, "Didn't expect more than one scan"); */ /* Release working memory */ /* (no work -- we let free_all release what's needful) */ return(0); } /* * Decompression pipeline controller used for multiple-scan files * and/or 2-pass color quantization. * * The current implementation places the "big" buffer at the stage of * upsampled, non-color-processed data. This is the only place that * makes sense when doing 2-pass quantization. For processing multiple-scan * files without 2-pass quantization, it would be possible to develop another * controller that buffers the downsampled data instead, thus reducing the size * of the temp files (by about a factor of 2 in typical cases). However, * our present upsampling logic is dependent on the assumption that * upsampling occurs during a scan, so it's much easier to do the * enlargement as the JPEG file is read. This also simplifies life for the * memory manager, which would otherwise have to deal with overlapping * access_big_sarray() requests. * At present it appears that most JPEG files will be single-scan, * so it doesn't seem worthwhile to worry about this optimization. */ #ifdef NEED_COMPLEX_CONTROLLER METHODDEF int complex_dcontroller (decompress_info_ptr cinfo) { long fullsize_width; /* # of samples per row in full-size buffers */ long cur_mcu_row; /* counts # of MCU rows processed */ long pixel_rows_output; /* # of pixel rows actually emitted */ int mcu_rows_per_loop; /* # of MCU rows processed per outer loop */ /* Work buffer for dequantized coefficients (IDCT input) */ JBLOCKIMAGE coeff_data; /* Work buffer for cross-block smoothing input */ #ifdef BLOCK_SMOOTHING_SUPPORTED // (HJG moved to lpGlobStruct) static JBLOCKIMAGE bsmooth[3]; /* this is optional */ // (HJG moved to lpGlobStruct) static int whichb; #endif /* Work buffer for downsampled image data (see comments at head of file) */ // (HJG moved to lpGlobStruct) static JSAMPIMAGE sampled_data2[2]; int whichss, ri; short ci, i; boolean single_scan; // 9509.21 jar use Thread Local Storage to manage JPEG Globals LPOI_JPEG_GLOBALS_STRUCT lpGlobStruct; lpGlobStruct = ( LPOI_JPEG_GLOBALS_STRUCT)TlsGetValue( dwTlsIndex); // 9509.21 jar if null, we'll alloc and set for this thread if ( lpGlobStruct == NULL) { lpGlobStruct = ( LPOI_JPEG_GLOBALS_STRUCT)LocalAlloc( LPTR, sizeof( OI_JPEG_GLOBALS_STRUCT)); if (lpGlobStruct != NULL) { TlsSetValue( dwTlsIndex, lpGlobStruct); } } /* Compute dimensions of full-size pixel buffers */ /* Note these are the same whether interleaved or not. */ lpGlobStruct->rows_in_mem_jdpipe = cinfo->max_v_samp_factor * DCTSIZE; fullsize_width = jround_up(cinfo->image_width, (long) (cinfo->max_h_samp_factor * DCTSIZE)); /* Allocate all working memory that doesn't depend on scan info */ /* output_workspace_jdpipe is the color-processed data */ lpGlobStruct->output_workspace_jdpipe = alloc_sampimage(cinfo, (int) cinfo->final_out_comps, (long) lpGlobStruct->rows_in_mem_jdpipe, fullsize_width); /* output_workspace_jdpipe = (JSAMPIMAGE) decmp_buf_ptr; */ prepare_range_limit_table(cinfo); /* Get a big image: lpGlobStruct->fullsize_image is sample data after upsampling. */ lpGlobStruct->fullsize_image = (big_sarray_ptr *) (*cinfo->emethods->alloc_small) (cinfo->num_components * SIZEOF(big_sarray_ptr)); for (ci = 0; ci < cinfo->num_components; ci++) { lpGlobStruct->fullsize_image[ci] = (*cinfo->emethods->request_big_sarray) (fullsize_width, jround_up(cinfo->image_height, (long) lpGlobStruct->rows_in_mem_jdpipe), (long) lpGlobStruct->rows_in_mem_jdpipe); } /* Also get an area for pointers to currently accessible chunks */ lpGlobStruct->fullsize_ptrs = (JSAMPIMAGE) (*cinfo->emethods->alloc_small) (cinfo->num_components * SIZEOF(JSAMPARRAY)); /* Tell the memory manager to instantiate big arrays */ (*cinfo->emethods->alloc_big_arrays) /* extra sarray space is for downsampled-data buffers: */ ((long) (fullsize_width /* max width in samples */ * cinfo->max_v_samp_factor*(DCTSIZE+2) /* max height */ * cinfo->num_components), /* max components per scan */ /* extra barray space is for MCU-row buffers: */ (long) ((fullsize_width / DCTSIZE) /* max width in blocks */ * cinfo->max_v_samp_factor /* max height */ * cinfo->num_components /* max components per scan */ * (cinfo->do_block_smoothing ? 4 : 1)),/* how many of these we need */ /* no extra "medium"-object space */ (long) 0); /* NB: if quantizer needs any "medium" size objects, it must get them */ /* at color_quant_init time */ /* If file is single-scan, we can do color quantization prescan on-the-fly * during the scan (we must be doing 2-pass quantization, else this method * would not have been selected). If it is multiple scans, we have to make * a separate pass after we've collected all the components. (We could save * some I/O by doing CQ prescan during the last scan, but the extra logic * doesn't seem worth the trouble.) */ single_scan = (cinfo->comps_in_scan == cinfo->num_components); /* Account for passes needed (color quantizer adds its passes separately). * If multiscan file, we guess that each component has its own scan, * and increment completed_passes by the number of components in the scan. */ if (single_scan) cinfo->total_passes++; /* the single scan */ else { cinfo->total_passes += cinfo->num_components; /* guessed # of scans */ if (cinfo->two_pass_quantize) cinfo->total_passes++; /* account for separate CQ prescan pass */ } if (! cinfo->two_pass_quantize) cinfo->total_passes++; /* count output pass unless quantizer does it */ /* Loop over scans in file */ do { /* Prepare for this scan */ if (cinfo->comps_in_scan == 1) { noninterleaved_scan_setup(cinfo); /* Need to read Vk MCU rows to obtain Vk block 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 provides Vk block rows */ mcu_rows_per_loop = 1; } /* Allocate scan-local working memory */ /* coeff_data holds a single MCU row of coefficient blocks */ coeff_data = alloc_MCU_row(cinfo); /* if doing cross-block smoothing, need extra space for its input */ #ifdef BLOCK_SMOOTHING_SUPPORTED if (cinfo->do_block_smoothing) { lpGlobStruct->bsmooth_2[0] = alloc_MCU_row(cinfo); lpGlobStruct->bsmooth_2[1] = alloc_MCU_row(cinfo); lpGlobStruct->bsmooth_2[2] = alloc_MCU_row(cinfo); } #endif /* sampled_data2 is sample data before upsampling */ alloc_sampling_buffer(cinfo, lpGlobStruct->sampled_data2); /* line up the big buffers for components in this scan */ for (ci = 0; ci < cinfo->comps_in_scan; ci++) { lpGlobStruct->fullsize_ptrs[ci] = (*cinfo->emethods->access_big_sarray) (lpGlobStruct->fullsize_image[cinfo->cur_comp_info[ci]->component_index], (long) 0, TRUE); } /* Initialize to read scan data */ (*cinfo->methods->entropy_decode_init) (cinfo); (*cinfo->methods->upsample_init) (cinfo); (*cinfo->methods->disassemble_init) (cinfo); /* Loop over scan's data: lpGlobStruct->rows_in_mem_jdpipe pixel rows are processed per loop */ pixel_rows_output = 0; whichss = 1; /* arrange to start with lpGlobStruct->sampled_data2[0] */ for (cur_mcu_row = 0; cur_mcu_row < cinfo->MCU_rows_in_scan; cur_mcu_row += mcu_rows_per_loop) { (*cinfo->methods->progress_monitor) (cinfo, cur_mcu_row, cinfo->MCU_rows_in_scan); whichss ^= 1; /* switch to other downsampled-data buffer */ /* Obtain v_samp_factor block rows of each component in the scan. */ /* This is a single MCU row if interleaved, multiple MCU rows if not. */ /* In the noninterleaved case there might be fewer than v_samp_factor */ /* block rows remaining; if so, pad with copies of the last pixel row */ /* so that upsampling doesn't have to treat it as a special case. */ for (ri = 0; ri < mcu_rows_per_loop; ri++) { if (cur_mcu_row + ri < cinfo->MCU_rows_in_scan) { /* OK to actually read an MCU row. */ #ifdef BLOCK_SMOOTHING_SUPPORTED if (cinfo->do_block_smoothing) get_smoothed_row(cinfo, coeff_data, lpGlobStruct->bsmooth_2, &lpGlobStruct->whichb_2, cur_mcu_row + ri); else #endif (*cinfo->methods->disassemble_MCU) (cinfo, coeff_data); (*cinfo->methods->reverse_DCT) (cinfo, coeff_data, lpGlobStruct->sampled_data2[whichss], ri * DCTSIZE); } else { /* Need to pad out with copies of the last downsampled row. */ /* This can only happen if there is just one component. */ duplicate_row(lpGlobStruct->sampled_data2[whichss][0], cinfo->cur_comp_info[0]->downsampled_width, ri * DCTSIZE - 1, DCTSIZE); } } /* Upsample the data */ /* First time through is a special case */ if (cur_mcu_row) { /* Expand last row group of previous set */ expand(cinfo, lpGlobStruct->sampled_data2[whichss], lpGlobStruct->fullsize_ptrs, fullsize_width, (short) DCTSIZE, (short) (DCTSIZE+1), (short) 0, (short) (DCTSIZE-1)); /* If single scan, can do color quantization prescan on-the-fly */ if (single_scan) (*cinfo->methods->color_quant_prescan) (cinfo, lpGlobStruct->rows_in_mem_jdpipe, lpGlobStruct->fullsize_ptrs, lpGlobStruct->output_workspace_jdpipe[0]); /* Realign the big buffers */ pixel_rows_output += lpGlobStruct->rows_in_mem_jdpipe; for (ci = 0; ci < cinfo->comps_in_scan; ci++) { lpGlobStruct->fullsize_ptrs[ci] = (*cinfo->emethods->access_big_sarray) (lpGlobStruct->fullsize_image[cinfo->cur_comp_info[ci]->component_index], pixel_rows_output, TRUE); } /* Expand first row group of this set */ expand(cinfo, lpGlobStruct->sampled_data2[whichss], lpGlobStruct->fullsize_ptrs, fullsize_width, (short) (DCTSIZE+1), (short) 0, (short) 1, (short) 0); } else { /* Expand first row group with dummy above-context */ expand(cinfo, lpGlobStruct->sampled_data2[whichss], lpGlobStruct->fullsize_ptrs, fullsize_width, (short) (-1), (short) 0, (short) 1, (short) 0); } /* Expand second through next-to-last row groups of this set */ for (i = 1; i <= DCTSIZE-2; i++) { expand(cinfo, lpGlobStruct->sampled_data2[whichss], lpGlobStruct->fullsize_ptrs, fullsize_width, (short) (i-1), (short) i, (short) (i+1), (short) i); } } /* end of loop over scan's data */ /* Expand the last row group with dummy below-context */ /* Note whichss points to last buffer side used */ expand(cinfo, lpGlobStruct->sampled_data2[whichss], lpGlobStruct->fullsize_ptrs, fullsize_width, (short) (DCTSIZE-2), (short) (DCTSIZE-1), (short) (-1), (short) (DCTSIZE-1)); /* If single scan, finish on-the-fly color quantization prescan */ if (single_scan) (*cinfo->methods->color_quant_prescan) (cinfo, (int) (cinfo->image_height - pixel_rows_output), lpGlobStruct->fullsize_ptrs, lpGlobStruct->output_workspace_jdpipe[0]); /* Clean up after the scan */ (*cinfo->methods->disassemble_term) (cinfo); (*cinfo->methods->upsample_term) (cinfo); (*cinfo->methods->entropy_decode_term) (cinfo); (*cinfo->methods->read_scan_trailer) (cinfo); if (single_scan) cinfo->completed_passes++; else cinfo->completed_passes += cinfo->comps_in_scan; /* Release scan-local working memory */ free_MCU_row(cinfo, coeff_data); #ifdef BLOCK_SMOOTHING_SUPPORTED if (cinfo->do_block_smoothing) { free_MCU_row(cinfo, lpGlobStruct->bsmooth_2[0]); free_MCU_row(cinfo, lpGlobStruct->bsmooth_2[1]); free_MCU_row(cinfo, lpGlobStruct->bsmooth_2[2]); } #endif free_sampling_buffer(cinfo, lpGlobStruct->sampled_data2); /* Repeat if there is another scan */ } while ((!single_scan) && (*cinfo->methods->read_scan_header) (cinfo)); if (single_scan) { /* If we expected just one scan, make SURE there's just one */ if ((*cinfo->methods->read_scan_header) (cinfo)) WARNMS(cinfo->emethods, "Didn't expect more than one scan"); /* We did the CQ prescan on-the-fly, so we are all set. */ } else { /* For multiple-scan file, do the CQ prescan as a separate pass. */ /* The main reason why prescan is passed the output_workspace_jdpipe is */ /* so that we can use scan_big_image to call it... */ if (cinfo->two_pass_quantize) scan_big_image(cinfo, cinfo->methods->color_quant_prescan); } /* Now that we've collected the data, do color processing and output */ if (cinfo->two_pass_quantize) (*cinfo->methods->color_quant_doit) (cinfo, scan_big_image); else scan_big_image(cinfo, emit_1pass); /* Release working memory */ /* (no work -- we let free_all release what's needful) */ return(0); } #endif /* NEED_COMPLEX_CONTROLLER */ /* * The method selection routine for decompression pipeline controllers. * Note that at this point we've already read the JPEG header and first SOS, * so we can tell whether the input is one scan or not. */ GLOBAL void jseldpipeline (decompress_info_ptr cinfo) { /* simplify subsequent tests on color quantization */ if (! cinfo->quantize_colors) cinfo->two_pass_quantize = FALSE; if (cinfo->comps_in_scan == cinfo->num_components) { /* It's a single-scan file */ if (cinfo->two_pass_quantize) { #ifdef NEED_COMPLEX_CONTROLLER cinfo->methods->d_pipeline_controller = complex_dcontroller; #else ERREXIT(cinfo->emethods, "2-pass quantization support was not compiled"); #endif } else cinfo->methods->d_pipeline_controller = simple_dcontroller; } else { /* It's a multiple-scan file */ #ifdef NEED_COMPLEX_CONTROLLER cinfo->methods->d_pipeline_controller = complex_dcontroller; #else ERREXIT(cinfo->emethods, "Multiple-scan support was not compiled"); #endif } }