jcmainct.c 9.16 KB
Newer Older
1 2 3 4 5 6 7
/*
 * jcmainct.c
 *
 * Copyright (C) 1994-1996, 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.
 *
8 9
 * This file contains the main_ptr buffer controller for compression.
 * The main_ptr buffer lies between the pre-processor and the JPEG
10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
 * compressor proper; it holds downsampled data in the JPEG colorspace.
 */

#define JPEG_INTERNALS
#include "jinclude.h"
#include "jpeglib.h"


/* Note: currently, there is no operating mode in which a full-image buffer
 * is needed at this step.  If there were, that mode could not be used with
 * "raw data" input, since this module is bypassed in that case.  However,
 * we've left the code here for possible use in special applications.
 */
#undef FULL_MAIN_BUFFER_SUPPORTED


/* Private buffer controller object */

typedef struct {
  struct jpeg_c_main_controller pub; /* public fields */

  JDIMENSION cur_iMCU_row;	/* number of current iMCU row */
  JDIMENSION rowgroup_ctr;	/* counts row groups received in iMCU row */
  boolean suspended;		/* remember if we suspended output */
  J_BUF_MODE pass_mode;		/* current operating mode */

  /* If using just a strip buffer, this points to the entire set of buffers
   * (we allocate one for each component).  In the full-image case, this
   * points to the currently accessible strips of the virtual arrays.
   */
  JSAMPARRAY buffer[MAX_COMPONENTS];

#ifdef FULL_MAIN_BUFFER_SUPPORTED
  /* If using full-image storage, this array holds pointers to virtual-array
   * control blocks for each component.  Unused if not full-image storage.
   */
  jvirt_sarray_ptr whole_image[MAX_COMPONENTS];
#endif
} my_main_controller;

typedef my_main_controller * my_main_ptr;


/* Forward declarations */
METHODDEF(void) process_data_simple_main
	JPP((j_compress_ptr cinfo, JSAMPARRAY input_buf,
	     JDIMENSION *in_row_ctr, JDIMENSION in_rows_avail));
#ifdef FULL_MAIN_BUFFER_SUPPORTED
METHODDEF(void) process_data_buffer_main
	JPP((j_compress_ptr cinfo, JSAMPARRAY input_buf,
	     JDIMENSION *in_row_ctr, JDIMENSION in_rows_avail));
#endif


/*
 * Initialize for a processing pass.
 */

METHODDEF(void)
start_pass_main (j_compress_ptr cinfo, J_BUF_MODE pass_mode)
{
71
  my_main_ptr main_ptr = (my_main_ptr) cinfo->main;
72 73 74 75 76

  /* Do nothing in raw-data mode. */
  if (cinfo->raw_data_in)
    return;

77 78 79 80
  main_ptr->cur_iMCU_row = 0;	/* initialize counters */
  main_ptr->rowgroup_ctr = 0;
  main_ptr->suspended = FALSE;
  main_ptr->pass_mode = pass_mode;	/* save mode for use by process_data */
81 82 83 84

  switch (pass_mode) {
  case JBUF_PASS_THRU:
#ifdef FULL_MAIN_BUFFER_SUPPORTED
85
    if (main_ptr->whole_image[0] != NULL)
86 87
      ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
#endif
88
    main_ptr->pub.process_data = process_data_simple_main;
89 90 91 92 93
    break;
#ifdef FULL_MAIN_BUFFER_SUPPORTED
  case JBUF_SAVE_SOURCE:
  case JBUF_CRANK_DEST:
  case JBUF_SAVE_AND_PASS:
94
    if (main_ptr->whole_image[0] == NULL)
95
      ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
96
    main_ptr->pub.process_data = process_data_buffer_main;
97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116
    break;
#endif
  default:
    ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
    break;
  }
}


/*
 * Process some data.
 * This routine handles the simple pass-through mode,
 * where we have only a strip buffer.
 */

