[FFmpeg-cvslog] avcodec/exr: simplify piz decompression
Paul B Mahol
git at videolan.org
Wed Feb 24 18:11:28 EET 2021
ffmpeg | branch: master | Paul B Mahol <onemda at gmail.com> | Sat Feb 20 02:35:06 2021 +0100| [767d3f7dcf818a88b7fa9c510b8721f247faee3c] | committer: Paul B Mahol
avcodec/exr: simplify piz decompression
Note that >32 codes are no longer supported, give
proper error code if such scenario ever happens.
> http://git.videolan.org/gitweb.cgi/ffmpeg.git/?a=commit;h=767d3f7dcf818a88b7fa9c510b8721f247faee3c
---
libavcodec/exr.c | 251 ++++++++++++++++++++-----------------------------------
1 file changed, 89 insertions(+), 162 deletions(-)
diff --git a/libavcodec/exr.c b/libavcodec/exr.c
index cacdff5774..5f99d9d5ab 100644
--- a/libavcodec/exr.c
+++ b/libavcodec/exr.c
@@ -91,6 +91,12 @@ enum ExrTileLevelRound {
EXR_TILE_ROUND_UNKNOWN,
};
+typedef struct HuffEntry {
+ uint8_t len;
+ uint16_t sym;
+ uint32_t code;
+} HuffEntry;
+
typedef struct EXRChannel {
int xsub, ysub;
enum ExrPixelType pixel_type;
@@ -116,6 +122,11 @@ typedef struct EXRThreadData {
int ysize, xsize;
int channel_line_size;
+
+ int run_sym;
+ HuffEntry *he;
+ uint64_t *freq;
+ VLC vlc;
} EXRThreadData;
typedef struct EXRContext {
@@ -319,25 +330,15 @@ static void apply_lut(const uint16_t *lut, uint16_t *dst, int dsize)
}
#define HUF_ENCBITS 16 // literal (value) bit length
-#define HUF_DECBITS 14 // decoding bit size (>= 8)
-
#define HUF_ENCSIZE ((1 << HUF_ENCBITS) + 1) // encoding table size
-#define HUF_DECSIZE (1 << HUF_DECBITS) // decoding table size
-#define HUF_DECMASK (HUF_DECSIZE - 1)
-typedef struct HufDec {
- int len;
- int lit;
- int *p;
-} HufDec;
-
-static void huf_canonical_code_table(uint64_t *hcode)
+static void huf_canonical_code_table(uint64_t *freq)
{
uint64_t c, n[59] = { 0 };
int i;
- for (i = 0; i < HUF_ENCSIZE; ++i)
- n[hcode[i]] += 1;
+ for (i = 0; i < HUF_ENCSIZE; i++)
+ n[freq[i]] += 1;
c = 0;
for (i = 58; i > 0; --i) {
@@ -347,10 +348,10 @@ static void huf_canonical_code_table(uint64_t *hcode)
}
for (i = 0; i < HUF_ENCSIZE; ++i) {
- int l = hcode[i];
+ int l = freq[i];
if (l > 0)
- hcode[i] = l | (n[l]++ << 6);
+ freq[i] = l | (n[l]++ << 6);
}
}
@@ -360,7 +361,7 @@ static void huf_canonical_code_table(uint64_t *hcode)
#define LONGEST_LONG_RUN (255 + SHORTEST_LONG_RUN)
static int huf_unpack_enc_table(GetByteContext *gb,
- int32_t im, int32_t iM, uint64_t *hcode)
+ int32_t im, int32_t iM, uint64_t *freq)
{
GetBitContext gbit;
int ret = init_get_bits8(&gbit, gb->buffer, bytestream2_get_bytes_left(gb));
@@ -368,7 +369,7 @@ static int huf_unpack_enc_table(GetByteContext *gb,
return ret;
for (; im <= iM; im++) {
- uint64_t l = hcode[im] = get_bits(&gbit, 6);
+ uint64_t l = freq[im] = get_bits(&gbit, 6);
if (l == LONG_ZEROCODE_RUN) {
int zerun = get_bits(&gbit, 8) + SHORTEST_LONG_RUN;
@@ -377,7 +378,7 @@ static int huf_unpack_enc_table(GetByteContext *gb,
return AVERROR_INVALIDDATA;
while (zerun--)
- hcode[im++] = 0;
+ freq[im++] = 0;
im--;
} else if (l >= SHORT_ZEROCODE_RUN) {
@@ -387,161 +388,91 @@ static int huf_unpack_enc_table(GetByteContext *gb,
return AVERROR_INVALIDDATA;
while (zerun--)
- hcode[im++] = 0;
+ freq[im++] = 0;
im--;
}
}
bytestream2_skip(gb, (get_bits_count(&gbit) + 7) / 8);
- huf_canonical_code_table(hcode);
+ huf_canonical_code_table(freq);
return 0;
}
-static int huf_build_dec_table(const uint64_t *hcode, int im,
- int iM, HufDec *hdecod)
+static int huf_build_dec_table(EXRContext *s,
+ EXRThreadData *td, int im, int iM)
{
- for (; im <= iM; im++) {
- uint64_t c = hcode[im] >> 6;
- int i, l = hcode[im] & 63;
-
- if (c >> l)
- return AVERROR_INVALIDDATA;
-
- if (l > HUF_DECBITS) {
- HufDec *pl = hdecod + (c >> (l - HUF_DECBITS));
- if (pl->len)
- return AVERROR_INVALIDDATA;
-
- pl->lit++;
-
- pl->p = av_realloc(pl->p, pl->lit * sizeof(int));
- if (!pl->p)
- return AVERROR(ENOMEM);
-
- pl->p[pl->lit - 1] = im;
- } else if (l) {
- HufDec *pl = hdecod + (c << (HUF_DECBITS - l));
-
- for (i = 1 << (HUF_DECBITS - l); i > 0; i--, pl++) {
- if (pl->len || pl->p)
- return AVERROR_INVALIDDATA;
- pl->len = l;
- pl->lit = im;
- }
+ int j = 0;
+
+ td->run_sym = -1;
+ for (int i = im; i < iM; i++) {
+ td->he[j].sym = i;
+ td->he[j].len = td->freq[i] & 63;
+ td->he[j].code = td->freq[i] >> 6;
+ if (td->he[j].len > 32) {
+ avpriv_request_sample(s->avctx, "Too big code length");
+ return AVERROR_PATCHWELCOME;
}
+ if (td->he[j].len > 0)
+ j++;
+ else
+ td->run_sym = i;
}
- return 0;
-}
-
-#define get_char(c, lc, gb) \
-{ \
- c = (c << 8) | bytestream2_get_byte(gb); \
- lc += 8; \
-}
+ if (td->run_sym == -1) {
+ avpriv_request_sample(s->avctx, "No place for run symbol");
+ return AVERROR_PATCHWELCOME;
+ }
-#define get_code(po, rlc, c, lc, gb, out, oe, outb) \
-{ \
- if (po == rlc) { \
- if (lc < 8) \
- get_char(c, lc, gb); \
- lc -= 8; \
- \
- cs = c >> lc; \
- \
- if (out + cs > oe || out == outb) \
- return AVERROR_INVALIDDATA; \
- \
- s = out[-1]; \
- \
- while (cs-- > 0) \
- *out++ = s; \
- } else if (out < oe) { \
- *out++ = po; \
- } else { \
- return AVERROR_INVALIDDATA; \
- } \
+ td->he[j].sym = td->run_sym;
+ td->he[j].len = td->freq[iM] & 63;
+ if (td->he[j].len > 32) {
+ avpriv_request_sample(s->avctx, "Too big code length");
+ return AVERROR_PATCHWELCOME;
+ }
+ td->he[j].code = td->freq[iM] >> 6;
+ j++;
+
+ ff_free_vlc(&td->vlc);
+ return ff_init_vlc_sparse(&td->vlc, 12, j,
+ &td->he[0].len, sizeof(td->he[0]), sizeof(td->he[0].len),
+ &td->he[0].code, sizeof(td->he[0]), sizeof(td->he[0].code),
+ &td->he[0].sym, sizeof(td->he[0]), sizeof(td->he[0].sym), 0);
}
-static int huf_decode(const uint64_t *hcode, const HufDec *hdecod,
- GetByteContext *gb, int nbits,
- int rlc, int no, uint16_t *out)
+static int huf_decode(VLC *vlc, GetByteContext *gb, int nbits, int run_sym,
+ int no, uint16_t *out)
{
- uint64_t c = 0;
- uint16_t *outb = out;
- uint16_t *oe = out + no;
- const uint8_t *ie = gb->buffer + (nbits + 7) / 8; // input byte size
- uint8_t cs;
- uint16_t s;
- int i, lc = 0;
-
- while (gb->buffer < ie) {
- get_char(c, lc, gb);
-
- while (lc >= HUF_DECBITS) {
- const HufDec pl = hdecod[(c >> (lc - HUF_DECBITS)) & HUF_DECMASK];
-
- if (pl.len) {
- lc -= pl.len;
- get_code(pl.lit, rlc, c, lc, gb, out, oe, outb);
- } else {
- int j;
-
- if (!pl.p)
- return AVERROR_INVALIDDATA;
-
- for (j = 0; j < pl.lit; j++) {
- int l = hcode[pl.p[j]] & 63;
-
- while (lc < l && bytestream2_get_bytes_left(gb) > 0)
- get_char(c, lc, gb);
-
- if (lc >= l) {
- if ((hcode[pl.p[j]] >> 6) ==
- ((c >> (lc - l)) & ((1LL << l) - 1))) {
- lc -= l;
- get_code(pl.p[j], rlc, c, lc, gb, out, oe, outb);
- break;
- }
- }
- }
-
- if (j == pl.lit)
- return AVERROR_INVALIDDATA;
- }
- }
- }
+ GetBitContext gbit;
+ int oe = 0;
- i = (8 - nbits) & 7;
- c >>= i;
- lc -= i;
+ init_get_bits(&gbit, gb->buffer, nbits);
+ while (get_bits_left(&gbit) > 0 && oe < no) {
+ uint16_t x = get_vlc2(&gbit, vlc->table, 12, 2);
- while (lc > 0) {
- const HufDec pl = hdecod[(c << (HUF_DECBITS - lc)) & HUF_DECMASK];
+ if (x == run_sym) {
+ int run = get_bits(&gbit, 8);
+ uint16_t fill = out[oe - 1];
- if (pl.len && lc >= pl.len) {
- lc -= pl.len;
- get_code(pl.lit, rlc, c, lc, gb, out, oe, outb);
+ while (run-- > 0)
+ out[oe++] = fill;
} else {
- return AVERROR_INVALIDDATA;
+ out[oe++] = x;
}
}
- if (out - outb != no)
- return AVERROR_INVALIDDATA;
return 0;
}
-static int huf_uncompress(GetByteContext *gb,
+static int huf_uncompress(EXRContext *s,
+ EXRThreadData *td,
+ GetByteContext *gb,
uint16_t *dst, int dst_size)
{
int32_t src_size, im, iM;
uint32_t nBits;
- uint64_t *freq;
- HufDec *hdec;
- int ret, i;
+ int ret;
src_size = bytestream2_get_le32(gb);
im = bytestream2_get_le32(gb);
@@ -555,34 +486,27 @@ static int huf_uncompress(GetByteContext *gb,
bytestream2_skip(gb, 4);
- freq = av_mallocz_array(HUF_ENCSIZE, sizeof(*freq));
- hdec = av_mallocz_array(HUF_DECSIZE, sizeof(*hdec));
- if (!freq || !hdec) {
+ if (!td->freq)
+ td->freq = av_malloc_array(HUF_ENCSIZE, sizeof(*td->freq));
+ if (!td->he)
+ td->he = av_calloc(HUF_ENCSIZE, sizeof(*td->he));
+ if (!td->freq || !td->he) {
ret = AVERROR(ENOMEM);
- goto fail;
+ return ret;
}
- if ((ret = huf_unpack_enc_table(gb, im, iM, freq)) < 0)
- goto fail;
+ memset(td->freq, 0, sizeof(*td->freq) * HUF_ENCSIZE);
+ if ((ret = huf_unpack_enc_table(gb, im, iM, td->freq)) < 0)
+ return ret;
if (nBits > 8 * bytestream2_get_bytes_left(gb)) {
ret = AVERROR_INVALIDDATA;
- goto fail;
+ return ret;
}
- if ((ret = huf_build_dec_table(freq, im, iM, hdec)) < 0)
- goto fail;
- ret = huf_decode(freq, hdec, gb, nBits, iM, dst_size, dst);
-
-fail:
- for (i = 0; i < HUF_DECSIZE; i++)
- if (hdec)
- av_freep(&hdec[i].p);
-
- av_free(freq);
- av_free(hdec);
-
- return ret;
+ if ((ret = huf_build_dec_table(s, td, im, iM)) < 0)
+ return ret;
+ return huf_decode(&td->vlc, gb, nBits, td->run_sym, dst_size, dst);
}
static inline void wdec14(uint16_t l, uint16_t h, uint16_t *a, uint16_t *b)
@@ -730,7 +654,7 @@ static int piz_uncompress(EXRContext *s, const uint8_t *src, int ssize,
maxval = reverse_lut(td->bitmap, td->lut);
- ret = huf_uncompress(&gb, tmp, dsize / sizeof(uint16_t));
+ ret = huf_uncompress(s, td, &gb, tmp, dsize / sizeof(uint16_t));
if (ret)
return ret;
@@ -2045,6 +1969,9 @@ static av_cold int decode_end(AVCodecContext *avctx)
av_freep(&td->tmp);
av_freep(&td->bitmap);
av_freep(&td->lut);
+ av_freep(&td->he);
+ av_freep(&td->freq);
+ ff_free_vlc(&td->vlc);
}
av_freep(&s->thread_data);
More information about the ffmpeg-cvslog
mailing list