The RLTable API in rl.c is not well designed for codecs with an explicit end-of-block code. ff_h261_rl_tcoeff's vlc has the EOB code as first element (presumably so that the decoder can check for it via "if (level == 0)") and this implies that the indices returned by get_rl_index() are off by one for run == 0 which is therefore explicitly checked. This commit changes this by adding a simple LUT for the values not requiring escaping. It is easy to directly include the sign bit into this, so this has also been done.
Showing the changes to libavcodec (1 of 1 file). Show all
Unified · Split
| @@ -36,6 +36,14 @@ · 35 unmodified lines | ||
| 36 | 36 | #include "h261enc.h" |
| 37 | 37 | #include "mpegvideoenc.h" |
| 38 | 38 | |
| 39 | +#define H261_MAX_RUN 26 | |
| 40 | +#define H261_MAX_LEVEL 15 | |
| 41 | + | |
| 42 | +static struct VLCLUT { | |
| 43 | + uint8_t len; | |
| 44 | + uint16_t code; | |
| 45 | +} vlc_lut[H261_MAX_RUN + 1][32 /* 0..2 * H261_MAX_LEN are used */]; | |
| 46 | + | |
| 39 | 47 | static uint8_t uni_h261_rl_len [64*64*2*2]; |
| 40 | 48 | #define UNI_ENC_INDEX(last,run,level) ((last)*128*64 + (run)*128 + (level)) |
| 41 | 49 | |
| @@ -165,10 +173,8 @@ static inline int get_cbp(MpegEncContext *s, int16_t block[6][64]) · 123 unmodified lines | ||
| 165 | 173 | static void h261_encode_block(H261EncContext *h, int16_t *block, int n) |
| 166 | 174 | { |
| 167 | 175 | MpegEncContext *const s = &h->s; |
| 168 | − int level, run, i, j, last_index, last_non_zero, sign, slevel, code; | |
| 169 | − const RLTable *rl; | |
| 176 | + int level, run, i, j, last_index, last_non_zero; | |
| 170 | 177 | |
| 171 | − rl = &ff_h261_rl_tcoeff; | |
| 172 | 178 | if (s->mb_intra) { |
| 173 | 179 | /* DC coef */ |
| 174 | 180 | level = block[0]; |
| @@ -204,24 +210,18 @@ static void h261_encode_block(H261EncContext *h, int16_t *block, int n) · 29 unmodified lines | ||
| 204 | 210 | level = block[j]; |
| 205 | 211 | if (level) { |
| 206 | 212 | run = i - last_non_zero - 1; |
| 207 | − sign = 0; | |
| 208 | − slevel = level; | |
| 209 | − if (level < 0) { | |
| 210 | − sign = 1; | |
| 211 | − level = -level; | |
| 212 | − } | |
| 213 | − code = get_rl_index(rl, 0 /*no last in H.261, EOB is used*/, | |
| 214 | − run, level); | |
| 215 | − if (run == 0 && level < 16) | |
| 216 | − code += 1; | |
| 217 | − put_bits(&s->pb, rl->table_vlc[code][1], rl->table_vlc[code][0]); | |
| 218 | − if (code == rl->n) { | |
| 219 | − put_bits(&s->pb, 6, run); | |
| 220 | − av_assert1(slevel != 0); | |
| 221 | − av_assert1(level <= 127); | |
| 222 | − put_sbits(&s->pb, 8, slevel); | |
| 213 | + | |
| 214 | + if (run <= H261_MAX_RUN && | |
| 215 | + (unsigned)(level + H261_MAX_LEVEL) <= 2 * H261_MAX_LEVEL && | |
| 216 | + vlc_lut[run][level + H261_MAX_LEVEL].len) { | |
| 217 | + put_bits(&s->pb, vlc_lut[run][level + H261_MAX_LEVEL].len, | |
| 218 | + vlc_lut[run][level + H261_MAX_LEVEL].code); | |
| 223 | 219 | } else { |
| 224 | − put_bits(&s->pb, 1, sign); | |
| 220 | + /* Escape */ | |
| 221 | + put_bits(&s->pb, 6 + 6, (1 << 6) | run); | |
| 222 | + av_assert1(level != 0); | |
| 223 | + av_assert1(FFABS(level) <= 127); | |
| 224 | + put_sbits(&s->pb, 8, level); | |
| 225 | 225 | } |
| 226 | 226 | last_non_zero = i; |
| 227 | 227 | } |
| @@ -365,6 +365,17 @@ static av_cold void h261_encode_init_static(void) · 137 unmodified lines | ||
| 365 | 365 | |
| 366 | 366 | ff_rl_init(&ff_h261_rl_tcoeff, h261_rl_table_store); |
| 367 | 367 | init_uni_h261_rl_tab(&ff_h261_rl_tcoeff, uni_h261_rl_len); |
| 368 | + | |
| 369 | + // The following loop is over the ordinary elements, not EOB or escape. | |
| 370 | + for (size_t i = 1; i < FF_ARRAY_ELEMS(ff_h261_tcoeff_vlc) - 1; i++) { | |
| 371 | + unsigned run = ff_h261_tcoeff_run[i]; | |
| 372 | + unsigned level = ff_h261_tcoeff_level[i]; | |
| 373 | + unsigned len = ff_h261_tcoeff_vlc[i][1] + 1 /* sign */; | |
| 374 | + unsigned code = ff_h261_tcoeff_vlc[i][0]; | |
| 375 | + | |
| 376 | + vlc_lut[run][H261_MAX_LEVEL + level] = (struct VLCLUT){ len, code << 1 }; | |
| 377 | + vlc_lut[run][H261_MAX_LEVEL - level] = (struct VLCLUT){ len, (code << 1) | 1 }; | |
| 378 | + } | |
| 368 | 379 | } |
| 369 | 380 | |
| 370 | 381 | av_cold int ff_h261_encode_init(MpegEncContext *s) |