METHODDEF(void)
process_data_simple_main (j_compress_ptr cinfo,
			  JSAMPARRAY input_buf, JDIMENSION *in_row_ctr,
			  JDIMENSION in_rows_avail)
{
117
  my_main_ptr main_ptr = (my_main_ptr) cinfo->main;
118

119 120 121
  while (main_ptr->cur_iMCU_row < cinfo->total_iMCU_rows) {
    /* Read input data if we haven't filled the main_ptr buffer yet */
    if (main_ptr->rowgroup_ctr < DCTSIZE)
122 123
      (*cinfo->prep->pre_process_data) (cinfo,
					input_buf, in_row_ctr, in_rows_avail,
124
					main_ptr->buffer, &main_ptr->rowgroup_ctr,
125 126 127 128 129 130
					(JDIMENSION) DCTSIZE);

    /* If we don't have a full iMCU row buffered, return to application for
     * more data.  Note that preprocessor will always pad to fill the iMCU row
     * at the bottom of the image.
     */
131
    if (main_ptr->rowgroup_ctr != DCTSIZE)
132 133 134
      return;

    /* Send the completed row to the compressor */
135
    if (! (*cinfo->coef->compress_data) (cinfo, main_ptr->buffer)) {
136 137 138 139 140 141
      /* If compressor did not consume the whole row, then we must need to
       * suspend processing and return to the application.  In this situation
       * we pretend we didn't yet consume the last input row; otherwise, if
       * it happened to be the last row of the image, the application would
       * think we were done.
       */
142
      if (! main_ptr->suspended) {
143
	(*in_row_ctr)--;
144
	main_ptr->suspended = TRUE;
145 146 147 148
      }
      return;
    }
    /* We did finish the row.  Undo our little suspension hack if a previous
149
     * call suspended; then mark the main_ptr buffer empty.
150
     */
151
    if (main_ptr->suspended) {
152
      (*in_row_ctr)++;
153
      main_ptr->suspended = FALSE;
154
    }
155 156
    main_ptr->rowgroup_ctr = 0;
    main_ptr->cur_iMCU_row++;
157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
  }
}


#ifdef FULL_MAIN_BUFFER_SUPPORTED

/*
 * Process some data.
 * This routine handles all of the modes that use a full-size buffer.
 */

METHODDEF(void)
process_data_buffer_main (j_compress_ptr cinfo,
			  JSAMPARRAY input_buf, JDIMENSION *in_row_ctr,
			  JDIMENSION in_rows_avail)
{
173
  my_main_ptr main_ptr = (my_main_ptr) cinfo->main;
174 175
  int ci;
  jpeg_component_info *compptr;
176
  boolean writing = (main_ptr->pass_mode != JBUF_CRANK_DEST);
177

178
  while (main_ptr->cur_iMCU_row < cinfo->total_iMCU_rows) {
179
    /* Realign the virtual buffers if at the start of an iMCU row. */
180
    if (main_ptr->rowgroup_ctr == 0) {
181 182
      for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
	   ci++, compptr++) {
183 184 185
	main_ptr->buffer[ci] = (*cinfo->mem->access_virt_sarray)
	  ((j_common_ptr) cinfo, main_ptr->whole_image[ci],
	   main_ptr->cur_iMCU_row * (compptr->v_samp_factor * DCTSIZE),
186 187 188 189 190
	   (JDIMENSION) (compptr->v_samp_factor * DCTSIZE), writing);
      }
      /* In a read pass, pretend we just read some source data. */
      if (! writing) {
	*in_row_ctr += cinfo->max_v_samp_factor * DCTSIZE;
191
	main_ptr->rowgroup_ctr = DCTSIZE;
192 193 194 195 196 197 198 199
      }
    }

    /* If a write pass, read input data until the current iMCU row is full. */
    /* Note: preprocessor will pad if necessary to fill the last iMCU row. */
    if (writing) {
      (*cinfo->prep->pre_process_data) (cinfo,
					input_buf, in_row_ctr, in_rows_avail,
200
					main_ptr->buffer, &main_ptr->rowgroup_ctr,
201 202
					(JDIMENSION) DCTSIZE);
      /* Return to application if we need more data to fill the iMCU row. */
203
      if (main_ptr->rowgroup_ctr < DCTSIZE)
204 205 206 207
	return;
    }

    /* Emit data, unless this is a sink-only pass. */
208 209
    if (main_ptr->pass_mode != JBUF_SAVE_SOURCE) {
      if (! (*cinfo->coef->compress_data) (cinfo, main_ptr->buffer)) {
210 211 212 213 214 215
	/* If compressor did not consume the whole row, then we must need to
	 * suspend processing and return to the application.  In this situation
	 * we pretend we didn't yet consume the last input row; otherwise, if
	 * it happened to be the last row of the image, the application would
	 * think we were done.
	 */
216
	if (! main_ptr->suspended) {
217
	  (*in_row_ctr)--;
218
	  main_ptr->suspended = TRUE;
219 220 221 222
	}
	return;
      }
      /* We did finish the row.  Undo our little suspension hack if a previous
223
       * call suspended; then mark the main_ptr buffer empty.
224
       */
225
      if (main_ptr->suspended) {
226
	(*in_row_ctr)++;
227
	main_ptr->suspended = FALSE;
228 229 230 231
      }
    }

    /* If get here, we are done with this iMCU row.  Mark buffer empty. */
232 233
    main_ptr->rowgroup_ctr = 0;
    main_ptr->cur_iMCU_row++;
234 235 236 237 238 239 240
  }
}

