Initial implementation of trellis quantization

A new pass type trellis_pass is added. It defines a pass where trellis
quantization is done in the quantize_trellis() function.
Trellis quantization can be enabled by setting use_moz_defaults to 2 or
by using the -trellis option in cjpeg
Note that trellis does currently not work with scan optimization. Scan
optimization is disabled when trellis is enabled.
This commit is contained in:
Frank Bossen
2014-03-23 21:06:01 +01:00
parent febf3466d4
commit d200b2c144
8 changed files with 331 additions and 17 deletions

View File

@@ -446,6 +446,11 @@ parse_switches (j_compress_ptr cinfo, int argc, char **argv,
/* Input file is Targa format. */ /* Input file is Targa format. */
is_targa = TRUE; is_targa = TRUE;
} else if (keymatch(arg, "trellis", 1)) {
/* enable trellis quantization */
cinfo->use_moz_defaults = 2;
jpeg_set_defaults(cinfo);
} else { } else {
usage(); /* bogus switch */ usage(); /* bogus switch */
} }

View File

@@ -2,6 +2,8 @@
* jccoefct.c * jccoefct.c
* *
* Copyright (C) 1994-1997, Thomas G. Lane. * Copyright (C) 1994-1997, Thomas G. Lane.
* mozjpeg Modifications:
* Copyright (C) 2014, Mozilla Corporation.
* This file is part of the Independent JPEG Group's software. * This file is part of the Independent JPEG Group's software.
* For conditions of distribution and use, see the accompanying README file. * For conditions of distribution and use, see the accompanying README file.
* *
@@ -13,7 +15,7 @@
#define JPEG_INTERNALS #define JPEG_INTERNALS
#include "jinclude.h" #include "jinclude.h"
#include "jpeglib.h" #include "jpeglib.h"
#include "jchuff.h"
/* We use a full-image coefficient buffer when doing Huffman optimization, /* We use a full-image coefficient buffer when doing Huffman optimization,
* and also for writing multiple-scan JPEG files. In all cases, the DCT * and also for writing multiple-scan JPEG files. In all cases, the DCT
@@ -52,6 +54,10 @@ typedef struct {
/* In multi-pass modes, we need a virtual block array for each component. */ /* In multi-pass modes, we need a virtual block array for each component. */
jvirt_barray_ptr whole_image[MAX_COMPONENTS]; jvirt_barray_ptr whole_image[MAX_COMPONENTS];
/* when using trellis quantization, need to keep a copy of all unquantized coefficients */
jvirt_barray_ptr whole_image_uq[MAX_COMPONENTS];
} my_coef_controller; } my_coef_controller;
typedef my_coef_controller * my_coef_ptr; typedef my_coef_controller * my_coef_ptr;
@@ -66,6 +72,8 @@ METHODDEF(boolean) compress_first_pass
METHODDEF(boolean) compress_output METHODDEF(boolean) compress_output
JPP((j_compress_ptr cinfo, JSAMPIMAGE input_buf)); JPP((j_compress_ptr cinfo, JSAMPIMAGE input_buf));
#endif #endif
METHODDEF(boolean) compress_trellis_pass
JPP((j_compress_ptr cinfo, JSAMPIMAGE input_buf));
LOCAL(void) LOCAL(void)
@@ -122,6 +130,12 @@ start_pass_coef (j_compress_ptr cinfo, J_BUF_MODE pass_mode)
coef->pub.compress_data = compress_output; coef->pub.compress_data = compress_output;
break; break;
#endif #endif
case JBUF_REQUANT:
if (coef->whole_image[0] == NULL)
ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
coef->pub.compress_data = compress_trellis_pass;
break;
default: default:
ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
break; break;
@@ -177,7 +191,7 @@ compress_data (j_compress_ptr cinfo, JSAMPIMAGE input_buf)
(*cinfo->fdct->forward_DCT) (cinfo, compptr, (*cinfo->fdct->forward_DCT) (cinfo, compptr,
input_buf[compptr->component_index], input_buf[compptr->component_index],
coef->MCU_buffer[blkn], coef->MCU_buffer[blkn],
ypos, xpos, (JDIMENSION) blockcnt); ypos, xpos, (JDIMENSION) blockcnt, NULL);
if (blockcnt < compptr->MCU_width) { if (blockcnt < compptr->MCU_width) {
/* Create some dummy blocks at the right edge of the image. */ /* Create some dummy blocks at the right edge of the image. */
jzero_far((void FAR *) coef->MCU_buffer[blkn + blockcnt], jzero_far((void FAR *) coef->MCU_buffer[blkn + blockcnt],
@@ -252,6 +266,7 @@ compress_first_pass (j_compress_ptr cinfo, JSAMPIMAGE input_buf)
jpeg_component_info *compptr; jpeg_component_info *compptr;
JBLOCKARRAY buffer; JBLOCKARRAY buffer;
JBLOCKROW thisblockrow, lastblockrow; JBLOCKROW thisblockrow, lastblockrow;
JBLOCKARRAY buffer_dst;
for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
ci++, compptr++) { ci++, compptr++) {
@@ -260,6 +275,12 @@ compress_first_pass (j_compress_ptr cinfo, JSAMPIMAGE input_buf)
((j_common_ptr) cinfo, coef->whole_image[ci], ((j_common_ptr) cinfo, coef->whole_image[ci],
coef->iMCU_row_num * compptr->v_samp_factor, coef->iMCU_row_num * compptr->v_samp_factor,
(JDIMENSION) compptr->v_samp_factor, TRUE); (JDIMENSION) compptr->v_samp_factor, TRUE);
buffer_dst = (*cinfo->mem->access_virt_barray)
((j_common_ptr) cinfo, coef->whole_image_uq[ci],
coef->iMCU_row_num * compptr->v_samp_factor,
(JDIMENSION) compptr->v_samp_factor, TRUE);
/* Count non-dummy DCT block rows in this iMCU row. */ /* Count non-dummy DCT block rows in this iMCU row. */
if (coef->iMCU_row_num < last_iMCU_row) if (coef->iMCU_row_num < last_iMCU_row)
block_rows = compptr->v_samp_factor; block_rows = compptr->v_samp_factor;
@@ -282,7 +303,7 @@ compress_first_pass (j_compress_ptr cinfo, JSAMPIMAGE input_buf)
(*cinfo->fdct->forward_DCT) (cinfo, compptr, (*cinfo->fdct->forward_DCT) (cinfo, compptr,
input_buf[ci], thisblockrow, input_buf[ci], thisblockrow,
(JDIMENSION) (block_row * DCTSIZE), (JDIMENSION) (block_row * DCTSIZE),
(JDIMENSION) 0, blocks_across); (JDIMENSION) 0, blocks_across, buffer_dst[block_row]);
if (ndummy > 0) { if (ndummy > 0) {
/* Create dummy blocks at the right edge of the image. */ /* Create dummy blocks at the right edge of the image. */
thisblockrow += blocks_across; /* => first dummy block */ thisblockrow += blocks_across; /* => first dummy block */
@@ -326,6 +347,100 @@ compress_first_pass (j_compress_ptr cinfo, JSAMPIMAGE input_buf)
return compress_output(cinfo, input_buf); return compress_output(cinfo, input_buf);
} }
METHODDEF(boolean)
compress_trellis_pass (j_compress_ptr cinfo, JSAMPIMAGE input_buf)
{
my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1;
JDIMENSION blocks_across, MCUs_across, MCUindex;
int bi, ci, h_samp_factor, block_row, block_rows, ndummy;
JCOEF lastDC;
jpeg_component_info *compptr;
JBLOCKARRAY buffer;
JBLOCKROW thisblockrow, lastblockrow;
JBLOCKARRAY buffer_dst;
for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
ci++, compptr++) {
c_derived_tbl actbl_data;
c_derived_tbl *actbl = &actbl_data;
jpeg_make_c_derived_tbl(cinfo, FALSE, cinfo->comp_info[ci].ac_tbl_no, &actbl);
/* Align the virtual buffer for this component. */
buffer = (*cinfo->mem->access_virt_barray)
((j_common_ptr) cinfo, coef->whole_image[ci],
coef->iMCU_row_num * compptr->v_samp_factor,
(JDIMENSION) compptr->v_samp_factor, TRUE);
buffer_dst = (*cinfo->mem->access_virt_barray)
((j_common_ptr) cinfo, coef->whole_image_uq[ci],
coef->iMCU_row_num * compptr->v_samp_factor,
(JDIMENSION) compptr->v_samp_factor, TRUE);
/* Count non-dummy DCT block rows in this iMCU row. */
if (coef->iMCU_row_num < last_iMCU_row)
block_rows = compptr->v_samp_factor;
else {
/* NB: can't use last_row_height here, since may not be set! */
block_rows = (int) (compptr->height_in_blocks % compptr->v_samp_factor);
if (block_rows == 0) block_rows = compptr->v_samp_factor;
}
blocks_across = compptr->width_in_blocks;
h_samp_factor = compptr->h_samp_factor;
/* Count number of dummy blocks to be added at the right margin. */
ndummy = (int) (blocks_across % h_samp_factor);
if (ndummy > 0)
ndummy = h_samp_factor - ndummy;
/* Perform DCT for all non-dummy blocks in this iMCU row. Each call
* on forward_DCT processes a complete horizontal row of DCT blocks.
*/
for (block_row = 0; block_row < block_rows; block_row++) {
thisblockrow = buffer[block_row];
quantize_trellis(cinfo, actbl, thisblockrow, buffer_dst[block_row], blocks_across, cinfo->quant_tbl_ptrs[cinfo->comp_info[ci].quant_tbl_no]);
if (ndummy > 0) {
/* Create dummy blocks at the right edge of the image. */
thisblockrow += blocks_across; /* => first dummy block */
jzero_far((void FAR *) thisblockrow, ndummy * SIZEOF(JBLOCK));
lastDC = thisblockrow[-1][0];
for (bi = 0; bi < ndummy; bi++) {
thisblockrow[bi][0] = lastDC;
}
}
}
/* If at end of image, create dummy block rows as needed.
* The tricky part here is that within each MCU, we want the DC values
* of the dummy blocks to match the last real block's DC value.
* This squeezes a few more bytes out of the resulting file...
*/
if (coef->iMCU_row_num == last_iMCU_row) {
blocks_across += ndummy; /* include lower right corner */
MCUs_across = blocks_across / h_samp_factor;
for (block_row = block_rows; block_row < compptr->v_samp_factor;
block_row++) {
thisblockrow = buffer[block_row];
lastblockrow = buffer[block_row-1];
jzero_far((void FAR *) thisblockrow,
(size_t) (blocks_across * SIZEOF(JBLOCK)));
for (MCUindex = 0; MCUindex < MCUs_across; MCUindex++) {
lastDC = lastblockrow[h_samp_factor-1][0];
for (bi = 0; bi < h_samp_factor; bi++) {
thisblockrow[bi][0] = lastDC;
}
thisblockrow += h_samp_factor; /* advance to next MCU in row */
lastblockrow += h_samp_factor;
}
}
}
}
/* NB: compress_output will increment iMCU_row_num if successful.
* A suspension return will result in redoing all the work above next time.
*/
/* Emit data to the entropy encoder, sharing code with subsequent passes */
return compress_output(cinfo, input_buf);
}
/* /*
* Process some data in subsequent passes of a multi-pass case. * Process some data in subsequent passes of a multi-pass case.
@@ -377,6 +492,7 @@ compress_output (j_compress_ptr cinfo, JSAMPIMAGE input_buf)
} }
} }
} }
/* Try to write the MCU. */ /* Try to write the MCU. */
if (! (*cinfo->entropy->encode_mcu) (cinfo, coef->MCU_buffer)) { if (! (*cinfo->entropy->encode_mcu) (cinfo, coef->MCU_buffer)) {
/* Suspension forced; update state counters and exit */ /* Suspension forced; update state counters and exit */
@@ -429,6 +545,14 @@ jinit_c_coef_controller (j_compress_ptr cinfo, boolean need_full_buffer)
(JDIMENSION) jround_up((long) compptr->height_in_blocks, (JDIMENSION) jround_up((long) compptr->height_in_blocks,
(long) compptr->v_samp_factor), (long) compptr->v_samp_factor),
(JDIMENSION) compptr->v_samp_factor); (JDIMENSION) compptr->v_samp_factor);
coef->whole_image_uq[ci] = (*cinfo->mem->request_virt_barray)
((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE,
(JDIMENSION) jround_up((long) compptr->width_in_blocks,
(long) compptr->h_samp_factor),
(JDIMENSION) jround_up((long) compptr->height_in_blocks,
(long) compptr->v_samp_factor),
(JDIMENSION) compptr->v_samp_factor);
} }
#else #else
ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);

View File

@@ -7,6 +7,8 @@
* Copyright (C) 1999-2006, MIYASAKA Masaru. * Copyright (C) 1999-2006, MIYASAKA Masaru.
* Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB * Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
* Copyright (C) 2011 D. R. Commander * Copyright (C) 2011 D. R. Commander
* mozjpeg Modifications:
* Copyright (C) 2014, Mozilla Corporation.
* For conditions of distribution and use, see the accompanying README file. * For conditions of distribution and use, see the accompanying README file.
* *
* This file contains the forward-DCT management logic. * This file contains the forward-DCT management logic.
@@ -20,7 +22,8 @@
#include "jpeglib.h" #include "jpeglib.h"
#include "jdct.h" /* Private declarations for DCT subsystem */ #include "jdct.h" /* Private declarations for DCT subsystem */
#include "jsimddct.h" #include "jsimddct.h"
#include <assert.h>
#include <math.h>
/* Private subobject for this module */ /* Private subobject for this module */
@@ -412,7 +415,7 @@ METHODDEF(void)
forward_DCT (j_compress_ptr cinfo, jpeg_component_info * compptr, forward_DCT (j_compress_ptr cinfo, jpeg_component_info * compptr,
JSAMPARRAY sample_data, JBLOCKROW coef_blocks, JSAMPARRAY sample_data, JBLOCKROW coef_blocks,
JDIMENSION start_row, JDIMENSION start_col, JDIMENSION start_row, JDIMENSION start_col,
JDIMENSION num_blocks) JDIMENSION num_blocks, JBLOCKROW dst)
/* This version is used for integer DCT implementations. */ /* This version is used for integer DCT implementations. */
{ {
/* This routine is heavily used, so it's worth coding it tightly. */ /* This routine is heavily used, so it's worth coding it tightly. */
@@ -436,6 +439,16 @@ forward_DCT (j_compress_ptr cinfo, jpeg_component_info * compptr,
/* Perform the DCT */ /* Perform the DCT */
(*do_dct) (workspace); (*do_dct) (workspace);
/* Save unquantized transform coefficients for later trellis quantization */
if (dst) {
int i;
for (i = 0; i < DCTSIZE2; i++) {
dst[bi][i] = workspace[i];
//printf("d%d ", workspace[i]);
}
//printf("\n");
}
/* Quantize/descale the coefficients, and store into coef_blocks[] */ /* Quantize/descale the coefficients, and store into coef_blocks[] */
(*do_quantize) (coef_blocks[bi], divisors, workspace); (*do_quantize) (coef_blocks[bi], divisors, workspace);
} }
@@ -502,7 +515,7 @@ METHODDEF(void)
forward_DCT_float (j_compress_ptr cinfo, jpeg_component_info * compptr, forward_DCT_float (j_compress_ptr cinfo, jpeg_component_info * compptr,
JSAMPARRAY sample_data, JBLOCKROW coef_blocks, JSAMPARRAY sample_data, JBLOCKROW coef_blocks,
JDIMENSION start_row, JDIMENSION start_col, JDIMENSION start_row, JDIMENSION start_col,
JDIMENSION num_blocks) JDIMENSION num_blocks, JBLOCKROW dst)
/* This version is used for floating-point DCT implementations. */ /* This version is used for floating-point DCT implementations. */
{ {
/* This routine is heavily used, so it's worth coding it tightly. */ /* This routine is heavily used, so it's worth coding it tightly. */
@@ -534,6 +547,144 @@ forward_DCT_float (j_compress_ptr cinfo, jpeg_component_info * compptr,
#endif /* DCT_FLOAT_SUPPORTED */ #endif /* DCT_FLOAT_SUPPORTED */
#include "jchuff.h"
static unsigned char jpeg_nbits_table[65536];
static int jpeg_nbits_table_init = 0;
GLOBAL(void)
quantize_trellis(j_compress_ptr cinfo, c_derived_tbl *actbl, JBLOCKROW coef_blocks, JBLOCKROW src, JDIMENSION num_blocks,
JQUANT_TBL * qtbl)
{
int i, j, k;
float accumulated_zero_dist[DCTSIZE2];
float accumulated_cost[DCTSIZE2];
int run_start[DCTSIZE2];
int bi;
float best_cost;
int last_coeff_idx; // position of last nonzero coefficient
float norm = 0.0;
float lambda_base;
float lambda;
if(!jpeg_nbits_table_init) {
for(i = 0; i < 65536; i++) {
int nbits = 0, temp = i;
while (temp) {temp >>= 1; nbits++;}
jpeg_nbits_table[i] = nbits;
}
jpeg_nbits_table_init = 1;
}
norm = 0.0;
for (i = 1; i < DCTSIZE2; i++) {
norm += qtbl->quantval[i] * qtbl->quantval[i];
}
norm /= 63.0;
lambda_base = 1.0 / norm;
for (bi = 0; bi < num_blocks; bi++) {
norm = 0.0;
for (i = 1; i < DCTSIZE2; i++) {
norm += src[bi][i] * src[bi][i];
}
norm /= 63.0;
lambda = pow(2.0, cinfo->lambda_log_scale1) * lambda_base / (pow(2.0, cinfo->lambda_log_scale2) + norm);
//lambda = pow(2.0, cinfo->lambda_log_scale1-12) * lambda_base;
accumulated_zero_dist[0] = 0.0;
accumulated_cost[0] = 0.0;
for (i = 1; i < DCTSIZE2; i++) {
int z = jpeg_natural_order[i];
int sign = src[bi][z] >> 31;
int x = abs(src[bi][z]);
int q = 8 * qtbl->quantval[z];
int candidate[16];
int candidate_bits[16];
float candidate_dist[16];
int num_candidates;
int qval;
accumulated_zero_dist[i] = x * x * lambda + accumulated_zero_dist[i-1];
qval = (x + q/2) / q; // quantized value (round nearest)
if (qval == 0) {
coef_blocks[bi][z] = 0;
accumulated_cost[i] = 1e38; // Shouldn't be needed
continue;
}
num_candidates = jpeg_nbits_table[qval];
for (k = 0; k < num_candidates; k++) {
int delta;
candidate[k] = (k < num_candidates - 1) ? (2 << k) - 1 : qval;
delta = candidate[k] * q - x;
candidate_bits[k] = k+1;
candidate_dist[k] = delta * delta * lambda;
}
accumulated_cost[i] = 1e38;
for (j = 0; j < i; j++) {
int zz = jpeg_natural_order[j];
if (j != 0 && coef_blocks[bi][zz] == 0)
continue;
int zero_run = i - 1 - j;
int run_bits = (zero_run >> 4) * actbl->ehufsi[0xf0];
zero_run &= 15;
for (k = 0; k < num_candidates; k++) {
int rate = actbl->ehufsi[16 * zero_run + candidate_bits[k]] + candidate_bits[k] + run_bits;
float cost = rate + candidate_dist[k];
cost += accumulated_zero_dist[i-1] - accumulated_zero_dist[j] + accumulated_cost[j];
if (cost < accumulated_cost[i]) {
coef_blocks[bi][z] = (candidate[k] ^ sign) - sign;
accumulated_cost[i] = cost;
run_start[i] = j;
}
}
}
}
last_coeff_idx = 0;
best_cost = accumulated_zero_dist[DCTSIZE2-1] + actbl->ehufsi[0];
for (i = 1; i < DCTSIZE2; i++) {
int z = jpeg_natural_order[i];
if (coef_blocks[bi][z] != 0) {
float cost = accumulated_cost[i] + accumulated_zero_dist[DCTSIZE2-1] - accumulated_zero_dist[i];
if (i < DCTSIZE2-1)
cost += actbl->ehufsi[0];
if (cost < best_cost) {
best_cost = cost;
last_coeff_idx = i;
}
}
}
// Zero out coefficients that are part of runs
i = DCTSIZE2 - 1;
while (i > 0)
{
while (i > last_coeff_idx) {
int z = jpeg_natural_order[i];
coef_blocks[bi][z] = 0;
i--;
}
last_coeff_idx = run_start[i];
i--;
}
}
}
/* /*
* Initialize FDCT manager. * Initialize FDCT manager.

View File

@@ -2,6 +2,8 @@
* jchuff.h * jchuff.h
* *
* Copyright (C) 1991-1997, Thomas G. Lane. * Copyright (C) 1991-1997, Thomas G. Lane.
* mozjpeg Modifications:
* Copyright (C) 2014, Mozilla Corporation.
* This file is part of the Independent JPEG Group's software. * This file is part of the Independent JPEG Group's software.
* For conditions of distribution and use, see the accompanying README file. * For conditions of distribution and use, see the accompanying README file.
* *
@@ -45,3 +47,7 @@ EXTERN(void) jpeg_make_c_derived_tbl
/* Generate an optimal table definition given the specified counts */ /* Generate an optimal table definition given the specified counts */
EXTERN(void) jpeg_gen_optimal_table EXTERN(void) jpeg_gen_optimal_table
JPP((j_compress_ptr cinfo, JHUFF_TBL * htbl, long freq[])); JPP((j_compress_ptr cinfo, JHUFF_TBL * htbl, long freq[]));
EXTERN(void) quantize_trellis
JPP((j_compress_ptr cinfo, c_derived_tbl *actbl, JBLOCKROW coef_blocks, JBLOCKROW src, JDIMENSION num_blocks,
JQUANT_TBL * qtbl));

View File

@@ -27,7 +27,8 @@
typedef enum { typedef enum {
main_pass, /* input data, also do first output step */ main_pass, /* input data, also do first output step */
huff_opt_pass, /* Huffman code optimization pass */ huff_opt_pass, /* Huffman code optimization pass */
output_pass /* data output pass */ output_pass, /* data output pass */
trellis_pass /* trellis quantization pass */
} c_pass_type; } c_pass_type;
typedef struct { typedef struct {
@@ -534,6 +535,12 @@ prepare_for_pass (j_compress_ptr cinfo)
(*cinfo->marker->write_scan_header) (cinfo); (*cinfo->marker->write_scan_header) (cinfo);
master->pub.call_pass_startup = FALSE; master->pub.call_pass_startup = FALSE;
break; break;
case trellis_pass:
(*cinfo->entropy->start_pass) (cinfo, TRUE);
(*cinfo->coef->start_pass) (cinfo, JBUF_REQUANT);
master->pub.call_pass_startup = FALSE;
break;
default: default:
ERREXIT(cinfo, JERR_NOT_COMPILED); ERREXIT(cinfo, JERR_NOT_COMPILED);
} }
@@ -596,7 +603,6 @@ select_scans (j_compress_ptr cinfo, int next_scan_number)
{ {
my_master_ptr master = (my_master_ptr) cinfo->master; my_master_ptr master = (my_master_ptr) cinfo->master;
unsigned long size[8];
int base_scan_idx; int base_scan_idx;
int luma_freq_split_scan_start = cinfo->num_scans_luma_dc + 3 * cinfo->Al_max_luma + 2; int luma_freq_split_scan_start = cinfo->num_scans_luma_dc + 3 * cinfo->Al_max_luma + 2;
int chroma_freq_split_scan_start = cinfo->num_scans_luma+cinfo->num_scans_chroma_dc+(6*cinfo->Al_max_chroma+4); int chroma_freq_split_scan_start = cinfo->num_scans_luma+cinfo->num_scans_chroma_dc+(6*cinfo->Al_max_chroma+4);
@@ -792,7 +798,10 @@ finish_pass_master (j_compress_ptr cinfo)
/* next pass is either output of scan 0 (after optimization) /* next pass is either output of scan 0 (after optimization)
* or output of scan 1 (if no optimization). * or output of scan 1 (if no optimization).
*/ */
master->pass_type = output_pass; if (cinfo->trellis_quant)
master->pass_type = trellis_pass;
else
master->pass_type = output_pass;
if (! cinfo->optimize_coding) if (! cinfo->optimize_coding)
master->scan_number++; master->scan_number++;
break; break;
@@ -812,6 +821,9 @@ finish_pass_master (j_compress_ptr cinfo)
master->scan_number++; master->scan_number++;
break; break;
case trellis_pass:
master->pass_type = output_pass;
break;
} }
master->pass_number++; master->pass_number++;
@@ -866,7 +878,9 @@ jinit_c_master_control (j_compress_ptr cinfo, boolean transcode_only)
} }
master->scan_number = 0; master->scan_number = 0;
master->pass_number = 0; master->pass_number = 0;
if (cinfo->optimize_coding) if (cinfo->trellis_quant)
master->total_passes = 3; // Don't support multiple scans for now
else if (cinfo->optimize_coding)
master->total_passes = cinfo->num_scans * 2; master->total_passes = cinfo->num_scans * 2;
else else
master->total_passes = cinfo->num_scans; master->total_passes = cinfo->num_scans;

View File

@@ -325,6 +325,8 @@ jpeg_set_defaults (j_compress_ptr cinfo)
} }
#ifdef C_PROGRESSIVE_SUPPORTED #ifdef C_PROGRESSIVE_SUPPORTED
cinfo->scan_info = NULL;
cinfo->num_scans = 0;
if (!cinfo->use_moz_defaults) { if (!cinfo->use_moz_defaults) {
/* Default is no multiple-scan output */ /* Default is no multiple-scan output */
cinfo->scan_info = NULL; cinfo->scan_info = NULL;
@@ -400,12 +402,16 @@ jpeg_set_defaults (j_compress_ptr cinfo)
jpeg_default_colorspace(cinfo); jpeg_default_colorspace(cinfo);
#ifdef C_PROGRESSIVE_SUPPORTED #ifdef C_PROGRESSIVE_SUPPORTED
if (cinfo->use_moz_defaults) { if (cinfo->use_moz_defaults == 1) { // Disable this while working on trellis
cinfo->optimize_scans = TRUE; cinfo->optimize_scans = TRUE;
jpeg_simple_progression(cinfo); jpeg_simple_progression(cinfo);
} else } else
cinfo->optimize_scans = FALSE; cinfo->optimize_scans = FALSE;
#endif #endif
cinfo->trellis_quant = (cinfo->use_moz_defaults == 2) ? TRUE : FALSE;
cinfo->lambda_log_scale1 = 17.0;
cinfo->lambda_log_scale2 = 15.0;
} }
@@ -760,7 +766,7 @@ jpeg_simple_progression (j_compress_ptr cinfo)
nscans = 10; nscans = 10;
} else { } else {
/* All-purpose script for other color spaces. */ /* All-purpose script for other color spaces. */
if (cinfo->use_moz_defaults) { if (cinfo->use_moz_defaults == TRUE) {
if (ncomps > MAX_COMPS_IN_SCAN) if (ncomps > MAX_COMPS_IN_SCAN)
nscans = 5 * ncomps; /* 2 DC + 4 AC scans per component */ nscans = 5 * ncomps; /* 2 DC + 4 AC scans per component */
else else
@@ -792,7 +798,7 @@ jpeg_simple_progression (j_compress_ptr cinfo)
if (ncomps == 3 && cinfo->jpeg_color_space == JCS_YCbCr) { if (ncomps == 3 && cinfo->jpeg_color_space == JCS_YCbCr) {
/* Custom script for YCbCr color images. */ /* Custom script for YCbCr color images. */
if (cinfo->use_moz_defaults) { if (cinfo->use_moz_defaults == TRUE) {
/* scan defined in jpeg_scan_rgb.txt in jpgcrush */ /* scan defined in jpeg_scan_rgb.txt in jpgcrush */
/* Initial DC scan */ /* Initial DC scan */
scanptr = fill_dc_scans(scanptr, 1, 0, 0); scanptr = fill_dc_scans(scanptr, 1, 0, 0);
@@ -831,7 +837,7 @@ jpeg_simple_progression (j_compress_ptr cinfo)
} }
} else { } else {
/* All-purpose script for other color spaces. */ /* All-purpose script for other color spaces. */
if (cinfo->use_moz_defaults) { if (cinfo->use_moz_defaults == TRUE) {
/* scan defined in jpeg_scan_bw.txt in jpgcrush */ /* scan defined in jpeg_scan_bw.txt in jpgcrush */
/* DC component, no successive approximation */ /* DC component, no successive approximation */
scanptr = fill_dc_scans(scanptr, ncomps, 0, 0); scanptr = fill_dc_scans(scanptr, ncomps, 0, 0);

View File

@@ -3,6 +3,8 @@
* *
* Copyright (C) 1991-1997, Thomas G. Lane. * Copyright (C) 1991-1997, Thomas G. Lane.
* Modified 1997-2009 by Guido Vollbeding. * Modified 1997-2009 by Guido Vollbeding.
* mozjpeg Modifications:
* Copyright (C) 2014, Mozilla Corporation.
* This file is part of the Independent JPEG Group's software. * This file is part of the Independent JPEG Group's software.
* For conditions of distribution and use, see the accompanying README file. * For conditions of distribution and use, see the accompanying README file.
* *
@@ -19,7 +21,9 @@ typedef enum { /* Operating modes for buffer controllers */
/* Remaining modes require a full-image buffer to have been created */ /* Remaining modes require a full-image buffer to have been created */
JBUF_SAVE_SOURCE, /* Run source subobject only, save output */ JBUF_SAVE_SOURCE, /* Run source subobject only, save output */
JBUF_CRANK_DEST, /* Run dest subobject only, using saved data */ JBUF_CRANK_DEST, /* Run dest subobject only, using saved data */
JBUF_SAVE_AND_PASS /* Run both subobjects, save output */ JBUF_SAVE_AND_PASS, /* Run both subobjects, save output */
JBUF_REQUANT /* Requantize */
} J_BUF_MODE; } J_BUF_MODE;
/* Values of global_state field (jdapi.c has some dependencies on ordering!) */ /* Values of global_state field (jdapi.c has some dependencies on ordering!) */
@@ -107,7 +111,7 @@ struct jpeg_forward_dct {
jpeg_component_info * compptr, jpeg_component_info * compptr,
JSAMPARRAY sample_data, JBLOCKROW coef_blocks, JSAMPARRAY sample_data, JBLOCKROW coef_blocks,
JDIMENSION start_row, JDIMENSION start_col, JDIMENSION start_row, JDIMENSION start_col,
JDIMENSION num_blocks)); JDIMENSION num_blocks, JBLOCKROW dst));
}; };
/* Entropy encoding */ /* Entropy encoding */

View File

@@ -376,8 +376,9 @@ struct jpeg_compress_struct {
int smoothing_factor; /* 1..100, or 0 for no input smoothing */ int smoothing_factor; /* 1..100, or 0 for no input smoothing */
J_DCT_METHOD dct_method; /* DCT algorithm selector */ J_DCT_METHOD dct_method; /* DCT algorithm selector */
boolean use_moz_defaults; /* TRUE if using Mozilla defaults */ int use_moz_defaults; /* nonzero if using Mozilla defaults, 1=crush, 2=trellis */
boolean optimize_scans; /* TRUE=optimize progressive coding scans */ boolean optimize_scans; /* TRUE=optimize progressive coding scans */
boolean trellis_quant; /* TRUE=use trellis quantization */
int num_scans_luma; /* # of entries in scan_info array pertaining to luma (used when optimize_scans is TRUE */ int num_scans_luma; /* # of entries in scan_info array pertaining to luma (used when optimize_scans is TRUE */
int num_scans_luma_dc; int num_scans_luma_dc;
@@ -387,6 +388,9 @@ struct jpeg_compress_struct {
int Al_max_luma; /* maximum value of Al tested when optimizing scans (luma) */ int Al_max_luma; /* maximum value of Al tested when optimizing scans (luma) */
int Al_max_chroma; /* maximum value of Al tested when optimizing scans (chroma) */ int Al_max_chroma; /* maximum value of Al tested when optimizing scans (chroma) */
float lambda_log_scale1;
float lambda_log_scale2;
/* The restart interval can be specified in absolute MCUs by setting /* The restart interval can be specified in absolute MCUs by setting
* restart_interval, or in MCU rows by setting restart_in_rows * restart_interval, or in MCU rows by setting restart_in_rows
* (in which case the correct restart_interval will be figured * (in which case the correct restart_interval will be figured