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:
5
cjpeg.c
5
cjpeg.c
@@ -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 */
|
||||||
}
|
}
|
||||||
|
|||||||
130
jccoefct.c
130
jccoefct.c
@@ -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);
|
||||||
|
|||||||
157
jcdctmgr.c
157
jcdctmgr.c
@@ -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.
|
||||||
|
|||||||
6
jchuff.h
6
jchuff.h
@@ -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));
|
||||||
|
|||||||
22
jcmaster.c
22
jcmaster.c
@@ -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;
|
||||||
|
|||||||
14
jcparam.c
14
jcparam.c
@@ -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);
|
||||||
|
|||||||
@@ -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 */
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user