#endif /* FULL_MAIN_BUFFER_SUPPORTED */


/*
241
 * Initialize main_ptr buffer controller.
242 243 244 245 246
 */

GLOBAL(void)
jinit_c_main_controller (j_compress_ptr cinfo, boolean need_full_buffer)
{
247
  my_main_ptr main_ptr;
248 249 250
  int ci;
  jpeg_component_info *compptr;

251
  main_ptr = (my_main_ptr)
252 253
    (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
				SIZEOF(my_main_controller));
254 255
  cinfo->main = (struct jpeg_c_main_controller *) main_ptr;
  main_ptr->pub.start_pass = start_pass_main;
256 257 258 259 260 261 262 263 264 265 266 267 268 269

  /* We don't need to create a buffer in raw-data mode. */
  if (cinfo->raw_data_in)
    return;

  /* Create the buffer.  It holds downsampled data, so each component
   * may be of a different size.
   */
  if (need_full_buffer) {
#ifdef FULL_MAIN_BUFFER_SUPPORTED
    /* Allocate a full-image virtual array for each component */
    /* Note we pad the bottom to a multiple of the iMCU height */
    for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
	 ci++, compptr++) {
270
      main_ptr->whole_image[ci] = (*cinfo->mem->request_virt_sarray)
271 272 273 274 275 276 277 278 279 280 281
	((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE,
	 compptr->width_in_blocks * DCTSIZE,
	 (JDIMENSION) jround_up((long) compptr->height_in_blocks,
				(long) compptr->v_samp_factor) * DCTSIZE,
	 (JDIMENSION) (compptr->v_samp_factor * DCTSIZE));
    }
#else
    ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
#endif
  } else {
#ifdef FULL_MAIN_BUFFER_SUPPORTED
282
    main_ptr->whole_image[0] = NULL; /* flag for no virtual arrays */
283 284 285 286
#endif
    /* Allocate a strip buffer for each component */
    for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
	 ci++, compptr++) {
287
      main_ptr->buffer[ci] = (*cinfo->mem->alloc_sarray)
288 289 290 291 292 293
	((j_common_ptr) cinfo, JPOOL_IMAGE,
	 compptr->width_in_blocks * DCTSIZE,
	 (JDIMENSION) (compptr->v_samp_factor * DCTSIZE));
    }
  }
}