| /* |
| * jcmaster.c |
| * |
| * Copyright (C) 1991-1995, 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 master control logic for the JPEG compressor. |
| * These routines are concerned with selecting the modules to be executed |
| * and with determining the number of passes and the work to be done in each |
| * pass. |
| */ |
| |
| #define JPEG_INTERNALS |
| #include "jinclude.h" |
| #include "jpeglib.h" |
| |
| |
| /* Private state */ |
| |
| typedef struct { |
| struct jpeg_comp_master pub; /* public fields */ |
| |
| int pass_number; /* eventually need more complex state... */ |
| } my_comp_master; |
| |
| typedef my_comp_master * my_master_ptr; |
| |
| |
| /* |
| * Support routines that do various essential calculations. |
| */ |
| |
| LOCAL void |
| initial_setup (j_compress_ptr cinfo) |
| /* Do computations that are needed before master selection phase */ |
| { |
| int ci; |
| jpeg_component_info *compptr; |
| long samplesperrow; |
| JDIMENSION jd_samplesperrow; |
| |
| /* Sanity check on image dimensions */ |
| if (cinfo->image_height <= 0 || cinfo->image_width <= 0 |
| || cinfo->num_components <= 0 || cinfo->input_components <= 0) |
| ERREXIT(cinfo, JERR_EMPTY_IMAGE); |
| |
| /* Make sure image isn't bigger than I can handle */ |
| if ((long) cinfo->image_height > (long) JPEG_MAX_DIMENSION || |
| (long) cinfo->image_width > (long) JPEG_MAX_DIMENSION) |
| ERREXIT1(cinfo, JERR_IMAGE_TOO_BIG, (unsigned int) JPEG_MAX_DIMENSION); |
| |
| /* Width of an input scanline must be representable as JDIMENSION. */ |
| samplesperrow = (long) cinfo->image_width * (long) cinfo->input_components; |
| jd_samplesperrow = (JDIMENSION) samplesperrow; |
| if ((long) jd_samplesperrow != samplesperrow) |
| ERREXIT(cinfo, JERR_WIDTH_OVERFLOW); |
| |
| /* For now, precision must match compiled-in value... */ |
| if (cinfo->data_precision != BITS_IN_JSAMPLE) |
| ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision); |
| |
| /* Check that number of components won't exceed internal array sizes */ |
| if (cinfo->num_components > MAX_COMPONENTS) |
| ERREXIT2(cinfo, JERR_COMPONENT_COUNT, cinfo->num_components, |
| MAX_COMPONENTS); |
| |
| /* Compute maximum sampling factors; check factor validity */ |
| cinfo->max_h_samp_factor = 1; |
| cinfo->max_v_samp_factor = 1; |
| for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; |
| ci++, compptr++) { |
| if (compptr->h_samp_factor<=0 || compptr->h_samp_factor>MAX_SAMP_FACTOR || |
| compptr->v_samp_factor<=0 || compptr->v_samp_factor>MAX_SAMP_FACTOR) |
| ERREXIT(cinfo, JERR_BAD_SAMPLING); |
| cinfo->max_h_samp_factor = MAX(cinfo->max_h_samp_factor, |
| compptr->h_samp_factor); |
| cinfo->max_v_samp_factor = MAX(cinfo->max_v_samp_factor, |
| compptr->v_samp_factor); |
| } |
| |
| /* Compute dimensions of components */ |
| for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; |
| ci++, compptr++) { |
| /* For compression, we never do DCT scaling. */ |
| compptr->DCT_scaled_size = DCTSIZE; |
| /* Size in DCT blocks */ |
| compptr->width_in_blocks = (JDIMENSION) |
| jdiv_round_up((long) cinfo->image_width * (long) compptr->h_samp_factor, |
| (long) (cinfo->max_h_samp_factor * DCTSIZE)); |
| compptr->height_in_blocks = (JDIMENSION) |
| jdiv_round_up((long) cinfo->image_height * (long) compptr->v_samp_factor, |
| (long) (cinfo->max_v_samp_factor * DCTSIZE)); |
| /* Size in samples */ |
| compptr->downsampled_width = (JDIMENSION) |
| jdiv_round_up((long) cinfo->image_width * (long) compptr->h_samp_factor, |
| (long) cinfo->max_h_samp_factor); |
| compptr->downsampled_height = (JDIMENSION) |
| jdiv_round_up((long) cinfo->image_height * (long) compptr->v_samp_factor, |
| (long) cinfo->max_v_samp_factor); |
| /* Mark component needed (this flag isn't actually used for compression) */ |
| compptr->component_needed = TRUE; |
| } |
| |
| /* Compute number of fully interleaved MCU rows (number of times that |
| * main controller will call coefficient controller). |
| */ |
| cinfo->total_iMCU_rows = (JDIMENSION) |
| jdiv_round_up((long) cinfo->image_height, |
| (long) (cinfo->max_v_samp_factor*DCTSIZE)); |
| } |
| |
| |
| LOCAL void |
| per_scan_setup (j_compress_ptr cinfo) |
| /* Do computations that are needed before processing a JPEG scan */ |
| /* cinfo->comps_in_scan and cinfo->cur_comp_info[] are already set */ |
| { |
| int ci, mcublks, tmp; |
| jpeg_component_info *compptr; |
| |
| if (cinfo->comps_in_scan == 1) { |
| |
| /* Noninterleaved (single-component) scan */ |
| compptr = cinfo->cur_comp_info[0]; |
| |
| /* Overall image size in MCUs */ |
| cinfo->MCUs_per_row = compptr->width_in_blocks; |
| cinfo->MCU_rows_in_scan = compptr->height_in_blocks; |
| |
| /* For noninterleaved scan, always one block per MCU */ |
| compptr->MCU_width = 1; |
| compptr->MCU_height = 1; |
| compptr->MCU_blocks = 1; |
| compptr->MCU_sample_width = DCTSIZE; |
| compptr->last_col_width = 1; |
| /* For noninterleaved scans, it is convenient to define last_row_height |
| * as the number of block rows present in the last iMCU row. |
| */ |
| tmp = (int) (compptr->height_in_blocks % compptr->v_samp_factor); |
| if (tmp == 0) tmp = compptr->v_samp_factor; |
| compptr->last_row_height = tmp; |
| |
| /* Prepare array describing MCU composition */ |
| cinfo->blocks_in_MCU = 1; |
| cinfo->MCU_membership[0] = 0; |
| |
| } else { |
| |
| /* Interleaved (multi-component) scan */ |
| if (cinfo->comps_in_scan <= 0 || cinfo->comps_in_scan > MAX_COMPS_IN_SCAN) |
| ERREXIT2(cinfo, JERR_COMPONENT_COUNT, cinfo->comps_in_scan, |
| MAX_COMPS_IN_SCAN); |
| |
| /* Overall image size in MCUs */ |
| cinfo->MCUs_per_row = (JDIMENSION) |
| jdiv_round_up((long) cinfo->image_width, |
| (long) (cinfo->max_h_samp_factor*DCTSIZE)); |
| cinfo->MCU_rows_in_scan = (JDIMENSION) |
| jdiv_round_up((long) cinfo->image_height, |
| (long) (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]; |
| /* Sampling factors give # of blocks of component in each MCU */ |
| compptr->MCU_width = compptr->h_samp_factor; |
| compptr->MCU_height = compptr->v_samp_factor; |
| compptr->MCU_blocks = compptr->MCU_width * compptr->MCU_height; |
| compptr->MCU_sample_width = compptr->MCU_width * DCTSIZE; |
| /* Figure number of non-dummy blocks in last MCU column & row */ |
| tmp = (int) (compptr->width_in_blocks % compptr->MCU_width); |
| if (tmp == 0) tmp = compptr->MCU_width; |
| compptr->last_col_width = tmp; |
| tmp = (int) (compptr->height_in_blocks % compptr->MCU_height); |
| if (tmp == 0) tmp = compptr->MCU_height; |
| compptr->last_row_height = tmp; |
| /* Prepare array describing MCU composition */ |
| mcublks = compptr->MCU_blocks; |
| if (cinfo->blocks_in_MCU + mcublks > MAX_BLOCKS_IN_MCU) |
| ERREXIT(cinfo, JERR_BAD_MCU_SIZE); |
| while (mcublks-- > 0) { |
| cinfo->MCU_membership[cinfo->blocks_in_MCU++] = ci; |
| } |
| } |
| |
| } |
| |
| /* Convert restart specified in rows to actual MCU count. */ |
| /* Note that count must fit in 16 bits, so we provide limiting. */ |
| if (cinfo->restart_in_rows > 0) { |
| long nominal = (long) cinfo->restart_in_rows * (long) cinfo->MCUs_per_row; |
| cinfo->restart_interval = (unsigned int) MIN(nominal, 65535L); |
| } |
| } |
| |
| |
| /* |
| * Master selection of compression modules. |
| * This is done once at the start of processing an image. We determine |
| * which modules will be used and give them appropriate initialization calls. |
| */ |
| |
| LOCAL void |
| master_selection (j_compress_ptr cinfo) |
| { |
| my_master_ptr master = (my_master_ptr) cinfo->master; |
| |
| initial_setup(cinfo); |
| master->pass_number = 0; |
| |
| /* There's not a lot of smarts here right now, but it'll get more |
| * complicated when we have multiple implementations available... |
| */ |
| |
| /* Preprocessing */ |
| if (! cinfo->raw_data_in) { |
| jinit_color_converter(cinfo); |
| jinit_downsampler(cinfo); |
| jinit_c_prep_controller(cinfo, FALSE /* never need full buffer here */); |
| } |
| /* Forward DCT */ |
| jinit_forward_dct(cinfo); |
| /* Entropy encoding: either Huffman or arithmetic coding. */ |
| if (cinfo->arith_code) { |
| #ifdef C_ARITH_CODING_SUPPORTED |
| jinit_arith_encoder(cinfo); |
| #else |
| ERREXIT(cinfo, JERR_ARITH_NOTIMPL); |
| #endif |
| } else |
| jinit_huff_encoder(cinfo); |
| |
| /* For now, a full buffer is needed only for Huffman optimization. */ |
| jinit_c_coef_controller(cinfo, cinfo->optimize_coding); |
| jinit_c_main_controller(cinfo, FALSE /* never need full buffer here */); |
| |
| jinit_marker_writer(cinfo); |
| |
| /* We can now tell the memory manager to allocate virtual arrays. */ |
| (*cinfo->mem->realize_virt_arrays) ((j_common_ptr) cinfo); |
| |
| /* Write the datastream header (SOI) immediately. |
| * Frame and scan headers are postponed till later. |
| * This lets application insert special markers after the SOI. |
| */ |
| (*cinfo->marker->write_file_header) (cinfo); |
| } |
| |
| |
| /* |
| * Per-pass setup. |
| * This is called at the beginning of each pass. We determine which modules |
| * will be active during this pass and give them appropriate start_pass calls. |
| * We also set is_last_pass to indicate whether any more passes will be |
| * required. |
| */ |
| |
| METHODDEF void |
| prepare_for_pass (j_compress_ptr cinfo) |
| { |
| my_master_ptr master = (my_master_ptr) cinfo->master; |
| int ci; |
| int npasses; |
| |
| /* ???? JUST A QUICK CROCK FOR NOW ??? */ |
| |
| /* For now, handle only single interleaved output scan; */ |
| /* we support two passes for Huffman optimization. */ |
| |
| /* Prepare for single scan containing all components */ |
| if (cinfo->num_components > MAX_COMPS_IN_SCAN) |
| ERREXIT2(cinfo, JERR_COMPONENT_COUNT, cinfo->num_components, |
| MAX_COMPS_IN_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]; |
| } |
| |
| per_scan_setup(cinfo); |
| |
| if (! cinfo->optimize_coding) { |
| /* Standard single-pass case */ |
| npasses = 1; |
| master->pub.call_pass_startup = TRUE; |
| master->pub.is_last_pass = TRUE; |
| if (! cinfo->raw_data_in) { |
| (*cinfo->cconvert->start_pass) (cinfo); |
| (*cinfo->downsample->start_pass) (cinfo); |
| (*cinfo->prep->start_pass) (cinfo, JBUF_PASS_THRU); |
| } |
| (*cinfo->fdct->start_pass) (cinfo); |
| (*cinfo->entropy->start_pass) (cinfo, FALSE); |
| (*cinfo->coef->start_pass) (cinfo, JBUF_PASS_THRU); |
| (*cinfo->main->start_pass) (cinfo, JBUF_PASS_THRU); |
| } else { |
| npasses = 2; |
| switch (master->pass_number) { |
| case 0: |
| /* Huffman optimization: run all modules, gather statistics */ |
| master->pub.call_pass_startup = FALSE; |
| master->pub.is_last_pass = FALSE; |
| if (! cinfo->raw_data_in) { |
| (*cinfo->cconvert->start_pass) (cinfo); |
| (*cinfo->downsample->start_pass) (cinfo); |
| (*cinfo->prep->start_pass) (cinfo, JBUF_PASS_THRU); |
| } |
| (*cinfo->fdct->start_pass) (cinfo); |
| (*cinfo->entropy->start_pass) (cinfo, TRUE); |
| (*cinfo->coef->start_pass) (cinfo, JBUF_SAVE_AND_PASS); |
| (*cinfo->main->start_pass) (cinfo, JBUF_PASS_THRU); |
| break; |
| case 1: |
| /* Second pass: reread data from coefficient buffer */ |
| master->pub.is_last_pass = TRUE; |
| (*cinfo->entropy->start_pass) (cinfo, FALSE); |
| (*cinfo->coef->start_pass) (cinfo, JBUF_CRANK_DEST); |
| /* We emit frame/scan headers now */ |
| (*cinfo->marker->write_frame_header) (cinfo); |
| (*cinfo->marker->write_scan_header) (cinfo); |
| break; |
| } |
| } |
| |
| /* Set up progress monitor's pass info if present */ |
| if (cinfo->progress != NULL) { |
| cinfo->progress->completed_passes = master->pass_number; |
| cinfo->progress->total_passes = npasses; |
| } |
| |
| master->pass_number++; |
| } |
| |
| |
| /* |
| * Special start-of-pass hook. |
| * This is called by jpeg_write_scanlines if call_pass_startup is TRUE. |
| * In single-pass processing, we need this hook because we don't want to |
| * write frame/scan headers during jpeg_start_compress; we want to let the |
| * application write COM markers etc. between jpeg_start_compress and the |
| * jpeg_write_scanlines loop. |
| * In multi-pass processing, this routine is not used. |
| */ |
| |
| METHODDEF void |
| pass_startup (j_compress_ptr cinfo) |
| { |
| cinfo->master->call_pass_startup = FALSE; /* reset flag so call only once */ |
| |
| (*cinfo->marker->write_frame_header) (cinfo); |
| (*cinfo->marker->write_scan_header) (cinfo); |
| } |
| |
| |
| /* |
| * Finish up at end of pass. |
| */ |
| |
| METHODDEF void |
| finish_pass_master (j_compress_ptr cinfo) |
| { |
| /* More complex logic later ??? */ |
| |
| /* The entropy coder needs an end-of-pass call, either to analyze |
| * statistics or to flush its output buffer. |
| */ |
| (*cinfo->entropy->finish_pass) (cinfo); |
| } |
| |
| |
| /* |
| * Initialize master compression control. |
| * This creates my own subrecord and also performs the master selection phase, |
| * which causes other modules to create their subrecords. |
| */ |
| |
| GLOBAL void |
| jinit_master_compress (j_compress_ptr cinfo) |
| { |
| my_master_ptr master; |
| |
| master = (my_master_ptr) |
| (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, |
| SIZEOF(my_comp_master)); |
| cinfo->master = (struct jpeg_comp_master *) master; |
| master->pub.prepare_for_pass = prepare_for_pass; |
| master->pub.pass_startup = pass_startup; |
| master->pub.finish_pass = finish_pass_master; |
| |
| master_selection(cinfo); |
| } |