Skip to content

Commit

Permalink
Partial fix for mozilla#138
Browse files Browse the repository at this point in the history
Initial implementation of trellis quantization for arithmetic coding.
The rate computation does not yet implement all rules of the entropy
coder and may thus be suboptimal.
  • Loading branch information
fbossen committed Dec 21, 2014
1 parent 9d8efde commit 4802ddd
Show file tree
Hide file tree
Showing 6 changed files with 450 additions and 19 deletions.
3 changes: 0 additions & 3 deletions cjpeg.c
Original file line number Diff line number Diff line change
Expand Up @@ -292,9 +292,6 @@ parse_switches (j_compress_ptr cinfo, int argc, char **argv,

/* No table optimization required for AC */
cinfo->optimize_coding = FALSE;

/* Trellis quantization currently incompatible with AC */
jpeg_c_set_bool_param(cinfo, JBOOLEAN_TRELLIS_QUANT, FALSE);
#else
fprintf(stderr, "%s: sorry, arithmetic coding not supported\n",
progname);
Expand Down
45 changes: 40 additions & 5 deletions jcarith.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
#define JPEG_INTERNALS
#include "jinclude.h"
#include "jpeglib.h"

#include <math.h>

/* Expanded entropy encoder object for arithmetic encoding. */

Expand Down Expand Up @@ -120,6 +120,10 @@ emit_byte (int val, j_compress_ptr cinfo)
{
struct jpeg_destination_mgr * dest = cinfo->dest;

/* Do not emit bytes during trellis passes */
if (cinfo->master->trellis_passes)
return;

*dest->next_output_byte++ = (JOCTET) val;
if (--dest->free_in_buffer == 0)
if (! (*dest->empty_output_buffer) (cinfo))
Expand Down Expand Up @@ -826,6 +830,7 @@ start_pass (j_compress_ptr cinfo, boolean gather_statistics)
arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy;
int ci, tbl;
jpeg_component_info * compptr;
boolean progressive_mode;

if (gather_statistics)
/* Make sure to avoid that in the master control logic!
Expand All @@ -836,8 +841,12 @@ start_pass (j_compress_ptr cinfo, boolean gather_statistics)

/* We assume jcmaster.c already validated the progressive scan parameters. */

/* Trellis optimization does DC and AC in same pass and without refinement
* so consider progressive mode to be off in such case */
progressive_mode = (cinfo->master->trellis_passes) ? FALSE : cinfo->progressive_mode;

/* Select execution routines */
if (cinfo->progressive_mode) {
if (progressive_mode) {
if (cinfo->Ah == 0) {
if (cinfo->Ss == 0)
entropy->pub.encode_mcu = encode_mcu_DC_first;
Expand All @@ -856,7 +865,7 @@ start_pass (j_compress_ptr cinfo, boolean gather_statistics)
for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
compptr = cinfo->cur_comp_info[ci];
/* DC needs no table for refinement scan */
if (cinfo->progressive_mode == 0 || (cinfo->Ss == 0 && cinfo->Ah == 0)) {
if (progressive_mode == 0 || (cinfo->Ss == 0 && cinfo->Ah == 0)) {
tbl = compptr->dc_tbl_no;
if (tbl < 0 || tbl >= NUM_ARITH_TBLS)
ERREXIT1(cinfo, JERR_NO_ARITH_TABLE, tbl);
Expand All @@ -869,7 +878,7 @@ start_pass (j_compress_ptr cinfo, boolean gather_statistics)
entropy->dc_context[ci] = 0;
}
/* AC needs no table when not present */
if (cinfo->progressive_mode == 0 || cinfo->Se) {
if (progressive_mode == 0 || cinfo->Se) {
tbl = compptr->ac_tbl_no;
if (tbl < 0 || tbl >= NUM_ARITH_TBLS)
ERREXIT1(cinfo, JERR_NO_ARITH_TABLE, tbl);
Expand All @@ -878,7 +887,7 @@ start_pass (j_compress_ptr cinfo, boolean gather_statistics)
((j_common_ptr) cinfo, JPOOL_IMAGE, AC_STAT_BINS);
MEMZERO(entropy->ac_stats[tbl], AC_STAT_BINS);
#ifdef CALCULATE_SPECTRAL_CONDITIONING
if (cinfo->progressive_mode)
if (progressive_mode)
/* Section G.1.3.2: Set appropriate arithmetic conditioning value Kx */
cinfo->arith_ac_K[tbl] = cinfo->Ss + ((8 + cinfo->Se - cinfo->Ss) >> 4);
#endif
Expand Down Expand Up @@ -925,3 +934,29 @@ jinit_arith_encoder (j_compress_ptr cinfo)
/* Initialize index for fixed probability estimation */
entropy->fixed_bin[0] = 113;
}

GLOBAL(void)
jget_arith_rates (j_compress_ptr cinfo, int dc_tbl_no, int ac_tbl_no, arith_rates *r)
{
int i;
arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy;
for (i = 0; i < DC_STAT_BINS; i++) {
int state = entropy->dc_stats[dc_tbl_no][i];
int mps_val = state >> 7;
float prob_lps = (jpeg_aritab[state & 0x7f] >> 16) / 46340.95; /* 32768*sqrt(2) */
float prob_0 = (mps_val) ? prob_lps : 1.0 - prob_lps;
float prob_1 = 1.0 - prob_0;
r->rate_dc[i][0] = -log(prob_0) / log(2.0);
r->rate_dc[i][1] = -log(prob_1) / log(2.0);
}

for (i = 0; i < AC_STAT_BINS; i++) {
int state = entropy->ac_stats[ac_tbl_no][i];
int mps_val = state >> 7;
float prob_lps = (jpeg_aritab[state & 0x7f] >> 16) / 46340.95;
float prob_0 = (mps_val) ? prob_lps : 1.0 - prob_lps;
float prob_1 = 1.0 - prob_0;
r->rate_ac[i][0] = -log(prob_0) / log(2.0);
r->rate_ac[i][1] = -log(prob_1) / log(2.0);
}
}
33 changes: 24 additions & 9 deletions jccoefct.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
#include "jpeglib.h"
#include "jchuff.h"


/* We use a full-image coefficient buffer when doing Huffman optimization,
* and also for writing multiple-scan JPEG files. In all cases, the DCT
* step is run during the first pass, and subsequent passes need only read
Expand Down Expand Up @@ -367,10 +366,18 @@ compress_trellis_pass (j_compress_ptr cinfo, JSAMPIMAGE input_buf)
c_derived_tbl *dctbl = &dctbl_data;
c_derived_tbl actbl_data;
c_derived_tbl *actbl = &actbl_data;

arith_rates arith_r_data;
arith_rates *arith_r = &arith_r_data;

compptr = cinfo->cur_comp_info[ci];

jpeg_make_c_derived_tbl(cinfo, TRUE, compptr->dc_tbl_no, &dctbl);
jpeg_make_c_derived_tbl(cinfo, FALSE, compptr->ac_tbl_no, &actbl);
if (cinfo->arith_code)
jget_arith_rates(cinfo, compptr->dc_tbl_no, compptr->ac_tbl_no, arith_r);
else {
jpeg_make_c_derived_tbl(cinfo, TRUE, compptr->dc_tbl_no, &dctbl);
jpeg_make_c_derived_tbl(cinfo, FALSE, compptr->ac_tbl_no, &actbl);
}

/* Align the virtual buffer for this component. */
buffer = (*cinfo->mem->access_virt_barray)
Expand Down Expand Up @@ -406,12 +413,20 @@ compress_trellis_pass (j_compress_ptr cinfo, JSAMPIMAGE input_buf)
for (block_row = 0; block_row < block_rows; block_row++) {
thisblockrow = buffer[block_row];
lastblockrow = (block_row > 0) ? buffer[block_row-1] : NULL;
quantize_trellis(cinfo, dctbl, actbl, thisblockrow,
buffer_dst[block_row], blocks_across,
cinfo->quant_tbl_ptrs[compptr->quant_tbl_no],
cinfo->master->norm_src[compptr->quant_tbl_no],
cinfo->master->norm_coef[compptr->quant_tbl_no],
&lastDC, lastblockrow, buffer_dst[block_row-1]);
if (cinfo->arith_code)
quantize_trellis_arith(cinfo, arith_r, thisblockrow,
buffer_dst[block_row], blocks_across,
cinfo->quant_tbl_ptrs[compptr->quant_tbl_no],
cinfo->master->norm_src[compptr->quant_tbl_no],
cinfo->master->norm_coef[compptr->quant_tbl_no],
&lastDC, lastblockrow, buffer_dst[block_row-1]);
else
quantize_trellis(cinfo, dctbl, actbl, thisblockrow,
buffer_dst[block_row], blocks_across,
cinfo->quant_tbl_ptrs[compptr->quant_tbl_no],
cinfo->master->norm_src[compptr->quant_tbl_no],
cinfo->master->norm_coef[compptr->quant_tbl_no],
&lastDC, lastblockrow, buffer_dst[block_row-1]);

if (ndummy > 0) {
/* Create dummy blocks at the right edge of the image. */
Expand Down
Loading

0 comments on commit 4802ddd

Please sign in to comment.