Merge branch 'upstream' into tizen_base
[platform/upstream/libjpeg-turbo.git] / jcdiffct.c
1 /*
2  * jcdiffct.c
3  *
4  * This file was part of the Independent JPEG Group's software:
5  * Copyright (C) 1994-1997, Thomas G. Lane.
6  * Lossless JPEG Modifications:
7  * Copyright (C) 1999, Ken Murchison.
8  * libjpeg-turbo Modifications:
9  * Copyright (C) 2022, D. R. Commander.
10  * For conditions of distribution and use, see the accompanying README.ijg
11  * file.
12  *
13  * This file contains the difference buffer controller for compression.
14  * This controller is the top level of the lossless JPEG compressor proper.
15  * The difference buffer lies between the prediction/differencing and entropy
16  * encoding steps.
17  */
18
19 #define JPEG_INTERNALS
20 #include "jinclude.h"
21 #include "jpeglib.h"
22 #include "jlossls.h"            /* Private declarations for lossless codec */
23
24
25 #ifdef C_LOSSLESS_SUPPORTED
26
27 /* We use a full-image sample buffer when doing Huffman optimization,
28  * and also for writing multiple-scan JPEG files.  In all cases, the
29  * full-image buffer is filled during the first pass, and the scaling,
30  * prediction and differencing steps are run during subsequent passes.
31  */
32 #ifdef ENTROPY_OPT_SUPPORTED
33 #define FULL_SAMP_BUFFER_SUPPORTED
34 #else
35 #ifdef C_MULTISCAN_FILES_SUPPORTED
36 #define FULL_SAMP_BUFFER_SUPPORTED
37 #endif
38 #endif
39
40
41 /* Private buffer controller object */
42
43 typedef struct {
44   struct jpeg_c_coef_controller pub; /* public fields */
45
46   JDIMENSION iMCU_row_num;      /* iMCU row # within image */
47   JDIMENSION mcu_ctr;           /* counts MCUs processed in current row */
48   int MCU_vert_offset;          /* counts MCU rows within iMCU row */
49   int MCU_rows_per_iMCU_row;    /* number of such rows needed */
50
51   _JSAMPROW cur_row[MAX_COMPONENTS];    /* row of point-transformed samples */
52   _JSAMPROW prev_row[MAX_COMPONENTS];   /* previous row of Pt'd samples */
53   JDIFFARRAY diff_buf[MAX_COMPONENTS];  /* iMCU row of differences */
54
55   /* In multi-pass modes, we need a virtual sample array for each component. */
56   jvirt_sarray_ptr whole_image[MAX_COMPONENTS];
57 } my_diff_controller;
58
59 typedef my_diff_controller *my_diff_ptr;
60
61
62 /* Forward declarations */
63 METHODDEF(boolean) compress_data(j_compress_ptr cinfo, _JSAMPIMAGE input_buf);
64 #ifdef FULL_SAMP_BUFFER_SUPPORTED
65 METHODDEF(boolean) compress_first_pass(j_compress_ptr cinfo,
66                                        _JSAMPIMAGE input_buf);
67 METHODDEF(boolean) compress_output(j_compress_ptr cinfo,
68                                    _JSAMPIMAGE input_buf);
69 #endif
70
71
72 LOCAL(void)
73 start_iMCU_row(j_compress_ptr cinfo)
74 /* Reset within-iMCU-row counters for a new row */
75 {
76   my_diff_ptr diff = (my_diff_ptr)cinfo->coef;
77
78   /* In an interleaved scan, an MCU row is the same as an iMCU row.
79    * In a noninterleaved scan, an iMCU row has v_samp_factor MCU rows.
80    * But at the bottom of the image, process only what's left.
81    */
82   if (cinfo->comps_in_scan > 1) {
83     diff->MCU_rows_per_iMCU_row = 1;
84   } else {
85     if (diff->iMCU_row_num < (cinfo->total_iMCU_rows-1))
86       diff->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->v_samp_factor;
87     else
88       diff->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->last_row_height;
89   }
90
91   diff->mcu_ctr = 0;
92   diff->MCU_vert_offset = 0;
93 }
94
95
96 /*
97  * Initialize for a processing pass.
98  */
99
100 METHODDEF(void)
101 start_pass_diff(j_compress_ptr cinfo, J_BUF_MODE pass_mode)
102 {
103   my_diff_ptr diff = (my_diff_ptr)cinfo->coef;
104
105   /* Because it is hitching a ride on the jpeg_forward_dct struct,
106    * start_pass_lossless() will be called at the start of the initial pass.
107    * This ensures that it will be called at the start of the Huffman
108    * optimization and output passes as well.
109    */
110   if (pass_mode == JBUF_CRANK_DEST)
111     (*cinfo->fdct->start_pass) (cinfo);
112
113   diff->iMCU_row_num = 0;
114   start_iMCU_row(cinfo);
115
116   switch (pass_mode) {
117   case JBUF_PASS_THRU:
118     if (diff->whole_image[0] != NULL)
119       ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
120     diff->pub._compress_data = compress_data;
121     break;
122 #ifdef FULL_SAMP_BUFFER_SUPPORTED
123   case JBUF_SAVE_AND_PASS:
124     if (diff->whole_image[0] == NULL)
125       ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
126     diff->pub._compress_data = compress_first_pass;
127     break;
128   case JBUF_CRANK_DEST:
129     if (diff->whole_image[0] == NULL)
130       ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
131     diff->pub._compress_data = compress_output;
132     break;
133 #endif
134   default:
135     ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
136     break;
137   }
138 }
139
140
141 #define SWAP_ROWS(rowa, rowb) { \
142   _JSAMPROW temp = rowa; \
143   rowa = rowb;  rowb = temp; \
144 }
145
146 /*
147  * Process some data in the single-pass case.
148  * We process the equivalent of one fully interleaved MCU row ("iMCU" row)
149  * per call, ie, v_samp_factor rows for each component in the image.
150  * Returns TRUE if the iMCU row is completed, FALSE if suspended.
151  *
152  * NB: input_buf contains a plane for each component in image,
153  * which we index according to the component's SOF position.
154  */
155
156 METHODDEF(boolean)
157 compress_data(j_compress_ptr cinfo, _JSAMPIMAGE input_buf)
158 {
159   my_diff_ptr diff = (my_diff_ptr)cinfo->coef;
160   lossless_comp_ptr losslessc = (lossless_comp_ptr)cinfo->fdct;
161   JDIMENSION MCU_col_num;       /* index of current MCU within row */
162   JDIMENSION MCU_count;         /* number of MCUs encoded */
163   JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1;
164   int ci, compi, yoffset, samp_row, samp_rows, samps_across;
165   jpeg_component_info *compptr;
166
167   /* Loop to write as much as one whole iMCU row */
168   for (yoffset = diff->MCU_vert_offset; yoffset < diff->MCU_rows_per_iMCU_row;
169        yoffset++) {
170
171     MCU_col_num = diff->mcu_ctr;
172
173     /* Scale and predict each scanline of the MCU row separately.
174      *
175      * Note: We only do this if we are at the start of an MCU row, ie,
176      * we don't want to reprocess a row suspended by the output.
177      */
178     if (MCU_col_num == 0) {
179       for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
180         compptr = cinfo->cur_comp_info[ci];
181         compi = compptr->component_index;
182         if (diff->iMCU_row_num < last_iMCU_row)
183           samp_rows = compptr->v_samp_factor;
184         else {
185           /* NB: can't use last_row_height here, since may not be set! */
186           samp_rows =
187             (int)(compptr->height_in_blocks % compptr->v_samp_factor);
188           if (samp_rows == 0) samp_rows = compptr->v_samp_factor;
189           else {
190             /* Fill dummy difference rows at the bottom edge with zeros, which
191              * will encode to the smallest amount of data.
192              */
193             for (samp_row = samp_rows; samp_row < compptr->v_samp_factor;
194                  samp_row++)
195               memset(diff->diff_buf[compi][samp_row], 0,
196                      jround_up((long)compptr->width_in_blocks,
197                                (long)compptr->h_samp_factor) * sizeof(JDIFF));
198           }
199         }
200         samps_across = compptr->width_in_blocks;
201
202         for (samp_row = 0; samp_row < samp_rows; samp_row++) {
203           (*losslessc->scaler_scale) (cinfo,
204                                       input_buf[compi][samp_row],
205                                       diff->cur_row[compi],
206                                       samps_across);
207           (*losslessc->predict_difference[compi])
208             (cinfo, compi, diff->cur_row[compi], diff->prev_row[compi],
209              diff->diff_buf[compi][samp_row], samps_across);
210           SWAP_ROWS(diff->cur_row[compi], diff->prev_row[compi]);
211         }
212       }
213     }
214     /* Try to write the MCU row (or remaining portion of suspended MCU row). */
215     MCU_count =
216       (*cinfo->entropy->encode_mcus) (cinfo,
217                                       diff->diff_buf, yoffset, MCU_col_num,
218                                       cinfo->MCUs_per_row - MCU_col_num);
219     if (MCU_count != cinfo->MCUs_per_row - MCU_col_num) {
220       /* Suspension forced; update state counters and exit */
221       diff->MCU_vert_offset = yoffset;
222       diff->mcu_ctr += MCU_col_num;
223       return FALSE;
224     }
225     /* Completed an MCU row, but perhaps not an iMCU row */
226     diff->mcu_ctr = 0;
227   }
228   /* Completed the iMCU row, advance counters for next one */
229   diff->iMCU_row_num++;
230   start_iMCU_row(cinfo);
231   return TRUE;
232 }
233
234
235 #ifdef FULL_SAMP_BUFFER_SUPPORTED
236
237 /*
238  * Process some data in the first pass of a multi-pass case.
239  * We process the equivalent of one fully interleaved MCU row ("iMCU" row)
240  * per call, ie, v_samp_factor rows for each component in the image.
241  * This amount of data is read from the source buffer and saved into the
242  * virtual arrays.
243  *
244  * We must also emit the data to the compressor.  This is conveniently
245  * done by calling compress_output() after we've loaded the current strip
246  * of the virtual arrays.
247  *
248  * NB: input_buf contains a plane for each component in image.  All components
249  * are loaded into the virtual arrays in this pass.  However, it may be that
250  * only a subset of the components are emitted to the compressor during
251  * this first pass; be careful about looking at the scan-dependent variables
252  * (MCU dimensions, etc).
253  */
254
255 METHODDEF(boolean)
256 compress_first_pass(j_compress_ptr cinfo, _JSAMPIMAGE input_buf)
257 {
258   my_diff_ptr diff = (my_diff_ptr)cinfo->coef;
259   JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1;
260   JDIMENSION samps_across;
261   int ci, samp_row, samp_rows;
262   _JSAMPARRAY buffer;
263   jpeg_component_info *compptr;
264
265   for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
266        ci++, compptr++) {
267     /* Align the virtual buffer for this component. */
268     buffer = (_JSAMPARRAY)(*cinfo->mem->access_virt_sarray)
269       ((j_common_ptr)cinfo, diff->whole_image[ci],
270        diff->iMCU_row_num * compptr->v_samp_factor,
271        (JDIMENSION)compptr->v_samp_factor, TRUE);
272
273     /* Count non-dummy sample rows in this iMCU row. */
274     if (diff->iMCU_row_num < last_iMCU_row)
275       samp_rows = compptr->v_samp_factor;
276     else {
277       /* NB: can't use last_row_height here, since may not be set! */
278       samp_rows = (int)(compptr->height_in_blocks % compptr->v_samp_factor);
279       if (samp_rows == 0) samp_rows = compptr->v_samp_factor;
280     }
281     samps_across = compptr->width_in_blocks;
282
283     /* Perform point transform scaling and prediction/differencing for all
284      * non-dummy rows in this iMCU row.  Each call on these functions
285      * processes a complete row of samples.
286      */
287     for (samp_row = 0; samp_row < samp_rows; samp_row++) {
288       memcpy(buffer[samp_row], input_buf[ci][samp_row],
289              samps_across * sizeof(_JSAMPLE));
290     }
291   }
292   /* NB: compress_output will increment iMCU_row_num if successful.
293    * A suspension return will result in redoing all the work above next time.
294    */
295
296   /* Emit data to the compressor, sharing code with subsequent passes */
297   return compress_output(cinfo, input_buf);
298 }
299
300
301 /*
302  * Process some data in subsequent passes of a multi-pass case.
303  * We process the equivalent of one fully interleaved MCU row ("iMCU" row)
304  * per call, ie, v_samp_factor rows for each component in the scan.
305  * The data is obtained from the virtual arrays and fed to the compressor.
306  * Returns TRUE if the iMCU row is completed, FALSE if suspended.
307  *
308  * NB: input_buf is ignored; it is likely to be a NULL pointer.
309  */
310
311 METHODDEF(boolean)
312 compress_output(j_compress_ptr cinfo, _JSAMPIMAGE input_buf)
313 {
314   my_diff_ptr diff = (my_diff_ptr)cinfo->coef;
315   int ci, compi;
316   _JSAMPARRAY buffer[MAX_COMPS_IN_SCAN];
317   jpeg_component_info *compptr;
318
319   /* Align the virtual buffers for the components used in this scan.
320    * NB: during first pass, this is safe only because the buffers will
321    * already be aligned properly, so jmemmgr.c won't need to do any I/O.
322    */
323   for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
324     compptr = cinfo->cur_comp_info[ci];
325     compi = compptr->component_index;
326     buffer[compi] = (_JSAMPARRAY)(*cinfo->mem->access_virt_sarray)
327       ((j_common_ptr)cinfo, diff->whole_image[compi],
328        diff->iMCU_row_num * compptr->v_samp_factor,
329        (JDIMENSION)compptr->v_samp_factor, FALSE);
330   }
331
332   return compress_data(cinfo, buffer);
333 }
334
335 #endif /* FULL_SAMP_BUFFER_SUPPORTED */
336
337
338 /*
339  * Initialize difference buffer controller.
340  */
341
342 GLOBAL(void)
343 _jinit_c_diff_controller(j_compress_ptr cinfo, boolean need_full_buffer)
344 {
345   my_diff_ptr diff;
346   int ci, row;
347   jpeg_component_info *compptr;
348
349   diff = (my_diff_ptr)
350     (*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
351                                 sizeof(my_diff_controller));
352   cinfo->coef = (struct jpeg_c_coef_controller *)diff;
353   diff->pub.start_pass = start_pass_diff;
354
355   /* Create the prediction row buffers. */
356   for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
357        ci++, compptr++) {
358     diff->cur_row[ci] = *(_JSAMPARRAY)(*cinfo->mem->alloc_sarray)
359       ((j_common_ptr)cinfo, JPOOL_IMAGE,
360        (JDIMENSION)jround_up((long)compptr->width_in_blocks,
361                              (long)compptr->h_samp_factor),
362        (JDIMENSION)1);
363     diff->prev_row[ci] = *(_JSAMPARRAY)(*cinfo->mem->alloc_sarray)
364       ((j_common_ptr)cinfo, JPOOL_IMAGE,
365        (JDIMENSION)jround_up((long)compptr->width_in_blocks,
366                              (long)compptr->h_samp_factor),
367        (JDIMENSION)1);
368   }
369
370   /* Create the difference buffer. */
371   for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
372        ci++, compptr++) {
373     diff->diff_buf[ci] =
374       ALLOC_DARRAY(JPOOL_IMAGE,
375                    (JDIMENSION)jround_up((long)compptr->width_in_blocks,
376                                          (long)compptr->h_samp_factor),
377                    (JDIMENSION)compptr->v_samp_factor);
378     /* Prefill difference rows with zeros.  We do this because only actual
379      * data is placed in the buffers during prediction/differencing, leaving
380      * any dummy differences at the right edge as zeros, which will encode
381      * to the smallest amount of data.
382      */
383     for (row = 0; row < compptr->v_samp_factor; row++)
384       memset(diff->diff_buf[ci][row], 0,
385              jround_up((long)compptr->width_in_blocks,
386                        (long)compptr->h_samp_factor) * sizeof(JDIFF));
387   }
388
389   /* Create the sample buffer. */
390   if (need_full_buffer) {
391 #ifdef FULL_SAMP_BUFFER_SUPPORTED
392     /* Allocate a full-image virtual array for each component, */
393     /* padded to a multiple of samp_factor differences in each direction. */
394     for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
395          ci++, compptr++) {
396       diff->whole_image[ci] = (*cinfo->mem->request_virt_sarray)
397         ((j_common_ptr)cinfo, JPOOL_IMAGE, FALSE,
398          (JDIMENSION)jround_up((long)compptr->width_in_blocks,
399                                (long)compptr->h_samp_factor),
400          (JDIMENSION)jround_up((long)compptr->height_in_blocks,
401                                (long)compptr->v_samp_factor),
402          (JDIMENSION)compptr->v_samp_factor);
403     }
404 #else
405     ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
406 #endif
407   } else
408     diff->whole_image[0] = NULL; /* flag for no virtual arrays */
409 }
410
411 #endif /* C_LOSSLESS_SUPPORTED */