Commit c27c791290 for ffmpeg
commit c27c7912904880e42f4a12c675527ae55a708a91
Author: Mark Thompson <sw@jkqxz.net>
Date: Sun Oct 25 11:25:19 2026 +0000
lavc/apv: Improve multi-symbol entropy decode
This reduces the number of branches in the fast paths, improving
throughput of the entropy decoder.
diff --git a/libavcodec/apv_decode.c b/libavcodec/apv_decode.c
index 7fd93ad0c2..a5167cc4e7 100644
--- a/libavcodec/apv_decode.c
+++ b/libavcodec/apv_decode.c
@@ -193,7 +193,10 @@ static int apv_decode_block(AVCodecContext *avctx,
APVDecodeContext *apv = avctx->priv_data;
int err;
- LOCAL_ALIGNED_32(int16_t, coeff, [64]);
+ // Aligned for SIMD use in transquant.
+ LOCAL_ALIGNED_32(int16_t, coeff, [APV_ENTROPY_COEFF_SIZE]);
+ // Zero only the used entries, padding entries may be written but
+ // are never read.
memset(coeff, 0, 64 * sizeof(int16_t));
err = ff_apv_entropy_decode_block(coeff, gbc, entropy_state);
diff --git a/libavcodec/apv_decode.h b/libavcodec/apv_decode.h
index dd65f1b948..6a6dc853ff 100644
--- a/libavcodec/apv_decode.h
+++ b/libavcodec/apv_decode.h
@@ -19,6 +19,7 @@
#ifndef AVCODEC_APV_DECODE_H
#define AVCODEC_APV_DECODE_H
+#include <assert.h>
#include <stdint.h>
#include <stdatomic.h>
@@ -33,10 +34,15 @@
// Number of bits in the entropy look-up tables.
// It may be desirable to tune this per-architecture, as a larger LUT
// trades greater memory use for fewer instructions.
-// (N bits -> 24*2^N bytes of tables; 9 -> 12KB of tables.)
+// (N bits -> 384*2^N bytes of tables; 9 -> 192KB of tables.)
#define APV_VLC_LUT_BITS 9
#define APV_VLC_LUT_SIZE (1 << APV_VLC_LUT_BITS)
+// The single-symbol LUT must be able to resolve a symbol with a single
+// leading zero for the largest k (5) without reading more bits, which
+// takes 2 + 1 + 5 = 8 bits.
+static_assert(APV_VLC_LUT_BITS >= 8, "APV VLC LUT too small");
+
typedef struct APVSingleVLCLUTEntry {
uint16_t result; // Return value if not reading more.
uint8_t consume; // Number of bits to consume.
@@ -52,26 +58,57 @@ typedef struct APVMultiVLCLUTEntry {
uint8_t k_level_0 : 3;
// k_level after decoding all symbols.
uint8_t k_level_1 : 3;
- // Run output values.
- uint8_t run[2];
- // Level output values.
- int16_t level[2];
- // Bit index of the end of each code.
+ // Level output values. If fewer than two levels are decoded the
+ // remaining ones are zero.
+ int8_t level[2];
+ // Scan position of each level relative to the scan position before
+ // this entry. Missing levels are placed at the end of the entry,
+ // where writing the level zero is harmless.
+ uint8_t level_pos[2];
+ // Total scan position advance if all symbols are consumed. If not
+ // all symbols are consumed this can be recalculated from level_pos.
+ uint8_t scan_advance;
+ // Bits consumed at the end of each of the four possible symbols.
+ // Entry 3 always contains the bits from all symbols, even if fewer
+ // than four symbols are consumed.
uint8_t offset[4];
+ // Index of the table to use for the next lookup, combining the
+ // type of the next symbol with k_run and k_level after this entry.
+ uint8_t next;
} APVMultiVLCLUTEntry;
+// Types of entry in the entropy table.
+enum {
+ // Entries are run/level/run/level.
+ APV_ENTROPY_RUN_FIRST = 0,
+ // Entries are level/run/level/run.
+ APV_ENTROPY_LEVEL_FIRST = 1,
+};
+// Index of the base point in the multi-symbol table for the given
+// type, k_run and k_level.
+#define APV_TABLE_INDEX(type, k_run, k_level) \
+ (((type) * 3 + (k_run)) * 5 + (k_level))
+
typedef struct APVVLCLUT {
// Single-symbol LUT for VLCs.
// Applies to all coefficients, but used only for DC coefficients
// in the decoder.
APVSingleVLCLUTEntry single_lut[6][APV_VLC_LUT_SIZE];
// Multi-symbol LUT for run/level combinations, decoding up to four
- // symbols per step. Comes in two versions, which to use depends on
- // whether the next symbol is a run or a level.
- APVMultiVLCLUTEntry run_first_lut[3][5][APV_VLC_LUT_SIZE];
- APVMultiVLCLUTEntry level_first_lut[3][5][APV_VLC_LUT_SIZE];
+ // symbols per step.
+ // Indexed by [run first or level first][k_run][k_level][bits].
+ APVMultiVLCLUTEntry multi_lut[2][3][5][APV_VLC_LUT_SIZE];
+ // Zigzag scan extended past the end of the block, where every
+ // position maps to a dummy coefficient after the block.
+ uint8_t zigzag[128];
} APVVLCLUT;
+
+// Number of coefficients in the block buffer used by entropy decode:
+// the block itself and a dummy coefficient slot at the end which is
+// used to avoid branching.
+#define APV_ENTROPY_COEFF_SIZE 65
+
typedef struct APVEntropyState {
void *log_ctx;
@@ -126,8 +163,10 @@ void ff_apv_entropy_build_decode_lut(APVVLCLUT *decode_lut);
* Entropy decode a single 8x8 block to coefficients.
*
* Outputs nonzero coefficients only to the block row-major order
- * (dezigzag is applied within the function). The output block
- * must have been filled with zeroes before calling this function.
+ * (dezigzag is applied within the function). The first 64 elements
+ * of the output block must have been filled with zeroes before
+ * calling this function, and there must be space for
+ * APV_ENTROPY_COEFF_SIZE elements in total.
*/
int ff_apv_entropy_decode_block(int16_t *restrict coeff,
GetBitContext *restrict gbc,
diff --git a/libavcodec/apv_entropy.c b/libavcodec/apv_entropy.c
index 30f31a14ff..507318cafa 100644
--- a/libavcodec/apv_entropy.c
+++ b/libavcodec/apv_entropy.c
@@ -108,101 +108,214 @@ void ff_apv_entropy_build_decode_lut(APVVLCLUT *decode_lut)
// Build the multi-symbol VLC table.
for (int start_run = 0; start_run <= 2; start_run++) {
for (int start_level = 0; start_level <= 4; start_level++) {
- for (unsigned int code = 0; code < lut_size; code++) {
- APVMultiVLCLUTEntry *ent;
- int k_run, k_level;
- GetBitContext gbc;
- PutBitContext pbc;
- uint8_t buffer[16];
- uint8_t run_first_buffer[16];
- uint8_t level_first_buffer[16];
-
- memset(buffer, 0, sizeof(buffer));
- init_put_bits(&pbc, buffer, sizeof(buffer));
- put_bits(&pbc, APV_VLC_LUT_BITS, code);
- flush_put_bits(&pbc);
-
- memcpy(run_first_buffer, buffer, sizeof(buffer));
- memcpy(level_first_buffer, buffer, sizeof(buffer));
-
- k_run = start_run;
- k_level = start_level;
-
- ent = &decode_lut->run_first_lut[k_run][k_level][code];
- memset(ent, 0, sizeof(*ent));
- init_get_bits8(&gbc, run_first_buffer, sizeof(run_first_buffer));
-
- ent->count = 0;
- for (int i = 0; i <= 1; i++) {
- int value, sign, pos;
-
- value = apv_read_vlc(&gbc, k_run, decode_lut);
- pos = get_bits_count(&gbc);
- if (pos > APV_VLC_LUT_BITS)
- break;
- ent->run[i] = value;
- ent->offset[ent->count] = pos;
- ++ent->count;
- k_run = FFMIN(value >> 2, 2);
-
- value = apv_read_vlc(&gbc, k_level, decode_lut);
- sign = get_bits1(&gbc);
- pos = get_bits_count(&gbc);
- if (pos > APV_VLC_LUT_BITS)
- break;
- ++value;
- ent->level[i] = sign ? -value : value;
- ent->offset[ent->count] = pos;
- ++ent->count;
- k_level = FFMIN(value >> 2, 4);
- if (i == 0)
- ent->k_level_0 = k_level;
- }
- if (ent->count > 0 && ent->count < 4)
- ent->offset[3] = ent->offset[ent->count - 1];
- ent->k_run = k_run;
- ent->k_level_1 = k_level;
-
- k_run = start_run;
- k_level = start_level;
-
- ent = &decode_lut->level_first_lut[k_run][k_level][code];
- memset(ent, 0, sizeof(*ent));
- init_get_bits8(&gbc, level_first_buffer, sizeof(level_first_buffer));
-
- ent->count = 0;
- for (int i = 0; i <= 1; i++) {
- int value, sign, pos;
-
- value = apv_read_vlc(&gbc, k_level, decode_lut);
- sign = get_bits1(&gbc);
- pos = get_bits_count(&gbc);
- if (pos > APV_VLC_LUT_BITS)
- break;
- ++value;
- ent->level[i] = sign ? -value : value;
- ent->offset[ent->count] = pos;
- ++ent->count;
- k_level = FFMIN(value >> 2, 4);
- if (i == 0)
- ent->k_level_0 = k_level;
-
- value = apv_read_vlc(&gbc, k_run, decode_lut);
- pos = get_bits_count(&gbc);
- if (pos > APV_VLC_LUT_BITS)
- break;
- ent->run[i] = value;
- ent->offset[ent->count] = pos;
- ++ent->count;
- k_run = FFMIN(value >> 2, 2);
+ for (int type = APV_ENTROPY_RUN_FIRST;
+ type <= APV_ENTROPY_LEVEL_FIRST; type++) {
+ for (unsigned int code = 0; code < lut_size; code++) {
+ APVMultiVLCLUTEntry *ent;
+ int k_run, k_level, adv, nb_levels;
+ GetBitContext gbc;
+ PutBitContext pbc;
+ uint8_t buffer[16];
+
+ memset(buffer, 0, sizeof(buffer));
+ init_put_bits(&pbc, buffer, sizeof(buffer));
+ put_bits(&pbc, APV_VLC_LUT_BITS, code);
+ flush_put_bits(&pbc);
+
+ k_run = start_run;
+ k_level = start_level;
+
+ ent = &decode_lut->multi_lut[type][k_run][k_level][code];
+ memset(ent, 0, sizeof(*ent));
+ init_get_bits8(&gbc, buffer, sizeof(buffer));
+
+ // Symbols alternate between run and level, starting
+ // with whichever the type indicates (so even values
+ // of sym are runs). Stop at the first one which
+ // does not fit in the lookup bits.
+ adv = 0;
+ nb_levels = 0;
+ for (int sym = type; sym < type + 4; sym++) {
+ int value, sign, pos;
+
+ if (sym % 2 == 0) {
+ // Reading a run.
+ value = apv_read_vlc(&gbc, k_run, decode_lut);
+ pos = get_bits_count(&gbc);
+ if (pos > APV_VLC_LUT_BITS)
+ break;
+ adv += value;
+ k_run = FFMIN(value >> 2, 2);
+ } else {
+ // Reading a level.
+ value = apv_read_vlc(&gbc, k_level, decode_lut);
+ sign = get_bits1(&gbc);
+ pos = get_bits_count(&gbc);
+ if (pos > APV_VLC_LUT_BITS)
+ break;
+ ++value;
+ av_assert0(value <= INT8_MAX);
+ ent->level[nb_levels] = sign ? -value : value;
+ ent->level_pos[nb_levels] = adv;
+ ++nb_levels;
+ adv += 1;
+ k_level = FFMIN(value >> 2, 4);
+ if (nb_levels == 1)
+ ent->k_level_0 = k_level;
+ }
+ ent->offset[ent->count] = pos;
+ ++ent->count;
+ }
+ // Missing levels write zeroes later in the array where
+ // they will either be overwritten or not used.
+ for (int i = nb_levels; i < 2; i++)
+ ent->level_pos[i] = adv;
+ // Entries are applied at scan positions below 64, so
+ // this keeps every write inside the extended zigzag.
+ av_assert0(adv < 64);
+ ent->scan_advance = adv;
+ if (ent->count > 0 && ent->count < 4)
+ ent->offset[3] = ent->offset[ent->count - 1];
+ ent->k_run = k_run;
+ ent->k_level_1 = k_level;
+ ent->next = APV_TABLE_INDEX(type ^ (ent->count & 1),
+ k_run, k_level);
}
- if (ent->count > 0 && ent->count < 4)
- ent->offset[3] = ent->offset[ent->count - 1];
- ent->k_run = k_run;
- ent->k_level_1 = k_level;
}
}
}
+
+ // Positions past the end of the block all map to the dummy
+ // coefficient slot at the end.
+ for (int i = 0; i < FF_ARRAY_ELEMS(decode_lut->zigzag); i++)
+ decode_lut->zigzag[i] = i < 64 ? ff_zigzag_direct[i] : 64;
+}
+
+// Decode a run code which is too long for the multi-symbol LUT.
+// All such codes fit in the 18 bits already read.
+av_always_inline
+static int apv_decode_long_run(GetBitContext *restrict gbc,
+ uint32_t next_bits, int k_run,
+ APVEntropyState *restrict state)
+{
+ uint32_t bits, low_bits;
+ unsigned int leading_zeroes, low_bit_count, low_bit_shift;
+
+ // Remove the prefix bits.
+ bits = next_bits & 0xffff;
+ // Determine code length.
+ leading_zeroes = 15 - av_log2(bits);
+ if (leading_zeroes >= 6) {
+ // 6 zeroes implies run > 64, which is always invalid.
+ av_log(state->log_ctx, AV_LOG_ERROR,
+ "Out-of-range run value: %d leading zeroes.\n",
+ leading_zeroes);
+ return AVERROR_INVALIDDATA;
+ }
+ // Extract the low bits.
+ low_bit_count = leading_zeroes + k_run;
+ low_bit_shift = 16 - (1 + 2 * leading_zeroes + k_run);
+ low_bits = av_zero_extend(bits >> low_bit_shift, low_bit_count);
+ // Skip over the bits just used.
+ skip_bits(gbc, 2 + leading_zeroes + 1 + low_bit_count);
+ // Construct run code.
+ return (2 << k_run) +
+ ((1 << leading_zeroes) - 1) * (1 << k_run) +
+ low_bits;
+}
+
+// Decode a level code which is too long for the multi-symbol LUT,
+// returning the signed level and setting the absolute value.
+// The 18 bits already read are sufficient for the length, but we may
+// need to read more bits to complete the value.
+av_always_inline
+static int apv_decode_long_level(GetBitContext *restrict gbc,
+ uint32_t next_bits, int k_level,
+ int *abs_level_out, int scan_pos,
+ APVEntropyState *restrict state)
+{
+ uint32_t bits;
+ unsigned int leading_zeroes;
+ int level, abs_level, sign;
+
+ // Remove the prefix bits.
+ bits = next_bits & 0xffff;
+ // Determine code length.
+ leading_zeroes = 15 - av_log2(bits);
+ // Skip the prefix and length bits.
+ skip_bits(gbc, 2 + leading_zeroes + 1);
+ // Read the rest of the code and construct the level.
+ // Include the + 1 offset for nonzero value here.
+ abs_level = (2 << k_level) +
+ ((1 << leading_zeroes) - 1) * (1 << k_level) +
+ get_bits(gbc, leading_zeroes + k_level) + 1;
+
+ sign = get_bits1(gbc);
+ if (sign)
+ level = -abs_level;
+ else
+ level = abs_level;
+
+ // Check range (not checked in any other case, only a long
+ // code can be out of range).
+ if (level < APV_MIN_TRANS_COEFF ||
+ level > APV_MAX_TRANS_COEFF) {
+ av_log(state->log_ctx, AV_LOG_ERROR,
+ "Out-of-range AC coefficient value at %d: %d.\n",
+ scan_pos, level);
+ return AVERROR_INVALIDDATA;
+ }
+ *abs_level_out = abs_level;
+ return level;
+}
+
+// Apply the symbols from a multi-symbol LUT entry. Both levels are
+// always written: absent ones are zero, and any beyond the end of the
+// block go to the dummy coefficient. Returns nonzero if the end of
+// the block was reached, in which case only the bits up to the symbol
+// which reached it are consumed.
+av_always_inline
+static int apv_apply_multi_entry(int16_t *restrict coeff,
+ GetBitContext *restrict gbc,
+ const APVMultiVLCLUTEntry *ent,
+ const uint8_t *zigzag,
+ int *scan_pos_ptr, int type)
+{
+ int scan_pos = *scan_pos_ptr;
+
+ coeff[zigzag[scan_pos + ent->level_pos[0]]] = ent->level[0];
+ coeff[zigzag[scan_pos + ent->level_pos[1]]] = ent->level[1];
+
+ if (scan_pos + ent->scan_advance >= 64) {
+ // We've gone over the end: find the symbol which reached the
+ // end and stop there.
+ int end[4], i;
+
+ if (type == APV_ENTROPY_RUN_FIRST) {
+ end[0] = ent->level_pos[0];
+ end[1] = ent->level_pos[0] + 1;
+ end[2] = ent->level_pos[1];
+ end[3] = ent->level_pos[1] + 1;
+ } else {
+ end[0] = 1;
+ end[1] = ent->level_pos[1];
+ end[2] = ent->level_pos[1] + 1;
+ end[3] = ent->scan_advance;
+ }
+ for (i = 0; i < ent->count - 1; i++) {
+ if (scan_pos + end[i] >= 64)
+ break;
+ }
+ skip_bits(gbc, ent->offset[i]);
+ *scan_pos_ptr = scan_pos + end[i];
+ return 1;
+ } else {
+ // All codes used: advance the bitstream and scan position by
+ // the full values.
+ skip_bits(gbc, ent->offset[3]);
+ *scan_pos_ptr = scan_pos + ent->scan_advance;
+ return 0;
+ }
}
int ff_apv_entropy_decode_block(int16_t *restrict coeff,
@@ -210,7 +323,9 @@ int ff_apv_entropy_decode_block(int16_t *restrict coeff,
APVEntropyState *restrict state)
{
const APVVLCLUT *lut = state->decode_lut;
- int scan_pos;
+ const APVMultiVLCLUTEntry *tables = lut->multi_lut[0][0][0];
+ const uint8_t *zigzag = lut->zigzag;
+ int scan_pos, type, table_index;
int k_dc = state->prev_k_dc;
int k_run, k_level;
uint32_t next_bits, lut_bits;
@@ -256,349 +371,118 @@ int ff_apv_entropy_decode_block(int16_t *restrict coeff,
// single-symbol LUT is never useful here as the multisymbol lookup
// has already determined that the code is too long.)
- // Run a single iteration of the run-first LUT to start, then a
- // single iteration of the level-first LUT if that only read a
- // single code. This avoids dealing with the first-AC logic inside
- // the normal code lookup sequence.
+ // The first level in the block sets the k_level for the next block,
+ // so run the first lookup (and the second, if the first did not
+ // contain a level) separately.
- k_level = state->prev_k_level;
+ scan_pos = 1;
+ k_run = 0;
+ k_level = state->prev_k_level;
{
next_bits = show_bits(gbc, 18);
lut_bits = next_bits >> (18 - APV_VLC_LUT_BITS);
- ent = &lut->run_first_lut[0][k_level][lut_bits];
+ ent = &lut->multi_lut[APV_ENTROPY_RUN_FIRST][0][k_level][lut_bits];
if (ent->count == 0) {
- // One long code.
- uint32_t bits, low_bits;
- unsigned int leading_zeroes, low_bit_count, low_bit_shift;
- int run;
-
- // Remove the prefix bits.
- bits = next_bits & 0xffff;
- // Determine code length.
- leading_zeroes = 15 - av_log2(bits);
- if (leading_zeroes >= 6) {
- // 6 zeroes implies run > 64, which is always invalid.
- av_log(state->log_ctx, AV_LOG_ERROR,
- "Out-of-range run value: %d leading zeroes.\n",
- leading_zeroes);
- return AVERROR_INVALIDDATA;
- }
- // Extract the low bits.
- low_bit_count = leading_zeroes;
- low_bit_shift = 16 - (1 + 2 * leading_zeroes);
- low_bits = av_zero_extend(bits >> low_bit_shift, low_bit_count);
- // Construct run code.
- run = 2 + ((1 << leading_zeroes) - 1) + low_bits;
- // Skip over the bits just used.
- skip_bits(gbc, 2 + leading_zeroes + 1 + low_bit_count);
-
- scan_pos = run + 1;
+ int run = apv_decode_long_run(gbc, next_bits, 0, state);
+ if (run < 0)
+ return run;
+ scan_pos += run;
if (scan_pos >= 64)
goto end_of_block;
k_run = FFMIN(run >> 2, 2);
- goto first_level;
} else {
- // One or more short codes starting with a run; if there is
- // a level code then the length needs to be saved for the
- // next block.
-
- scan_pos = ent->run[0] + 1;
- if (scan_pos >= 64) {
- skip_bits(gbc, ent->offset[0]);
- goto end_of_block;
- }
- if (ent->count > 1) {
- coeff[ff_zigzag_direct[scan_pos]] = ent->level[0];
- ++scan_pos;
+ // The level is only real if the run before it did not
+ // reach the end of the block.
+ if (ent->count > 1 && scan_pos + ent->level_pos[0] < 64)
state->prev_k_level = ent->k_level_0;
- if (scan_pos >= 64) {
- skip_bits(gbc, ent->offset[1]);
- goto end_of_block;
- }
- }
- if (ent->count > 2) {
- scan_pos += ent->run[1];
- if (scan_pos >= 64) {
- skip_bits(gbc, ent->offset[2]);
- goto end_of_block;
- }
- }
- if (ent->count > 3) {
- coeff[ff_zigzag_direct[scan_pos]] = ent->level[1];
- ++scan_pos;
- if (scan_pos >= 64) {
- skip_bits(gbc, ent->offset[3]);
- goto end_of_block;
- }
- }
- skip_bits(gbc, ent->offset[3]);
+ if (apv_apply_multi_entry(coeff, gbc, ent, zigzag,
+ &scan_pos, APV_ENTROPY_RUN_FIRST))
+ goto end_of_block;
k_run = ent->k_run;
k_level = ent->k_level_1;
- if (ent->count == 1)
- goto first_level;
- else if (ent->count & 1)
- goto next_is_level;
- else
- goto next_is_run;
+ if (ent->count > 1) {
+ type = APV_ENTROPY_RUN_FIRST ^ (ent->count & 1);
+ goto normal_loop;
+ }
}
}
- first_level: {
+ // Only read a run, still need to read the first level.
+ {
next_bits = show_bits(gbc, 18);
lut_bits = next_bits >> (18 - APV_VLC_LUT_BITS);
- ent = &lut->level_first_lut[k_run][k_level][lut_bits];
+ ent = &lut->multi_lut[APV_ENTROPY_LEVEL_FIRST][k_run][k_level][lut_bits];
if (ent->count == 0) {
- // One long code.
- uint32_t bits;
- unsigned int leading_zeroes;
- int level, abs_level, sign;
-
- // Remove the prefix bits.
- bits = next_bits & 0xffff;
- // Determine code length.
- leading_zeroes = 15 - av_log2(bits);
- // Skip the prefix and length bits.
- skip_bits(gbc, 2 + leading_zeroes + 1);
- // Read the rest of the code and construct the level.
- // Include the + 1 offset for nonzero value here.
- abs_level = (2 << k_level) +
- ((1 << leading_zeroes) - 1) * (1 << k_level) +
- get_bits(gbc, leading_zeroes + k_level) + 1;
-
- sign = get_bits(gbc, 1);
- if (sign)
- level = -abs_level;
- else
- level = abs_level;
-
- // Check range (not checked in any other case, only a long
- // code can be out of range).
- if (level < APV_MIN_TRANS_COEFF ||
- level > APV_MAX_TRANS_COEFF) {
- av_log(state->log_ctx, AV_LOG_ERROR,
- "Out-of-range AC coefficient value at %d: %d.\n",
- scan_pos, level);
- return AVERROR_INVALIDDATA;
- }
- coeff[ff_zigzag_direct[scan_pos]] = level;
+ int level, abs_level;
+ level = apv_decode_long_level(gbc, next_bits, k_level,
+ &abs_level, scan_pos, state);
+ if (level < APV_MIN_TRANS_COEFF)
+ return level;
+ coeff[zigzag[scan_pos]] = level;
++scan_pos;
k_level = FFMIN(abs_level >> 2, 4);
state->prev_k_level = k_level;
if (scan_pos >= 64)
goto end_of_block;
- goto next_is_run;
-
+ type = APV_ENTROPY_RUN_FIRST;
} else {
- // One or more short codes.
-
- coeff[ff_zigzag_direct[scan_pos]] = ent->level[0];
- ++scan_pos;
state->prev_k_level = ent->k_level_0;
- if (scan_pos >= 64) {
- skip_bits(gbc, ent->offset[0]);
+ if (apv_apply_multi_entry(coeff, gbc, ent, zigzag,
+ &scan_pos, APV_ENTROPY_LEVEL_FIRST))
goto end_of_block;
- }
- if (ent->count > 1) {
- scan_pos += ent->run[0];
- if (scan_pos >= 64) {
- skip_bits(gbc, ent->offset[1]);
- goto end_of_block;
- }
- }
- if (ent->count > 2) {
- coeff[ff_zigzag_direct[scan_pos]] = ent->level[1];
- ++scan_pos;
- if (scan_pos >= 64) {
- skip_bits(gbc, ent->offset[2]);
- goto end_of_block;
- }
- }
- if (ent->count > 3) {
- scan_pos += ent->run[1];
- if (scan_pos >= 64) {
- skip_bits(gbc, ent->offset[3]);
- goto end_of_block;
- }
- }
- skip_bits(gbc, ent->offset[3]);
k_run = ent->k_run;
k_level = ent->k_level_1;
- if (ent->count & 1)
- goto next_is_run;
- else
- goto next_is_level;
+ type = APV_ENTROPY_LEVEL_FIRST ^ (ent->count & 1);
}
}
- next_is_run: {
+normal_loop:
+ // From here the only state carried between lookups is the index of
+ // the table to use, which each entry supplies for the next one.
+ table_index = APV_TABLE_INDEX(type, k_run, k_level);
+ for (;;) {
next_bits = show_bits(gbc, 18);
lut_bits = next_bits >> (18 - APV_VLC_LUT_BITS);
- ent = &lut->run_first_lut[k_run][k_level][lut_bits];
+ ent = &tables[table_index * APV_VLC_LUT_SIZE + lut_bits];
if (ent->count == 0) {
- // One long code.
- uint32_t bits, low_bits;
- unsigned int leading_zeroes, low_bit_count, low_bit_shift;
- int run;
-
- // Remove the prefix bits.
- bits = next_bits & 0xffff;
- // Determine code length.
- leading_zeroes = 15 - av_log2(bits);
- if (leading_zeroes >= 6) {
- // 6 zeroes implies run > 64, which is always invalid.
- av_log(state->log_ctx, AV_LOG_ERROR,
- "Out-of-range run value: %d leading zeroes.\n",
- leading_zeroes);
- return AVERROR_INVALIDDATA;
- }
- // Extract the low bits.
- low_bit_count = leading_zeroes + k_run;
- low_bit_shift = 16 - (1 + 2 * leading_zeroes + k_run);
- low_bits = av_zero_extend(bits >> low_bit_shift, low_bit_count);
- // Construct run code.
- run = (2 << k_run) +
- ((1 << leading_zeroes) - 1) * (1 << k_run) +
- low_bits;
- // Skip over the bits just used.
- skip_bits(gbc, 2 + leading_zeroes + 1 + low_bit_count);
-
- scan_pos += run;
- if (scan_pos >= 64)
- goto end_of_block;
- k_run = FFMIN(run >> 2, 2);
- goto next_is_level;
-
- } else {
- // One or more short codes.
-
- scan_pos += ent->run[0];
- if (scan_pos >= 64) {
- skip_bits(gbc, ent->offset[0]);
- goto end_of_block;
- }
- if (ent->count > 1) {
- coeff[ff_zigzag_direct[scan_pos]] = ent->level[0];
- ++scan_pos;
- if (scan_pos >= 64) {
- skip_bits(gbc, ent->offset[1]);
- goto end_of_block;
- }
- }
- if (ent->count > 2) {
- scan_pos += ent->run[1];
- if (scan_pos >= 64) {
- skip_bits(gbc, ent->offset[2]);
+ // Missed in the lookup, so need to re-derive the type,
+ // k_run and k_level from the table index.
+ k_run = table_index / 5 % 3;
+ k_level = table_index % 5;
+ if (table_index < APV_TABLE_INDEX(APV_ENTROPY_LEVEL_FIRST, 0, 0)) {
+ int run = apv_decode_long_run(gbc, next_bits, k_run, state);
+ if (run < 0)
+ return run;
+ scan_pos += run;
+ if (scan_pos >= 64)
goto end_of_block;
- }
- }
- if (ent->count > 3) {
- coeff[ff_zigzag_direct[scan_pos]] = ent->level[1];
+ k_run = FFMIN(run >> 2, 2);
+ table_index = APV_TABLE_INDEX(APV_ENTROPY_LEVEL_FIRST, k_run, k_level);
+ } else {
+ int level, abs_level;
+ level = apv_decode_long_level(gbc, next_bits, k_level,
+ &abs_level, scan_pos, state);
+ if (level < APV_MIN_TRANS_COEFF)
+ return level;
+ coeff[zigzag[scan_pos]] = level;
++scan_pos;
- if (scan_pos >= 64) {
- skip_bits(gbc, ent->offset[3]);
+ k_level = FFMIN(abs_level >> 2, 4);
+ if (scan_pos >= 64)
goto end_of_block;
- }
+ table_index = APV_TABLE_INDEX(APV_ENTROPY_RUN_FIRST, k_run, k_level);
}
- skip_bits(gbc, ent->offset[3]);
- k_run = ent->k_run;
- k_level = ent->k_level_1;
- if (ent->count & 1)
- goto next_is_level;
- else
- goto next_is_run;
- }
- }
-
- next_is_level: {
- next_bits = show_bits(gbc, 18);
- lut_bits = next_bits >> (18 - APV_VLC_LUT_BITS);
-
- ent = &lut->level_first_lut[k_run][k_level][lut_bits];
-
- if (ent->count == 0) {
- // One long code.
- uint32_t bits;
- unsigned int leading_zeroes;
- int level, abs_level, sign;
-
- // Remove the prefix bits.
- bits = next_bits & 0xffff;
- // Determine code length.
- leading_zeroes = 15 - av_log2(bits);
- // Skip the prefix and length bits.
- skip_bits(gbc, 2 + leading_zeroes + 1);
- // Read the rest of the code and construct the level.
- // Include the + 1 offset for nonzero value here.
- abs_level = (2 << k_level) +
- ((1 << leading_zeroes) - 1) * (1 << k_level) +
- get_bits(gbc, leading_zeroes + k_level) + 1;
-
- sign = get_bits(gbc, 1);
- if (sign)
- level = -abs_level;
- else
- level = abs_level;
-
- // Check range (not checked in any other case, only a long
- // code can be out of range).
- if (level < APV_MIN_TRANS_COEFF ||
- level > APV_MAX_TRANS_COEFF) {
- av_log(state->log_ctx, AV_LOG_ERROR,
- "Out-of-range AC coefficient value at %d: %d.\n",
- scan_pos, level);
- return AVERROR_INVALIDDATA;
- }
- coeff[ff_zigzag_direct[scan_pos]] = level;
- ++scan_pos;
- k_level = FFMIN(abs_level >> 2, 4);
- if (scan_pos >= 64)
- goto end_of_block;
- goto next_is_run;
-
} else {
- // One or more short codes.
-
- coeff[ff_zigzag_direct[scan_pos]] = ent->level[0];
- ++scan_pos;
- if (scan_pos >= 64) {
- skip_bits(gbc, ent->offset[0]);
+ type = table_index >= APV_TABLE_INDEX(APV_ENTROPY_LEVEL_FIRST, 0, 0);
+ if (apv_apply_multi_entry(coeff, gbc, ent, zigzag,
+ &scan_pos, type))
goto end_of_block;
- }
- if (ent->count > 1) {
- scan_pos += ent->run[0];
- if (scan_pos >= 64) {
- skip_bits(gbc, ent->offset[1]);
- goto end_of_block;
- }
- }
- if (ent->count > 2) {
- coeff[ff_zigzag_direct[scan_pos]] = ent->level[1];
- ++scan_pos;
- if (scan_pos >= 64) {
- skip_bits(gbc, ent->offset[2]);
- goto end_of_block;
- }
- }
- if (ent->count > 3) {
- scan_pos += ent->run[1];
- if (scan_pos >= 64) {
- skip_bits(gbc, ent->offset[3]);
- goto end_of_block;
- }
- }
- skip_bits(gbc, ent->offset[3]);
- k_run = ent->k_run;
- k_level = ent->k_level_1;
- if (ent->count & 1)
- goto next_is_run;
- else
- goto next_is_level;
+ table_index = ent->next;
}
}
diff --git a/libavcodec/tests/apv.c b/libavcodec/tests/apv.c
index 365a395af1..2f57539a1d 100644
--- a/libavcodec/tests/apv.c
+++ b/libavcodec/tests/apv.c
@@ -313,7 +313,7 @@ static int test_apv_entropy_decode_block(void)
APVEntropyState state, save_state;
int16_t block[64];
int16_t block_test1[64];
- int16_t block_test2[64];
+ int16_t block_test2[APV_ENTROPY_COEFF_SIZE];
uint8_t buffer[1024];
PutBitContext pbc;
GetBitContext gbc;