From ee555de7dd54b280234ab5e0f45cacd792433983 Mon Sep 17 00:00:00 2001 From: "Ronald S. Bultje" Date: Tue, 28 Dec 2010 17:37:19 +0000 Subject: [PATCH] Support CODEC_FLAG_EMU_EDGE in VP8 decoder. Originally committed as revision 26117 to svn://svn.ffmpeg.org/ffmpeg/trunk --- libavcodec/h264pred.c | 69 ++++++++++++++++- libavcodec/h264pred.h | 22 +++++- libavcodec/vp8.c | 170 ++++++++++++++++++++++++++++++++++++------ 3 files changed, 235 insertions(+), 26 deletions(-) diff --git a/libavcodec/h264pred.c b/libavcodec/h264pred.c index 5706c97e16..05a5899979 100644 --- a/libavcodec/h264pred.c +++ b/libavcodec/h264pred.c @@ -80,6 +80,20 @@ static void pred4x4_128_dc_c(uint8_t *src, const uint8_t *topright, int stride){ ((uint32_t*)(src+3*stride))[0]= 128U*0x01010101U; } +static void pred4x4_127_dc_c(uint8_t *src, const uint8_t *topright, int stride){ + ((uint32_t*)(src+0*stride))[0]= + ((uint32_t*)(src+1*stride))[0]= + ((uint32_t*)(src+2*stride))[0]= + ((uint32_t*)(src+3*stride))[0]= 127U*0x01010101U; +} + +static void pred4x4_129_dc_c(uint8_t *src, const uint8_t *topright, int stride){ + ((uint32_t*)(src+0*stride))[0]= + ((uint32_t*)(src+1*stride))[0]= + ((uint32_t*)(src+2*stride))[0]= + ((uint32_t*)(src+3*stride))[0]= 129U*0x01010101U; +} + #define LOAD_TOP_RIGHT_EDGE\ const int av_unused t4= topright[0];\ @@ -547,6 +561,28 @@ static void pred16x16_128_dc_c(uint8_t *src, int stride){ } } +static void pred16x16_127_dc_c(uint8_t *src, int stride){ + int i; + + for(i=0; i<16; i++){ + ((uint32_t*)(src+i*stride))[0]= + ((uint32_t*)(src+i*stride))[1]= + ((uint32_t*)(src+i*stride))[2]= + ((uint32_t*)(src+i*stride))[3]= 0x01010101U*127U; + } +} + +static void pred16x16_129_dc_c(uint8_t *src, int stride){ + int i; + + for(i=0; i<16; i++){ + ((uint32_t*)(src+i*stride))[0]= + ((uint32_t*)(src+i*stride))[1]= + ((uint32_t*)(src+i*stride))[2]= + ((uint32_t*)(src+i*stride))[3]= 0x01010101U*129U; + } +} + static inline void pred16x16_plane_compat_c(uint8_t *src, int stride, const int svq3, const int rv40){ int i, j, k; int a; @@ -658,6 +694,23 @@ static void pred8x8_128_dc_c(uint8_t *src, int stride){ } } +static void pred8x8_127_dc_c(uint8_t *src, int stride){ + int i; + + for(i=0; i<8; i++){ + ((uint32_t*)(src+i*stride))[0]= + ((uint32_t*)(src+i*stride))[1]= 0x01010101U*127U; + } +} +static void pred8x8_129_dc_c(uint8_t *src, int stride){ + int i; + + for(i=0; i<8; i++){ + ((uint32_t*)(src+i*stride))[0]= + ((uint32_t*)(src+i*stride))[1]= 0x01010101U*129U; + } +} + static void pred8x8_left_dc_c(uint8_t *src, int stride){ int i; int dc0, dc2; @@ -1210,11 +1263,17 @@ void ff_h264_pred_init(H264PredContext *h, int codec_id){ } else h->pred4x4[VERT_LEFT_PRED ]= pred4x4_vertical_left_c; h->pred4x4[HOR_UP_PRED ]= pred4x4_horizontal_up_c; + if(codec_id != CODEC_ID_VP8) { h->pred4x4[LEFT_DC_PRED ]= pred4x4_left_dc_c; h->pred4x4[TOP_DC_PRED ]= pred4x4_top_dc_c; h->pred4x4[DC_128_PRED ]= pred4x4_128_dc_c; - if(codec_id == CODEC_ID_VP8) + } else { h->pred4x4[TM_VP8_PRED ]= pred4x4_tm_vp8_c; + h->pred4x4[DC_127_PRED ]= pred4x4_127_dc_c; + h->pred4x4[DC_129_PRED ]= pred4x4_129_dc_c; + h->pred4x4[VERT_VP8_PRED ]= pred4x4_vertical_c; + h->pred4x4[HOR_VP8_PRED ]= pred4x4_horizontal_c; + } }else{ h->pred4x4[VERT_PRED ]= pred4x4_vertical_c; h->pred4x4[HOR_PRED ]= pred4x4_horizontal_c; @@ -1264,13 +1323,16 @@ void ff_h264_pred_init(H264PredContext *h, int codec_id){ h->pred8x8[DC_PRED8x8 ]= pred8x8_dc_rv40_c; h->pred8x8[LEFT_DC_PRED8x8]= pred8x8_left_dc_rv40_c; h->pred8x8[TOP_DC_PRED8x8 ]= pred8x8_top_dc_rv40_c; + if (codec_id == CODEC_ID_VP8) { + h->pred8x8[DC_127_PRED8x8]= pred8x8_127_dc_c; + h->pred8x8[DC_129_PRED8x8]= pred8x8_129_dc_c; + } } h->pred8x8[DC_128_PRED8x8 ]= pred8x8_128_dc_c; h->pred16x16[DC_PRED8x8 ]= pred16x16_dc_c; h->pred16x16[VERT_PRED8x8 ]= pred16x16_vertical_c; h->pred16x16[HOR_PRED8x8 ]= pred16x16_horizontal_c; - h->pred16x16[PLANE_PRED8x8 ]= pred16x16_plane_c; switch(codec_id){ case CODEC_ID_SVQ3: h->pred16x16[PLANE_PRED8x8 ]= pred16x16_plane_svq3_c; @@ -1280,9 +1342,12 @@ void ff_h264_pred_init(H264PredContext *h, int codec_id){ break; case CODEC_ID_VP8: h->pred16x16[PLANE_PRED8x8 ]= pred16x16_tm_vp8_c; + h->pred16x16[DC_127_PRED8x8]= pred16x16_127_dc_c; + h->pred16x16[DC_129_PRED8x8]= pred16x16_129_dc_c; break; default: h->pred16x16[PLANE_PRED8x8 ]= pred16x16_plane_c; + break; } h->pred16x16[LEFT_DC_PRED8x8]= pred16x16_left_dc_c; h->pred16x16[TOP_DC_PRED8x8 ]= pred16x16_top_dc_c; diff --git a/libavcodec/h264pred.h b/libavcodec/h264pred.h index b7fd2a2b7a..a492ae0ecc 100644 --- a/libavcodec/h264pred.h +++ b/libavcodec/h264pred.h @@ -45,29 +45,45 @@ #define VERT_LEFT_PRED 7 #define HOR_UP_PRED 8 +// DC edge (not for VP8) #define LEFT_DC_PRED 9 #define TOP_DC_PRED 10 #define DC_128_PRED 11 -#define TM_VP8_PRED 9 ///< "True Motion", used instead of plane - +// RV40 specific #define DIAG_DOWN_LEFT_PRED_RV40_NODOWN 12 #define HOR_UP_PRED_RV40_NODOWN 13 #define VERT_LEFT_PRED_RV40_NODOWN 14 +// VP8 specific +#define TM_VP8_PRED 9 ///< "True Motion", used instead of plane +#define VERT_VP8_PRED 10 ///< for VP8, #VERT_PRED is the average of + ///< (left col+cur col x2+right col) / 4; + ///< this is the "unaveraged" one +#define HOR_VP8_PRED 11 ///< unaveraged version of #HOR_PRED, see + ///< #VERT_VP8_PRED for details +#define DC_127_PRED 12 +#define DC_129_PRED 13 + #define DC_PRED8x8 0 #define HOR_PRED8x8 1 #define VERT_PRED8x8 2 #define PLANE_PRED8x8 3 +// DC edge #define LEFT_DC_PRED8x8 4 #define TOP_DC_PRED8x8 5 #define DC_128_PRED8x8 6 +// H264/SVQ3 (8x8) specific #define ALZHEIMER_DC_L0T_PRED8x8 7 #define ALZHEIMER_DC_0LT_PRED8x8 8 #define ALZHEIMER_DC_L00_PRED8x8 9 #define ALZHEIMER_DC_0L0_PRED8x8 10 + +// VP8 specific +#define DC_127_PRED8x8 7 +#define DC_129_PRED8x8 8 //@} /** @@ -77,7 +93,7 @@ typedef struct H264PredContext{ void (*pred4x4 [9+3+3])(uint8_t *src, const uint8_t *topright, int stride);//FIXME move to dsp? void (*pred8x8l [9+3])(uint8_t *src, int topleft, int topright, int stride); void (*pred8x8 [4+3+4])(uint8_t *src, int stride); - void (*pred16x16[4+3])(uint8_t *src, int stride); + void (*pred16x16[4+3+2])(uint8_t *src, int stride); void (*pred4x4_add [2])(uint8_t *pix/*align 4*/, const DCTELEM *block/*align 16*/, int stride); void (*pred8x8l_add [2])(uint8_t *pix/*align 8*/, const DCTELEM *block/*align 16*/, int stride); 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; }