diff options
author | Ronald S. Bultje <rsbultje@gmail.com> | 2010-12-28 17:37:19 +0000 |
---|---|---|
committer | Ronald S. Bultje <rsbultje@gmail.com> | 2010-12-28 17:37:19 +0000 |
commit | ee555de7dd54b280234ab5e0f45cacd792433983 (patch) | |
tree | 4c58942b3e38cb6085d334ba158de0b57092177c /libavcodec/vp8.c | |
parent | b59dd1ea4f39c8d5a7efb51ef378f810c0279c09 (diff) | |
download | ffmpeg-ee555de7dd54b280234ab5e0f45cacd792433983.tar.gz |
Support CODEC_FLAG_EMU_EDGE in VP8 decoder.
Originally committed as revision 26117 to svn://svn.ffmpeg.org/ffmpeg/trunk
Diffstat (limited to 'libavcodec/vp8.c')
-rw-r--r-- | libavcodec/vp8.c | 170 |
1 files changed, 149 insertions, 21 deletions
diff --git a/libavcodec/vp8.c b/libavcodec/vp8.c index 49cff25122..50ecaf1889 100644 --- a/libavcodec/vp8.c +++ b/libavcodec/vp8.c @@ -983,14 +983,91 @@ void xchg_mb_border(uint8_t *top_border, uint8_t *src_y, uint8_t *src_cb, uint8_ } static av_always_inline -int check_intra_pred_mode(int mode, int mb_x, int mb_y) +int check_dc_pred8x8_mode(int mode, int mb_x, int mb_y) +{ + if (!mb_x) { + return mb_y ? TOP_DC_PRED8x8 : DC_128_PRED8x8; + } else { + return mb_y ? mode : LEFT_DC_PRED8x8; + } +} + +static av_always_inline +int check_tm_pred8x8_mode(int mode, int mb_x, int mb_y) +{ + if (!mb_x) { + return mb_y ? VERT_PRED8x8 : DC_129_PRED8x8; + } else { + return mb_y ? mode : HOR_PRED8x8; + } +} + +static av_always_inline +int check_intra_pred8x8_mode(int mode, int mb_x, int mb_y) { if (mode == DC_PRED8x8) { - if (!mb_x) { - mode = mb_y ? TOP_DC_PRED8x8 : DC_128_PRED8x8; - } else if (!mb_y) { - mode = LEFT_DC_PRED8x8; + return check_dc_pred8x8_mode(mode, mb_x, mb_y); + } else { + return mode; + } +} + +static av_always_inline +int check_intra_pred8x8_mode_emuedge(int mode, int mb_x, int mb_y) +{ + switch (mode) { + case DC_PRED8x8: + return check_dc_pred8x8_mode(mode, mb_x, mb_y); + case VERT_PRED8x8: + return !mb_y ? DC_127_PRED8x8 : mode; + case HOR_PRED8x8: + return !mb_x ? DC_129_PRED8x8 : mode; + case PLANE_PRED8x8 /*TM*/: + return check_tm_pred8x8_mode(mode, mb_x, mb_y); + } + return mode; +} + +static av_always_inline +int check_tm_pred4x4_mode(int mode, int mb_x, int mb_y) +{ + if (!mb_x) { + return mb_y ? VERT_VP8_PRED : DC_129_PRED; + } else { + return mb_y ? mode : HOR_VP8_PRED; + } +} + +static av_always_inline +int check_intra_pred4x4_mode_emuedge(int mode, int mb_x, int mb_y, int *copy_buf) +{ + switch (mode) { + case VERT_PRED: + if (!mb_x && mb_y) { + *copy_buf = 1; + return mode; + } + /* fall-through */ + case DIAG_DOWN_LEFT_PRED: + case VERT_LEFT_PRED: + return !mb_y ? DC_127_PRED : mode; + case HOR_PRED: + if (!mb_y) { + *copy_buf = 1; + return mode; } + /* fall-through */ + case HOR_UP_PRED: + return !mb_x ? DC_129_PRED : mode; + case TM_VP8_PRED: + return check_tm_pred4x4_mode(mode, mb_x, mb_y); + case DC_PRED: // 4x4 DC doesn't use the same "H.264-style" exceptions as 16x16/8x8 DC + case DIAG_DOWN_RIGHT_PRED: + case VERT_RIGHT_PRED: + case HOR_DOWN_PRED: + if (!mb_y || !mb_x) + *copy_buf = 1; + return mode; } return mode; } @@ -999,21 +1076,27 @@ static av_always_inline void intra_predict(VP8Context *s, uint8_t *dst[3], VP8Macroblock *mb, int mb_x, int mb_y) { + AVCodecContext *avctx = s->avctx; int x, y, mode, nnz, tr; // for the first row, we need to run xchg_mb_border to init the top edge to 127 // otherwise, skip it if we aren't going to deblock - if (s->deblock_filter || !mb_y) + if (!(avctx->flags & CODEC_FLAG_EMU_EDGE && !mb_y) && (s->deblock_filter || !mb_y)) xchg_mb_border(s->top_border[mb_x+1], dst[0], dst[1], dst[2], s->linesize, s->uvlinesize, mb_x, mb_y, s->mb_width, s->filter.simple, 1); if (mb->mode < MODE_I4x4) { - mode = check_intra_pred_mode(mb->mode, mb_x, mb_y); + if (avctx->flags & CODEC_FLAG_EMU_EDGE) { // tested + mode = check_intra_pred8x8_mode_emuedge(mb->mode, mb_x, mb_y); + } else { + mode = check_intra_pred8x8_mode(mb->mode, mb_x, mb_y); + } s->hpc.pred16x16[mode](dst[0], s->linesize); } else { uint8_t *ptr = dst[0]; uint8_t *intra4x4 = s->intra4x4_pred_mode_mb; + uint8_t tr_top[4] = { 127, 127, 127, 127 }; // all blocks on the right edge of the macroblock use bottom edge // the top macroblock for their topright edge @@ -1032,10 +1115,53 @@ void intra_predict(VP8Context *s, uint8_t *dst[3], VP8Macroblock *mb, for (y = 0; y < 4; y++) { uint8_t *topright = ptr + 4 - s->linesize; for (x = 0; x < 4; x++) { - if (x == 3) + int copy = 0, linesize = s->linesize; + uint8_t *dst = ptr+4*x; + DECLARE_ALIGNED(4, uint8_t, copy_dst)[5*8]; + + if ((y == 0 || x == 3) && mb_y == 0 && avctx->flags & CODEC_FLAG_EMU_EDGE) { + topright = tr_top; + } else if (x == 3) topright = tr_right; - s->hpc.pred4x4[intra4x4[x]](ptr+4*x, topright, s->linesize); + if (avctx->flags & CODEC_FLAG_EMU_EDGE) { // mb_x+x or mb_y+y is a hack but works + mode = check_intra_pred4x4_mode_emuedge(intra4x4[x], mb_x + x, mb_y + y, ©); + if (copy) { + dst = copy_dst + 12; + linesize = 8; + if (!(mb_y + y)) { + copy_dst[3] = 127U; + * (uint32_t *) (copy_dst + 4) = 127U * 0x01010101U; + } else { + * (uint32_t *) (copy_dst + 4) = * (uint32_t *) (ptr+4*x-s->linesize); + if (!(mb_x + x)) { + copy_dst[3] = 129U; + } else { + copy_dst[3] = ptr[4*x-s->linesize-1]; + } + } + if (!(mb_x + x)) { + copy_dst[11] = + copy_dst[19] = + copy_dst[27] = + copy_dst[35] = 129U; + } else { + copy_dst[11] = ptr[4*x -1]; + copy_dst[19] = ptr[4*x+s->linesize -1]; + copy_dst[27] = ptr[4*x+s->linesize*2-1]; + copy_dst[35] = ptr[4*x+s->linesize*3-1]; + } + } + } else { + mode = intra4x4[x]; + } + s->hpc.pred4x4[mode](dst, topright, linesize); + if (copy) { + * (uint32_t *) (ptr+4*x) = * (uint32_t *) (copy_dst + 12); + * (uint32_t *) (ptr+4*x+s->linesize) = * (uint32_t *) (copy_dst + 20); + * (uint32_t *) (ptr+4*x+s->linesize*2) = * (uint32_t *) (copy_dst + 28); + * (uint32_t *) (ptr+4*x+s->linesize*3) = * (uint32_t *) (copy_dst + 36); + } nnz = s->non_zero_count_cache[y][x]; if (nnz) { @@ -1052,11 +1178,15 @@ void intra_predict(VP8Context *s, uint8_t *dst[3], VP8Macroblock *mb, } } - mode = check_intra_pred_mode(s->chroma_pred_mode, mb_x, mb_y); + if (avctx->flags & CODEC_FLAG_EMU_EDGE) { + mode = check_intra_pred8x8_mode_emuedge(s->chroma_pred_mode, mb_x, mb_y); + } else { + mode = check_intra_pred8x8_mode(s->chroma_pred_mode, mb_x, mb_y); + } s->hpc.pred8x8[mode](dst[1], s->uvlinesize); s->hpc.pred8x8[mode](dst[2], s->uvlinesize); - if (s->deblock_filter || !mb_y) + if (!(avctx->flags & CODEC_FLAG_EMU_EDGE && !mb_y) && (s->deblock_filter || !mb_y)) xchg_mb_border(s->top_border[mb_x+1], dst[0], dst[1], dst[2], s->linesize, s->uvlinesize, mb_x, mb_y, s->mb_width, s->filter.simple, 0); @@ -1533,7 +1663,10 @@ static int vp8_decode_frame(AVCodecContext *avctx, void *data, int *data_size, memset(s->macroblocks + s->mb_height*2 - 1, 0, (s->mb_width+1)*sizeof(*s->macroblocks)); // top edge of 127 for intra prediction - memset(s->top_border, 127, (s->mb_width+1)*sizeof(*s->top_border)); + if (!(avctx->flags & CODEC_FLAG_EMU_EDGE)) { + s->top_border[0][15] = s->top_border[0][23] = 127; + memset(s->top_border[1]-1, 127, s->mb_width*sizeof(*s->top_border)+1); + } memset(s->ref_count, 0, sizeof(s->ref_count)); if (s->keyframe) memset(s->intra4x4_pred_mode_top, DC_PRED, s->mb_width*4); @@ -1553,12 +1686,13 @@ static int vp8_decode_frame(AVCodecContext *avctx, void *data, int *data_size, AV_WN32A(s->intra4x4_pred_mode_left, DC_PRED*0x01010101); // left edge of 129 for intra prediction - if (!(avctx->flags & CODEC_FLAG_EMU_EDGE)) + if (!(avctx->flags & CODEC_FLAG_EMU_EDGE)) { for (i = 0; i < 3; i++) for (y = 0; y < 16>>!!i; y++) dst[i][y*curframe->linesize[i]-1] = 129; - if (mb_y) - memset(s->top_border, 129, sizeof(*s->top_border)); + if (mb_y == 1) // top left edge is also 129 + s->top_border[0][15] = s->top_border[0][23] = s->top_border[0][31] = 129; + } for (mb_x = 0; mb_x < s->mb_width; mb_x++, mb_xy++, mb++) { /* Prefetch the current frame, 4 MBs ahead */ @@ -1658,12 +1792,6 @@ static av_cold int vp8_decode_init(AVCodecContext *avctx) ff_h264_pred_init(&s->hpc, CODEC_ID_VP8); ff_vp8dsp_init(&s->vp8dsp); - // intra pred needs edge emulation among other things - if (avctx->flags&CODEC_FLAG_EMU_EDGE) { - av_log(avctx, AV_LOG_ERROR, "Edge emulation not supported\n"); - return AVERROR_PATCHWELCOME; - } - return 0; } |