Skip to content

Commit

Permalink
use a struct EntropyStats for stats
Browse files Browse the repository at this point in the history
-> freq_xx_[] array will now be allocated from stack instead
   of heap, but they'll be less persistent OTOH.
  • Loading branch information
skal65535 committed May 2, 2024
1 parent fb8c9d3 commit 5064f40
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 27 deletions.
47 changes: 26 additions & 21 deletions src/enc.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1260,30 +1260,34 @@ void Encoder::FinalPassScan(size_t nb_mbs, const DCTCoeffs* coeffs) {
////////////////////////////////////////////////////////////////////////////////
// Huffman tables optimization

void Encoder::ResetEntropyStats() {
memset(freq_ac_, 0, sizeof(freq_ac_));
memset(freq_dc_, 0, sizeof(freq_dc_));
}
struct EntropyStats {
EntropyStats() {
memset(freq_ac_, 0, sizeof(freq_ac_));
memset(freq_dc_, 0, sizeof(freq_dc_));
}
void Add(int idx, const DCTCoeffs coeffs[], const RunLevel run_levels[]);

uint32_t freq_dc_[2][12 + 1]; // frequency distribution for DC coeffs
uint32_t freq_ac_[2][256 + 1]; // frequency distribution for AC coeffs
};

void Encoder::AddEntropyStats(const DCTCoeffs* const coeffs,
const RunLevel* const run_levels) {
void EntropyStats::Add(int idx, const DCTCoeffs coeffs[],
const RunLevel run_levels[]) {
// freq_ac_[] and freq_dc_[] cannot overflow 32bits, since the maximum
// resolution allowed is 65535 * 65535. The sum of all frequencies cannot
// be greater than 32bits, either.
const int idx = coeffs->idx_;
const int q_idx = quant_idx_[idx];
for (int i = 0; i < coeffs->nb_coeffs_; ++i) {
const int run = run_levels[i].run_;
const int tmp = (run >> 4);
if (tmp) freq_ac_[q_idx][0xf0] += tmp; // count escapes (all at once)
if (tmp) freq_ac_[idx][0xf0] += tmp; // count escapes (all at once)
const int suffix = run_levels[i].level_;
const int sym = ((run & 0x0f) << 4) | (suffix & 0x0f);
++freq_ac_[q_idx][sym];
++freq_ac_[idx][sym];
}
if (coeffs->last_ < 63) { // EOB
++freq_ac_[q_idx][0x00];
++freq_ac_[idx][0x00];
}
++freq_dc_[q_idx][coeffs->dc_code_ & 0x0f];
++freq_dc_[idx][coeffs->dc_code_ & 0x0f];
}

static int cmp(const void *pa, const void *pb) {
Expand Down Expand Up @@ -1471,30 +1475,30 @@ static void BuildOptimalTable(HuffmanTable* const t,
}
}

void Encoder::CompileEntropyStats() {
void Encoder::OptimizeHuffmanTablesFromStats(const EntropyStats& stats) {
// plug and build new tables
for (int q_idx = 0; q_idx < (nb_comps_ == 1 ? 1 : 2); ++q_idx) {
// DC tables
Huffman_tables_[q_idx] = &opt_tables_dc_[q_idx];
opt_tables_dc_[q_idx].syms_ = opt_syms_dc_[q_idx];
BuildOptimalTable(&opt_tables_dc_[q_idx], freq_dc_[q_idx], 12);
BuildOptimalTable(&opt_tables_dc_[q_idx], stats.freq_dc_[q_idx], 12);
// AC tables
Huffman_tables_[2 + q_idx] = &opt_tables_ac_[q_idx];
opt_tables_ac_[q_idx].syms_ = opt_syms_ac_[q_idx];
BuildOptimalTable(&opt_tables_ac_[q_idx], freq_ac_[q_idx], 256);
BuildOptimalTable(&opt_tables_ac_[q_idx], stats.freq_ac_[q_idx], 256);
}
}

void Encoder::StoreOptimalHuffmanTables(size_t nb_mbs,
const DCTCoeffs* coeffs) {
// optimize Huffman tables
ResetEntropyStats();
EntropyStats stats;
const RunLevel* run_levels = all_run_levels_;
for (size_t n = 0; n < nb_mbs; ++n) {
AddEntropyStats(&coeffs[n], run_levels);
stats.Add(quant_idx_[coeffs[n].idx_], &coeffs[n], run_levels);
run_levels += coeffs[n].nb_coeffs_;
}
CompileEntropyStats();
OptimizeHuffmanTablesFromStats(stats);
}

////////////////////////////////////////////////////////////////////////////////
Expand All @@ -1512,7 +1516,7 @@ void Encoder::SinglePassScanOptimized() {
// We use the default Huffman tables as basis for bit-rate evaluation
if (use_trellis_) InitCodes(true);

ResetEntropyStats();
EntropyStats stats;
ResetDCs();
nb_run_levels_ = 0;
int16_t* in = in_blocks_;
Expand All @@ -1535,7 +1539,7 @@ void Encoder::SinglePassScanOptimized() {
const int dc = quantize_block(in, c, &quants_[quant_idx_[c]],
coeffs, run_levels);
coeffs->dc_code_ = GenerateDCDiffCode(dc, &DCs_[c]);
AddEntropyStats(coeffs, run_levels);
stats.Add(quant_idx_[c], coeffs, run_levels);
if (reuse_run_levels_) {
nb_run_levels_ += coeffs->nb_coeffs_;
++coeffs;
Expand All @@ -1548,7 +1552,8 @@ void Encoder::SinglePassScanOptimized() {
}
}

CompileEntropyStats();
OptimizeHuffmanTablesFromStats(stats);

WriteDHT();
WriteSOS();

Expand Down
7 changes: 1 addition & 6 deletions src/sjpegi.h
Original file line number Diff line number Diff line change
Expand Up @@ -256,10 +256,7 @@ struct Encoder {
void CollectCoeffs();

// 2-pass Huffman optimizing scan
void ResetEntropyStats();
void AddEntropyStats(const DCTCoeffs* const coeffs,
const RunLevel* const run_levels);
void CompileEntropyStats();
void OptimizeHuffmanTablesFromStats(const struct EntropyStats& stats);
void StoreOptimalHuffmanTables(size_t nb_mbs, const DCTCoeffs* coeffs);

void SinglePassScan(); // finalizing scan
Expand Down Expand Up @@ -393,8 +390,6 @@ struct Encoder {
uint32_t dc_codes_[2][12];

// histograms for dynamic codes. Could be temporaries.
uint32_t freq_ac_[2][256 + 1]; // frequency distribution for AC coeffs
uint32_t freq_dc_[2][12 + 1]; // frequency distribution for DC coeffs
uint8_t opt_syms_ac_[2][256]; // optimal table for AC symbols
uint8_t opt_syms_dc_[2][12]; // optimal table for DC symbols
HuffmanTable opt_tables_ac_[2];
Expand Down

0 comments on commit 5064f40

Please sign in to comment.