1/* 2 * reserved comment block 3 * DO NOT REMOVE OR ALTER! 4 */ 5/* 6 * jcmainct.c 7 * 8 * Copyright (C) 1994-1996, Thomas G. Lane. 9 * This file is part of the Independent JPEG Group's software. 10 * For conditions of distribution and use, see the accompanying README file. 11 * 12 * This file contains the main buffer controller for compression. 13 * The main buffer lies between the pre-processor and the JPEG 14 * compressor proper; it holds downsampled data in the JPEG colorspace. 15 */ 16 17#define JPEG_INTERNALS 18#include "jinclude.h" 19#include "jpeglib.h" 20 21 22/* Note: currently, there is no operating mode in which a full-image buffer 23 * is needed at this step. If there were, that mode could not be used with 24 * "raw data" input, since this module is bypassed in that case. However, 25 * we've left the code here for possible use in special applications. 26 */ 27#undef FULL_MAIN_BUFFER_SUPPORTED 28 29 30/* Private buffer controller object */ 31 32typedef struct { 33 struct jpeg_c_main_controller pub; /* public fields */ 34 35 JDIMENSION cur_iMCU_row; /* number of current iMCU row */ 36 JDIMENSION rowgroup_ctr; /* counts row groups received in iMCU row */ 37 boolean suspended; /* remember if we suspended output */ 38 J_BUF_MODE pass_mode; /* current operating mode */ 39 40 /* If using just a strip buffer, this points to the entire set of buffers 41 * (we allocate one for each component). In the full-image case, this 42 * points to the currently accessible strips of the virtual arrays. 43 */ 44 JSAMPARRAY buffer[MAX_COMPONENTS]; 45 46#ifdef FULL_MAIN_BUFFER_SUPPORTED 47 /* If using full-image storage, this array holds pointers to virtual-array 48 * control blocks for each component. Unused if not full-image storage. 49 */ 50 jvirt_sarray_ptr whole_image[MAX_COMPONENTS]; 51#endif 52} my_main_controller; 53 54typedef my_main_controller * my_main_ptr; 55 56 57/* Forward declarations */ 58METHODDEF(void) process_data_simple_main 59 JPP((j_compress_ptr cinfo, JSAMPARRAY input_buf, 60 JDIMENSION *in_row_ctr, JDIMENSION in_rows_avail)); 61#ifdef FULL_MAIN_BUFFER_SUPPORTED 62METHODDEF(void) process_data_buffer_main 63 JPP((j_compress_ptr cinfo, JSAMPARRAY input_buf, 64 JDIMENSION *in_row_ctr, JDIMENSION in_rows_avail)); 65#endif 66 67 68/* 69 * Initialize for a processing pass. 70 */ 71 72METHODDEF(void) 73start_pass_main (j_compress_ptr cinfo, J_BUF_MODE pass_mode) 74{ 75 my_main_ptr _main = (my_main_ptr) cinfo->main; 76 77 /* Do nothing in raw-data mode. */ 78 if (cinfo->raw_data_in) 79 return; 80 81 _main->cur_iMCU_row = 0; /* initialize counters */ 82 _main->rowgroup_ctr = 0; 83 _main->suspended = FALSE; 84 _main->pass_mode = pass_mode; /* save mode for use by process_data */ 85 86 switch (pass_mode) { 87 case JBUF_PASS_THRU: 88#ifdef FULL_MAIN_BUFFER_SUPPORTED 89 if (_main->whole_image[0] != NULL) 90 ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); 91#endif 92 _main->pub.process_data = process_data_simple_main; 93 break; 94#ifdef FULL_MAIN_BUFFER_SUPPORTED 95 case JBUF_SAVE_SOURCE: 96 case JBUF_CRANK_DEST: 97 case JBUF_SAVE_AND_PASS: 98 if (_main->whole_image[0] == NULL) 99 ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); 100 _main->pub.process_data = process_data_buffer_main; 101 break; 102#endif 103 default: 104 ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); 105 break; 106 } 107} 108 109 110/* 111 * Process some data. 112 * This routine handles the simple pass-through mode, 113 * where we have only a strip buffer. 114 */ 115 116METHODDEF(void) 117process_data_simple_main (j_compress_ptr cinfo, 118 JSAMPARRAY input_buf, JDIMENSION *in_row_ctr, 119 JDIMENSION in_rows_avail) 120{ 121 my_main_ptr _main = (my_main_ptr) cinfo->main; 122 123 while (_main->cur_iMCU_row < cinfo->total_iMCU_rows) { 124 /* Read input data if we haven't filled the main buffer yet */ 125 if (_main->rowgroup_ctr < DCTSIZE) 126 (*cinfo->prep->pre_process_data) (cinfo, 127 input_buf, in_row_ctr, in_rows_avail, 128 _main->buffer, &_main->rowgroup_ctr, 129 (JDIMENSION) DCTSIZE); 130 131 /* If we don't have a full iMCU row buffered, return to application for 132 * more data. Note that preprocessor will always pad to fill the iMCU row 133 * at the bottom of the image. 134 */ 135 if (_main->rowgroup_ctr != DCTSIZE) 136 return; 137 138 /* Send the completed row to the compressor */ 139 if (! (*cinfo->coef->compress_data) (cinfo, _main->buffer)) { 140 /* If compressor did not consume the whole row, then we must need to 141 * suspend processing and return to the application. In this situation 142 * we pretend we didn't yet consume the last input row; otherwise, if 143 * it happened to be the last row of the image, the application would 144 * think we were done. 145 */ 146 if (! _main->suspended) { 147 (*in_row_ctr)--; 148 _main->suspended = TRUE; 149 } 150 return; 151 } 152 /* We did finish the row. Undo our little suspension hack if a previous 153 * call suspended; then mark the main buffer empty. 154 */ 155 if (_main->suspended) { 156 (*in_row_ctr)++; 157 _main->suspended = FALSE; 158 } 159 _main->rowgroup_ctr = 0; 160 _main->cur_iMCU_row++; 161 } 162} 163 164 165#ifdef FULL_MAIN_BUFFER_SUPPORTED 166 167/* 168 * Process some data. 169 * This routine handles all of the modes that use a full-size buffer. 170 */ 171 172METHODDEF(void) 173process_data_buffer_main (j_compress_ptr cinfo, 174 JSAMPARRAY input_buf, JDIMENSION *in_row_ctr, 175 JDIMENSION in_rows_avail) 176{ 177 my_main_ptr _main = (my_main_ptr) cinfo->main; 178 int ci; 179 jpeg_component_info *compptr; 180 boolean writing = (_main->pass_mode != JBUF_CRANK_DEST); 181 182 while (_main->cur_iMCU_row < cinfo->total_iMCU_rows) { 183 /* Realign the virtual buffers if at the start of an iMCU row. */ 184 if (_main->rowgroup_ctr == 0) { 185 for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; 186 ci++, compptr++) { 187 _main->buffer[ci] = (*cinfo->mem->access_virt_sarray) 188 ((j_common_ptr) cinfo, _main->whole_image[ci], 189 _main->cur_iMCU_row * (compptr->v_samp_factor * DCTSIZE), 190 (JDIMENSION) (compptr->v_samp_factor * DCTSIZE), writing); 191 } 192 /* In a read pass, pretend we just read some source data. */ 193 if (! writing) { 194 *in_row_ctr += cinfo->max_v_samp_factor * DCTSIZE; 195 _main->rowgroup_ctr = DCTSIZE; 196 } 197 } 198 199 /* If a write pass, read input data until the current iMCU row is full. */ 200 /* Note: preprocessor will pad if necessary to fill the last iMCU row. */ 201 if (writing) { 202 (*cinfo->prep->pre_process_data) (cinfo, 203 input_buf, in_row_ctr, in_rows_avail, 204 _main->buffer, &_main->rowgroup_ctr, 205 (JDIMENSION) DCTSIZE); 206 /* Return to application if we need more data to fill the iMCU row. */ 207 if (_main->rowgroup_ctr < DCTSIZE) 208 return; 209 } 210 211 /* Emit data, unless this is a sink-only pass. */ 212 if (_main->pass_mode != JBUF_SAVE_SOURCE) { 213 if (! (*cinfo->coef->compress_data) (cinfo, _main->buffer)) { 214 /* If compressor did not consume the whole row, then we must need to 215 * suspend processing and return to the application. In this situation 216 * we pretend we didn't yet consume the last input row; otherwise, if 217 * it happened to be the last row of the image, the application would 218 * think we were done. 219 */ 220 if (! _main->suspended) { 221 (*in_row_ctr)--; 222 _main->suspended = TRUE; 223 } 224 return; 225 } 226 /* We did finish the row. Undo our little suspension hack if a previous 227 * call suspended; then mark the main buffer empty. 228 */ 229 if (_main->suspended) { 230 (*in_row_ctr)++; 231 _main->suspended = FALSE; 232 } 233 } 234 235 /* If get here, we are done with this iMCU row. Mark buffer empty. */ 236 _main->rowgroup_ctr = 0; 237 _main->cur_iMCU_row++; 238 } 239} 240 241#endif /* FULL_MAIN_BUFFER_SUPPORTED */ 242 243 244/* 245 * Initialize main buffer controller. 246 */ 247 248GLOBAL(void) 249jinit_c_main_controller (j_compress_ptr cinfo, boolean need_full_buffer) 250{ 251 my_main_ptr _main; 252 int ci; 253 jpeg_component_info *compptr; 254 255 _main = (my_main_ptr) 256 (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, 257 SIZEOF(my_main_controller)); 258 cinfo->main = (struct jpeg_c_main_controller *) _main; 259 _main->pub.start_pass = start_pass_main; 260 261 /* We don't need to create a buffer in raw-data mode. */ 262 if (cinfo->raw_data_in) 263 return; 264 265 /* Create the buffer. It holds downsampled data, so each component 266 * may be of a different size. 267 */ 268 if (need_full_buffer) { 269#ifdef FULL_MAIN_BUFFER_SUPPORTED 270 /* Allocate a full-image virtual array for each component */ 271 /* Note we pad the bottom to a multiple of the iMCU height */ 272 for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; 273 ci++, compptr++) { 274 _main->whole_image[ci] = (*cinfo->mem->request_virt_sarray) 275 ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE, 276 compptr->width_in_blocks * DCTSIZE, 277 (JDIMENSION) jround_up((long) compptr->height_in_blocks, 278 (long) compptr->v_samp_factor) * DCTSIZE, 279 (JDIMENSION) (compptr->v_samp_factor * DCTSIZE)); 280 } 281#else 282 ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); 283#endif 284 } else { 285#ifdef FULL_MAIN_BUFFER_SUPPORTED 286 _main->whole_image[0] = NULL; /* flag for no virtual arrays */ 287#endif 288 /* Allocate a strip buffer for each component */ 289 for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; 290 ci++, compptr++) { 291 _main->buffer[ci] = (*cinfo->mem->alloc_sarray) 292 ((j_common_ptr) cinfo, JPOOL_IMAGE, 293 compptr->width_in_blocks * DCTSIZE, 294 (JDIMENSION) (compptr->v_samp_factor * DCTSIZE)); 295 } 296 } 297} 298