+#if CONFIG_VP4_DECODER
+/**
+ * eob_tracker[] is instead of TOKEN_EOB(value)
+ * a dummy TOKEN_EOB(0) value is used to make vp3_dequant work
+ *
+ * @return < 0 on error
+ */
+static int vp4_unpack_vlcs(Vp3DecodeContext *s, GetBitContext *gb,
+ VLC *vlc_tables[64],
+ int plane, int eob_tracker[64], int fragment)
+{
+ int token;
+ int zero_run = 0;
+ int16_t coeff = 0;
+ int coeff_i = 0;
+ int eob_run;
+
+ while (!eob_tracker[coeff_i]) {
+ if (get_bits_left(gb) < 1)
+ return AVERROR_INVALIDDATA;
+
+ token = get_vlc2(gb, vlc_tables[coeff_i]->table, 11, 3);
+
+ /* use the token to get a zero run, a coefficient, and an eob run */
+ if ((unsigned) token <= 6U) {
+ eob_run = get_eob_run(gb, token);
+ *s->dct_tokens[plane][coeff_i]++ = TOKEN_EOB(0);
+ eob_tracker[coeff_i] = eob_run - 1;
+ return 0;
+ } else if (token >= 0) {
+ zero_run = get_coeff(gb, token, &coeff);
+
+ if (zero_run) {
+ if (coeff_i + zero_run > 64) {
+ av_log(s->avctx, AV_LOG_DEBUG,
+ "Invalid zero run of %d with %d coeffs left\n",
+ zero_run, 64 - coeff_i);
+ zero_run = 64 - coeff_i;
+ }
+ *s->dct_tokens[plane][coeff_i]++ = TOKEN_ZERO_RUN(coeff, zero_run);
+ coeff_i += zero_run;
+ } else {
+ if (!coeff_i)
+ s->all_fragments[fragment].dc = coeff;
+
+ *s->dct_tokens[plane][coeff_i]++ = TOKEN_COEFF(coeff);
+ }
+ coeff_i++;
+ if (coeff_i >= 64) /* > 64 occurs when there is a zero_run overflow */
+ return 0; /* stop */
+ } else {
+ av_log(s->avctx, AV_LOG_ERROR, "Invalid token %d\n", token);
+ return -1;
+ }
+ }
+ *s->dct_tokens[plane][coeff_i]++ = TOKEN_EOB(0);
+ eob_tracker[coeff_i]--;
+ return 0;
+}
+
+static void vp4_dc_predictor_reset(VP4Predictor *p)
+{
+ p->dc = 0;
+ p->type = VP4_DC_UNDEFINED;
+}
+
+static void vp4_dc_pred_before(const Vp3DecodeContext *s, VP4Predictor dc_pred[6][6], int sb_x)
+{
+ int i, j;
+
+ for (i = 0; i < 4; i++)
+ dc_pred[0][i + 1] = s->dc_pred_row[sb_x * 4 + i];
+
+ for (j = 1; j < 5; j++)
+ for (i = 0; i < 4; i++)
+ vp4_dc_predictor_reset(&dc_pred[j][i + 1]);
+}
+
+static void vp4_dc_pred_after(Vp3DecodeContext *s, VP4Predictor dc_pred[6][6], int sb_x)
+{
+ int i;
+
+ for (i = 0; i < 4; i++)
+ s->dc_pred_row[sb_x * 4 + i] = dc_pred[4][i + 1];
+
+ for (i = 1; i < 5; i++)
+ dc_pred[i][0] = dc_pred[i][4];
+}
+
+/* note: dc_pred points to the current block */
+static int vp4_dc_pred(const Vp3DecodeContext *s, const VP4Predictor * dc_pred, const int * last_dc, int type, int plane)
+{
+ int count = 0;
+ int dc = 0;
+
+ if (dc_pred[-6].type == type) {
+ dc += dc_pred[-6].dc;
+ count++;
+ }
+
+ if (dc_pred[6].type == type) {
+ dc += dc_pred[6].dc;
+ count++;
+ }
+
+ if (count != 2 && dc_pred[-1].type == type) {
+ dc += dc_pred[-1].dc;
+ count++;
+ }
+
+ if (count != 2 && dc_pred[1].type == type) {
+ dc += dc_pred[1].dc;
+ count++;
+ }
+
+ /* using division instead of shift to correctly handle negative values */
+ return count == 2 ? dc / 2 : last_dc[type];
+}
+
+static void vp4_set_tokens_base(Vp3DecodeContext *s)
+{
+ int plane, i;
+ int16_t *base = s->dct_tokens_base;
+ for (plane = 0; plane < 3; plane++) {
+ for (i = 0; i < 64; i++) {
+ s->dct_tokens[plane][i] = base;
+ base += s->fragment_width[!!plane] * s->fragment_height[!!plane];
+ }
+ }
+}
+
+static int vp4_unpack_dct_coeffs(Vp3DecodeContext *s, GetBitContext *gb)
+{
+ int i, j;
+ int dc_y_table;
+ int dc_c_table;
+ int ac_y_table;
+ int ac_c_table;
+ VLC *tables[2][64];
+ int plane, sb_y, sb_x;
+ int eob_tracker[64];
+ VP4Predictor dc_pred[6][6];
+ int last_dc[NB_VP4_DC_TYPES];
+
+ if (get_bits_left(gb) < 16)
+ return AVERROR_INVALIDDATA;
+
+ /* fetch the DC table indexes */
+ dc_y_table = get_bits(gb, 4);
+ dc_c_table = get_bits(gb, 4);
+
+ ac_y_table = get_bits(gb, 4);
+ ac_c_table = get_bits(gb, 4);
+
+ /* build tables of DC/AC VLC tables */
+
+ tables[0][0] = &s->dc_vlc[dc_y_table];
+ tables[1][0] = &s->dc_vlc[dc_c_table];
+ for (i = 1; i <= 5; i++) {
+ tables[0][i] = &s->ac_vlc_1[ac_y_table];
+ tables[1][i] = &s->ac_vlc_1[ac_c_table];
+ }
+ for (i = 6; i <= 14; i++) {
+ tables[0][i] = &s->ac_vlc_2[ac_y_table];
+ tables[1][i] = &s->ac_vlc_2[ac_c_table];
+ }
+ for (i = 15; i <= 27; i++) {
+ tables[0][i] = &s->ac_vlc_3[ac_y_table];
+ tables[1][i] = &s->ac_vlc_3[ac_c_table];
+ }
+ for (i = 28; i <= 63; i++) {
+ tables[0][i] = &s->ac_vlc_4[ac_y_table];
+ tables[1][i] = &s->ac_vlc_4[ac_c_table];
+ }
+
+ vp4_set_tokens_base(s);
+
+ memset(last_dc, 0, sizeof(last_dc));
+
+ for (plane = 0; plane < ((s->avctx->flags & AV_CODEC_FLAG_GRAY) ? 1 : 3); plane++) {
+ memset(eob_tracker, 0, sizeof(eob_tracker));
+
+ /* initialise dc prediction */
+ for (i = 0; i < s->fragment_width[!!plane]; i++)
+ vp4_dc_predictor_reset(&s->dc_pred_row[i]);
+
+ for (j = 0; j < 6; j++)
+ for (i = 0; i < 6; i++)
+ vp4_dc_predictor_reset(&dc_pred[j][i]);
+
+ for (sb_y = 0; sb_y * 4 < s->fragment_height[!!plane]; sb_y++) {
+ for (sb_x = 0; sb_x *4 < s->fragment_width[!!plane]; sb_x++) {
+ vp4_dc_pred_before(s, dc_pred, sb_x);
+ for (j = 0; j < 16; j++) {
+ int hx = hilbert_offset[j][0];
+ int hy = hilbert_offset[j][1];
+ int x = 4 * sb_x + hx;
+ int y = 4 * sb_y + hy;
+ VP4Predictor *this_dc_pred = &dc_pred[hy + 1][hx + 1];
+ int fragment, dc_block_type;
+
+ if (x >= s->fragment_width[!!plane] || y >= s->fragment_height[!!plane])
+ continue;
+
+ fragment = s->fragment_start[plane] + y * s->fragment_width[!!plane] + x;
+
+ if (s->all_fragments[fragment].coding_method == MODE_COPY)
+ continue;
+
+ if (vp4_unpack_vlcs(s, gb, tables[!!plane], plane, eob_tracker, fragment) < 0)
+ return -1;
+
+ dc_block_type = vp4_pred_block_type_map[s->all_fragments[fragment].coding_method];
+
+ s->all_fragments[fragment].dc +=
+ vp4_dc_pred(s, this_dc_pred, last_dc, dc_block_type, plane);
+
+ this_dc_pred->type = dc_block_type,
+ this_dc_pred->dc = last_dc[dc_block_type] = s->all_fragments[fragment].dc;
+ }
+ vp4_dc_pred_after(s, dc_pred, sb_x);
+ }
+ }
+ }
+
+ vp4_set_tokens_base(s);
+
+ return 0;
+}
+#endif
+