diff options
author | Loren Merritt <lorenm@u.washington.edu> | 2008-12-11 00:26:00 +0300 |
---|---|---|
committer | Loren Merritt <lorenm@u.washington.edu> | 2008-12-11 00:26:00 +0300 |
commit | 5fac277602ebab5990c4d20342a4e55bb7c43b93 (patch) | |
tree | 4372e8a189c0a2c919bd5e6c8e012b533df59305 /libavcodec | |
parent | 8153f14444519e0aec299678ad9bc4268d55acff (diff) |
fix progressive jpeg:
support refinement passes
remove intermediate clipping
remove redundant idct
Originally committed as revision 16044 to svn://svn.ffmpeg.org/ffmpeg/trunk
Diffstat (limited to 'libavcodec')
-rw-r--r-- | libavcodec/mjpegdec.c | 243 | ||||
-rw-r--r-- | libavcodec/mjpegdec.h | 4 |
2 files changed, 202 insertions, 45 deletions
diff --git a/libavcodec/mjpegdec.c b/libavcodec/mjpegdec.c index e8a34ef2ba..54beb76dae 100644 --- a/libavcodec/mjpegdec.c +++ b/libavcodec/mjpegdec.c @@ -351,9 +351,17 @@ int ff_mjpeg_decode_sof(MJpegDecodeContext *s) /* totally blank picture as progressive JPEG will only add details to it */ if(s->progressive){ - memset(s->picture.data[0], 0, s->picture.linesize[0] * s->height); - memset(s->picture.data[1], 0, s->picture.linesize[1] * s->height >> (s->v_max - s->v_count[1])); - memset(s->picture.data[2], 0, s->picture.linesize[2] * s->height >> (s->v_max - s->v_count[2])); + int bw = (width + s->h_max*8-1) / (s->h_max*8); + int bh = (height + s->v_max*8-1) / (s->v_max*8); + for(i=0; i<s->nb_components; i++) { + int size = bw * bh * s->h_count[i] * s->v_count[i]; + av_freep(&s->blocks[i]); + av_freep(&s->last_nnz[i]); + s->blocks[i] = av_malloc(size * sizeof(**s->blocks)); + s->last_nnz[i] = av_mallocz(size * sizeof(**s->last_nnz)); + s->block_stride[i] = bw * s->h_count[i]; + } + memset(s->coefs_finished, 0, sizeof(s->coefs_finished)); } return 0; } @@ -432,27 +440,29 @@ static int decode_block(MJpegDecodeContext *s, DCTELEM *block, return 0; } +static int decode_dc_progressive(MJpegDecodeContext *s, DCTELEM *block, int component, + int dc_index, int16_t *quant_matrix, int Al) +{ + int val; + memset(block, 0, 64*sizeof(DCTELEM)); + val = mjpeg_decode_dc(s, dc_index); + if (val == 0xffff) { + av_log(s->avctx, AV_LOG_ERROR, "error dc\n"); + return -1; + } + val = (val * quant_matrix[0] << Al) + s->last_dc[component]; + s->last_dc[component] = val; + block[0] = val; + return 0; +} + /* decode block and dequantize - progressive JPEG version */ -static int decode_block_progressive(MJpegDecodeContext *s, DCTELEM *block, - int component, int dc_index, int ac_index, int16_t *quant_matrix, - int ss, int se, int Ah, int Al, int *EOBRUN) +static int decode_block_progressive(MJpegDecodeContext *s, DCTELEM *block, uint8_t *last_nnz, + int ac_index, int16_t *quant_matrix, + int ss, int se, int Al, int *EOBRUN) { int code, i, j, level, val, run; - /* DC coef */ - if(!ss){ - val = mjpeg_decode_dc(s, dc_index); - if (val == 0xffff) { - av_log(s->avctx, AV_LOG_ERROR, "error dc\n"); - return -1; - } - val = (val * quant_matrix[0] << Al) + s->last_dc[component]; - }else - val = 0; - s->last_dc[component] = val; - block[0] = val; - if(!se) return 0; - /* AC coefs */ if(*EOBRUN){ (*EOBRUN)--; return 0; @@ -505,9 +515,100 @@ static int decode_block_progressive(MJpegDecodeContext *s, DCTELEM *block, } } CLOSE_READER(re, &s->gb)} + if(i > *last_nnz) + *last_nnz = i; + return 0; +} + +#define REFINE_BIT(j) {\ + UPDATE_CACHE(re, &s->gb);\ + sign = block[j]>>15;\ + block[j] += SHOW_UBITS(re, &s->gb, 1) * ((quant_matrix[j]^sign)-sign) << Al;\ + LAST_SKIP_BITS(re, &s->gb, 1);\ +} + +#define ZERO_RUN \ +for(;;i++) {\ + if(i > last) {\ + i += run;\ + if(i > se) {\ + av_log(s->avctx, AV_LOG_ERROR, "error count: %d\n", i);\ + return -1;\ + }\ + break;\ + }\ + j = s->scantable.permutated[i];\ + if(block[j])\ + REFINE_BIT(j)\ + else if(run-- == 0)\ + break;\ +} + +/* decode block and dequantize - progressive JPEG refinement pass */ +static int decode_block_refinement(MJpegDecodeContext *s, DCTELEM *block, uint8_t *last_nnz, + int ac_index, int16_t *quant_matrix, + int ss, int se, int Al, int *EOBRUN) +{ + int code, i=ss, j, sign, val, run; + int last = FFMIN(se, *last_nnz); + + OPEN_READER(re, &s->gb); + if(*EOBRUN) + (*EOBRUN)--; + else { + for(;;i++) { + UPDATE_CACHE(re, &s->gb); + GET_VLC(code, re, &s->gb, s->vlcs[1][ac_index].table, 9, 2) + /* Progressive JPEG use AC coeffs from zero and this decoder sets offset 16 by default */ + code -= 16; + if(code & 0xF) { + run = ((unsigned) code) >> 4; + UPDATE_CACHE(re, &s->gb); + val = SHOW_UBITS(re, &s->gb, 1); + LAST_SKIP_BITS(re, &s->gb, 1); + ZERO_RUN; + j = s->scantable.permutated[i]; + val--; + block[j] = ((quant_matrix[j]^val)-val) << Al; + if(i == se) { + if(i > *last_nnz) + *last_nnz = i; + CLOSE_READER(re, &s->gb) + return 0; + } + }else{ + run = ((unsigned) code) >> 4; + if(run == 0xF){ + ZERO_RUN; + }else{ + val = run; + run = (1 << run); + if(val) { + UPDATE_CACHE(re, &s->gb); + run += SHOW_UBITS(re, &s->gb, val); + LAST_SKIP_BITS(re, &s->gb, val); + } + *EOBRUN = run - 1; + break; + } + } + } + + if(i > *last_nnz) + *last_nnz = i; + } + + for(;i<=last;i++) { + j = s->scantable.permutated[i]; + if(block[j]) + REFINE_BIT(j) + } + CLOSE_READER(re, &s->gb); return 0; } +#undef REFINE_BIT +#undef ZERO_RUN static int ljpeg_decode_rgb_scan(MJpegDecodeContext *s, int predictor, int point_transform){ int i, mb_x, mb_y; @@ -660,18 +761,16 @@ static int ljpeg_decode_yuv_scan(MJpegDecodeContext *s, int predictor, int point return 0; } -static int mjpeg_decode_scan(MJpegDecodeContext *s, int nb_components, int ss, int se, int Ah, int Al){ +static int mjpeg_decode_scan(MJpegDecodeContext *s, int nb_components, int Ah, int Al){ int i, mb_x, mb_y; - int EOBRUN = 0; uint8_t* data[MAX_COMPONENTS]; int linesize[MAX_COMPONENTS]; - if(Ah) return 0; /* TODO decode refinement planes too */ - for(i=0; i < nb_components; i++) { int c = s->comp_index[i]; data[c] = s->picture.data[c]; linesize[c]=s->linesize[c]; + s->coefs_finished[c] |= 1; if(s->avctx->codec->id==CODEC_ID_AMV) { //picture should be flipped upside-down for this codec assert(!(s->avctx->flags & CODEC_FLAG_EMU_EDGE)); @@ -695,30 +794,32 @@ static int mjpeg_decode_scan(MJpegDecodeContext *s, int nb_components, int ss, i x = 0; y = 0; for(j=0;j<n;j++) { - memset(s->block, 0, sizeof(s->block)); - if (!s->progressive && decode_block(s, s->block, i, - s->dc_index[i], s->ac_index[i], - s->quant_matrixes[ s->quant_index[c] ]) < 0) { - av_log(s->avctx, AV_LOG_ERROR, "error y=%d x=%d\n", mb_y, mb_x); - return -1; - } - if (s->progressive && decode_block_progressive(s, s->block, i, - s->dc_index[i], s->ac_index[i], - s->quant_matrixes[ s->quant_index[c] ], ss, se, Ah, Al, &EOBRUN) < 0) { - av_log(s->avctx, AV_LOG_ERROR, "error y=%d x=%d\n", mb_y, mb_x); - return -1; - } -// av_log(s->avctx, AV_LOG_DEBUG, "mb: %d %d processed\n", mb_y, mb_x); ptr = data[c] + (((linesize[c] * (v * mb_y + y) * 8) + (h * mb_x + x) * 8) >> s->avctx->lowres); - if (s->interlaced && s->bottom_field) + if(s->interlaced && s->bottom_field) ptr += linesize[c] >> 1; -//av_log(NULL, AV_LOG_DEBUG, "%d %d %d %d %d %d %d %d \n", mb_x, mb_y, x, y, c, s->bottom_field, (v * mb_y + y) * 8, (h * mb_x + x) * 8); - if(!s->progressive) + if(!s->progressive) { + memset(s->block, 0, sizeof(s->block)); + if(decode_block(s, s->block, i, + s->dc_index[i], s->ac_index[i], + s->quant_matrixes[ s->quant_index[c] ]) < 0) { + av_log(s->avctx, AV_LOG_ERROR, "error y=%d x=%d\n", mb_y, mb_x); + return -1; + } s->dsp.idct_put(ptr, linesize[c], s->block); - else - s->dsp.idct_add(ptr, linesize[c], s->block); + } else { + int block_idx = s->block_stride[c] * (v * mb_y + y) + (h * mb_x + x); + DCTELEM *block = s->blocks[c][block_idx]; + if(Ah) + block[0] += get_bits1(&s->gb) * s->quant_matrixes[ s->quant_index[c] ][0] << Al; + else if(decode_dc_progressive(s, block, i, s->dc_index[i], s->quant_matrixes[ s->quant_index[c] ], Al) < 0) { + av_log(s->avctx, AV_LOG_ERROR, "error y=%d x=%d\n", mb_y, mb_x); + return -1; + } + } +// av_log(s->avctx, AV_LOG_DEBUG, "mb: %d %d processed\n", mb_y, mb_x); +//av_log(NULL, AV_LOG_DEBUG, "%d %d %d %d %d %d %d %d \n", mb_x, mb_y, x, y, c, s->bottom_field, (v * mb_y + y) * 8, (h * mb_x + x) * 8); if (++x == h) { x = 0; y++; @@ -738,6 +839,49 @@ static int mjpeg_decode_scan(MJpegDecodeContext *s, int nb_components, int ss, i return 0; } +static int mjpeg_decode_scan_progressive_ac(MJpegDecodeContext *s, int ss, int se, int Ah, int Al){ + int mb_x, mb_y; + int EOBRUN = 0; + int c = s->comp_index[0]; + uint8_t* data = s->picture.data[c]; + int linesize = s->linesize[c]; + int last_scan = 0; + int16_t *quant_matrix = s->quant_matrixes[ s->quant_index[c] ]; + + if(!Al) { + s->coefs_finished[c] |= (1LL<<(se+1))-(1LL<<ss); + last_scan = !~s->coefs_finished[c]; + } + + if(s->interlaced && s->bottom_field) + data += linesize >> 1; + + for(mb_y = 0; mb_y < s->mb_height; mb_y++) { + uint8_t *ptr = data + (mb_y*linesize*8 >> s->avctx->lowres); + int block_idx = mb_y * s->block_stride[c]; + DCTELEM (*block)[64] = &s->blocks[c][block_idx]; + uint8_t *last_nnz = &s->last_nnz[c][block_idx]; + for(mb_x = 0; mb_x < s->mb_width; mb_x++, block++, last_nnz++) { + int ret; + if(Ah) + ret = decode_block_refinement(s, *block, last_nnz, s->ac_index[0], + quant_matrix, ss, se, Al, &EOBRUN); + else + ret = decode_block_progressive(s, *block, last_nnz, s->ac_index[0], + quant_matrix, ss, se, Al, &EOBRUN); + if(ret < 0) { + av_log(s->avctx, AV_LOG_ERROR, "error y=%d x=%d\n", mb_y, mb_x); + return -1; + } + if(last_scan) { + s->dsp.idct_put(ptr, linesize, *block); + ptr += 8 >> s->avctx->lowres; + } + } + } + return 0; +} + int ff_mjpeg_decode_sos(MJpegDecodeContext *s) { int len, nb_components, i, h, v, predictor, point_transform; @@ -849,8 +993,13 @@ int ff_mjpeg_decode_sos(MJpegDecodeContext *s) } } }else{ - if(mjpeg_decode_scan(s, nb_components, predictor, ilv, prev_shift, point_transform) < 0) - return -1; + if(s->progressive && predictor) { + if(mjpeg_decode_scan_progressive_ac(s, predictor, ilv, prev_shift, point_transform) < 0) + return -1; + } else { + if(mjpeg_decode_scan(s, nb_components, prev_shift, point_transform) < 0) + return -1; + } } emms_c(); return 0; @@ -1354,6 +1503,10 @@ av_cold int ff_mjpeg_decode_end(AVCodecContext *avctx) for(j=0;j<4;j++) free_vlc(&s->vlcs[i][j]); } + for(i=0; i<MAX_COMPONENTS; i++) { + av_freep(&s->blocks[i]); + av_freep(&s->last_nnz[i]); + } return 0; } diff --git a/libavcodec/mjpegdec.h b/libavcodec/mjpegdec.h index c973a9c2a2..e90d864937 100644 --- a/libavcodec/mjpegdec.h +++ b/libavcodec/mjpegdec.h @@ -67,6 +67,7 @@ typedef struct MJpegDecodeContext { int width, height; int mb_width, mb_height; int nb_components; + int block_stride[MAX_COMPONENTS]; int component_id[MAX_COMPONENTS]; int h_count[MAX_COMPONENTS]; /* horizontal and vertical count for each component */ int v_count[MAX_COMPONENTS]; @@ -83,6 +84,9 @@ typedef struct MJpegDecodeContext { int linesize[MAX_COMPONENTS]; ///< linesize << interlaced int8_t *qscale_table; DECLARE_ALIGNED_16(DCTELEM, block[64]); + DCTELEM (*blocks[MAX_COMPONENTS])[64]; ///< intermediate sums (progressive mode) + uint8_t *last_nnz[MAX_COMPONENTS]; + uint64_t coefs_finished[MAX_COMPONENTS]; ///< bitmask of which coefs have been completely decoded (progressive mode) ScanTable scantable; DSPContext dsp; |