From dc73c7adc0284871af34100a6062378c07a63569 Mon Sep 17 00:00:00 2001 From: Michael Niedermayer Date: Fri, 12 Jun 2015 03:06:56 +0200 Subject: avcodec/jpeg2000dec: Fix Selective arithmetic coding bypass and Multiple codeword segments These 2 are highly related so they are in the same commit Fixes part of Ticket4605 Fixes p0_04.j2k Signed-off-by: Michael Niedermayer --- libavcodec/jpeg2000.c | 2 +- libavcodec/jpeg2000.h | 25 ++++++++++++-- libavcodec/jpeg2000dec.c | 85 ++++++++++++++++++++++++++++++++++-------------- 3 files changed, 85 insertions(+), 27 deletions(-) diff --git a/libavcodec/jpeg2000.c b/libavcodec/jpeg2000.c index 38df58dd1d..9304536291 100644 --- a/libavcodec/jpeg2000.c +++ b/libavcodec/jpeg2000.c @@ -468,7 +468,7 @@ int ff_jpeg2000_init_component(Jpeg2000Component *comp, cblk->zero = 0; cblk->lblock = 3; cblk->length = 0; - cblk->lengthinc = 0; + memset(cblk->lengthinc, 0, sizeof(cblk->lengthinc)); cblk->npasses = 0; } } diff --git a/libavcodec/jpeg2000.h b/libavcodec/jpeg2000.h index 46067c871c..6ff0e90923 100644 --- a/libavcodec/jpeg2000.h +++ b/libavcodec/jpeg2000.h @@ -163,11 +163,15 @@ typedef struct Jpeg2000Cblk { uint8_t ninclpasses; // number coding of passes included in codestream uint8_t nonzerobits; uint16_t length; - uint16_t lengthinc; + uint16_t lengthinc[JPEG2000_MAX_PASSES]; + uint8_t nb_lengthinc; uint8_t lblock; uint8_t zero; uint8_t data[8192]; - Jpeg2000Pass passes[100]; + int nb_terminations; + int nb_terminationsinc; + int data_start[JPEG2000_MAX_PASSES]; + Jpeg2000Pass passes[JPEG2000_MAX_PASSES]; uint16_t coord[2][2]; // border coordinates {{x0, x1}, {y0, y1}} } Jpeg2000Cblk; // code block @@ -264,4 +268,21 @@ void ff_jpeg2000_reinit(Jpeg2000Component *comp, Jpeg2000CodingStyle *codsty); void ff_jpeg2000_cleanup(Jpeg2000Component *comp, Jpeg2000CodingStyle *codsty); +static inline int needs_termination(int style, int passno) { + if (style & JPEG2000_CBLK_BYPASS) { + int type = passno % 3; + passno /= 3; + if (type == 0 && passno > 2) + return 2; + if (type == 2 && passno > 2) + return 1; + if (style & JPEG2000_CBLK_TERMALL) { + return passno > 2 ? 2 : 1; + } + } + if (style & JPEG2000_CBLK_TERMALL) + return 1; + return 0; +} + #endif /* AVCODEC_JPEG2000_H */ diff --git a/libavcodec/jpeg2000dec.c b/libavcodec/jpeg2000dec.c index 7e62880a01..507893a920 100644 --- a/libavcodec/jpeg2000dec.c +++ b/libavcodec/jpeg2000dec.c @@ -764,6 +764,7 @@ static int jpeg2000_decode_packet(Jpeg2000DecoderContext *s, int layno, uint8_t *expn, int numgbits) { int bandno, cblkno, ret, nb_code_blocks; + int cwsno; if (!(ret = get_bits(s, 1))) { jpeg2000_flush(s); @@ -819,16 +820,32 @@ static int jpeg2000_decode_packet(Jpeg2000DecoderContext *s, } cblk->lblock += llen; - if ((ret = get_bits(s, av_log2(newpasses) + cblk->lblock)) < 0) - return ret; - if (ret > sizeof(cblk->data)) { - avpriv_request_sample(s->avctx, - "Block with lengthinc greater than %"SIZE_SPECIFIER"", - sizeof(cblk->data)); - return AVERROR_PATCHWELCOME; - } - cblk->lengthinc = ret; - cblk->npasses += newpasses; + + cblk->nb_lengthinc = 0; + cblk->nb_terminationsinc = 0; + do { + int newpasses1 = 0; + + while (newpasses1 < newpasses) { + newpasses1 ++; + if (needs_termination(codsty->cblk_style, cblk->npasses + newpasses1 - 1)) { + cblk->nb_terminationsinc ++; + break; + } + } + + if ((ret = get_bits(s, av_log2(newpasses1) + cblk->lblock)) < 0) + return ret; + if (ret > sizeof(cblk->data)) { + avpriv_request_sample(s->avctx, + "Block with lengthinc greater than %"SIZE_SPECIFIER"", + sizeof(cblk->data)); + return AVERROR_PATCHWELCOME; + } + cblk->lengthinc[cblk->nb_lengthinc++] = ret; + cblk->npasses += newpasses1; + newpasses -= newpasses1; + } while(newpasses); } } jpeg2000_flush(s); @@ -847,18 +864,27 @@ static int jpeg2000_decode_packet(Jpeg2000DecoderContext *s, nb_code_blocks = prec->nb_codeblocks_height * prec->nb_codeblocks_width; for (cblkno = 0; cblkno < nb_code_blocks; cblkno++) { Jpeg2000Cblk *cblk = prec->cblk + cblkno; - if ( bytestream2_get_bytes_left(&s->g) < cblk->lengthinc - || sizeof(cblk->data) < cblk->length + cblk->lengthinc + 2 - ) { - av_log(s->avctx, AV_LOG_ERROR, - "Block length %"PRIu16" or lengthinc %d is too large\n", - cblk->length, cblk->lengthinc); - return AVERROR_INVALIDDATA; - } + for (cwsno = 0; cwsno < cblk->nb_lengthinc; cwsno ++) { + if ( bytestream2_get_bytes_left(&s->g) < cblk->lengthinc[cwsno] + || sizeof(cblk->data) < cblk->length + cblk->lengthinc[cwsno] + 4 + ) { + av_log(s->avctx, AV_LOG_ERROR, + "Block length %"PRIu16" or lengthinc %d is too large\n", + cblk->length, cblk->lengthinc[cwsno]); + return AVERROR_INVALIDDATA; + } - bytestream2_get_bufferu(&s->g, cblk->data + cblk->length, cblk->lengthinc); - cblk->length += cblk->lengthinc; - cblk->lengthinc = 0; + bytestream2_get_bufferu(&s->g, cblk->data + cblk->length, cblk->lengthinc[cwsno]); + cblk->length += cblk->lengthinc[cwsno]; + cblk->lengthinc[cwsno] = 0; + if (cblk->nb_terminationsinc) { + cblk->nb_terminationsinc--; + cblk->nb_terminations++; + cblk->data[cblk->length++] = 0xFF; + cblk->data[cblk->length++] = 0xFF; + cblk->data_start[cblk->nb_terminations] = cblk->length; + } + } } } return 0; @@ -1012,7 +1038,7 @@ static void decode_sigpass(Jpeg2000T1Context *t1, int width, int height, flags_mask &= ~(JPEG2000_T1_SIG_S | JPEG2000_T1_SIG_SW | JPEG2000_T1_SIG_SE); if (ff_mqc_decode(&t1->mqc, t1->mqc.cx_states + ff_jpeg2000_getsigctxno(t1->flags[y+1][x+1] & flags_mask, bandno))) { int xorbit, ctxno = ff_jpeg2000_getsgnctxno(t1->flags[y+1][x+1], &xorbit); - if (bpass_csty_symbol) + if (t1->mqc.raw) t1->data[y][x] = ff_mqc_decode(&t1->mqc, t1->mqc.cx_states + ctxno) ? -mask : mask; else t1->data[y][x] = (ff_mqc_decode(&t1->mqc, t1->mqc.cx_states + ctxno) ^ xorbit) ? @@ -1116,9 +1142,11 @@ static int decode_cblk(Jpeg2000DecoderContext *s, Jpeg2000CodingStyle *codsty, int width, int height, int bandpos) { int passno = cblk->npasses, pass_t = 2, bpno = cblk->nonzerobits - 1, y; - int clnpass_cnt = 0; + int pass_cnt = 0; int bpass_csty_symbol = codsty->cblk_style & JPEG2000_CBLK_BYPASS; int vert_causal_ctx_csty_symbol = codsty->cblk_style & JPEG2000_CBLK_VSC; + int term_cnt = 0; + int coder_type; av_assert0(width <= JPEG2000_MAX_CBLKW); av_assert0(height <= JPEG2000_MAX_CBLKH); @@ -1141,24 +1169,33 @@ static int decode_cblk(Jpeg2000DecoderContext *s, Jpeg2000CodingStyle *codsty, switch(pass_t) { case 0: decode_sigpass(t1, width, height, bpno + 1, bandpos, - bpass_csty_symbol && (clnpass_cnt >= 4), + bpass_csty_symbol && (pass_cnt >= 3*3), vert_causal_ctx_csty_symbol); break; case 1: decode_refpass(t1, width, height, bpno + 1); break; case 2: + av_assert2(!t1->mqc.raw); decode_clnpass(s, t1, width, height, bpno + 1, bandpos, codsty->cblk_style & JPEG2000_CBLK_SEGSYM, vert_causal_ctx_csty_symbol); break; } + if ((coder_type = needs_termination(codsty->cblk_style, pass_cnt))) { + if (term_cnt >= cblk->nb_terminations) { + av_log(s->avctx, AV_LOG_ERROR, "Missing needed termination \n"); + return AVERROR_INVALIDDATA; + } + ff_mqc_initdec(&t1->mqc, cblk->data + cblk->data_start[++term_cnt], coder_type == 2, 0); + } pass_t++; if (pass_t == 3) { bpno--; pass_t = 0; } + pass_cnt ++; } return 0; } -- cgit v1.2.3