mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2024-12-23 12:43:46 +02:00
Support CODEC_FLAG_EMU_EDGE in VP8 decoder.
Originally committed as revision 26117 to svn://svn.ffmpeg.org/ffmpeg/trunk
This commit is contained in:
parent
b59dd1ea4f
commit
ee555de7dd
@ -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;
|
||||
|
@ -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);
|
||||
|
170
libavcodec/vp8.c
170
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;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user