From 8e776366dc0c4dda9201717832cfb081fa066129 Mon Sep 17 00:00:00 2001 From: Marko Viitanen Date: Mon, 16 Sep 2013 16:37:24 +0300 Subject: [PATCH 1/3] Added (basic) motion vector prediction --- src/encoder.c | 22 +++++++++---- src/inter.c | 89 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/inter.h | 5 ++- src/search.c | 2 +- 4 files changed, 110 insertions(+), 8 deletions(-) diff --git a/src/encoder.c b/src/encoder.c index 13226272..3f8cb64b 100644 --- a/src/encoder.c +++ b/src/encoder.c @@ -969,6 +969,10 @@ void encode_coding_tree(encoder_control* encoder,uint16_t xCtb,uint16_t yCtb, ui else { uint32_t uiRefListIdx; + + int16_t mv_cand[2][2]; + + /* // Void TEncSbac::codeInterDir( TComDataCU* pcCU, UInt uiAbsPartIdx ) if(encoder->in.cur_pic->slicetype == SLICE_B) @@ -989,6 +993,7 @@ void encode_coding_tree(encoder_control* encoder,uint16_t xCtb,uint16_t yCtb, ui */ + for(uiRefListIdx = 0; uiRefListIdx < 2; uiRefListIdx++) { //if(encoder->ref_idx_num[uiRefListIdx] > 0) @@ -1029,18 +1034,19 @@ void encode_coding_tree(encoder_control* encoder,uint16_t xCtb,uint16_t yCtb, ui } } + /* Get MV candidates */ + inter_get_mv_cand(encoder, xCtb, yCtb, depth, mv_cand); + cur_CU->inter.mv_ref = 0; if (!(/*pcCU->getSlice()->getMvdL1ZeroFlag() &&*/ encoder->ref_list == REF_PIC_LIST_1 && cur_CU->inter.mv_dir==3)) { - /*const TComCUMvField* pcCUMvField = pcCU->getCUMvField( eRefList );*/ - //TODO: calculate MV field difference - const int32_t mvd_hor = cur_CU->inter.mv[0];//pcCUMvField->getMvd( uiAbsPartIdx ).getHor(); - const int32_t mvd_ver = cur_CU->inter.mv[1];//pcCUMvField->getMvd( uiAbsPartIdx ).getVer(); + const int32_t mvd_hor = cur_CU->inter.mv[0]-mv_cand[cur_CU->inter.mv_ref][0]; + const int32_t mvd_ver = cur_CU->inter.mv[1]-mv_cand[cur_CU->inter.mv_ref][1]; const int8_t bHorAbsGr0 = mvd_hor != 0; const int8_t bVerAbsGr0 = mvd_ver != 0; const uint32_t mvd_hor_abs = abs(mvd_hor); const uint32_t mvd_ver_abs = abs(mvd_ver); - + cabac.ctx = &g_cCUMvdSCModel[0]; CABAC_BIN(&cabac, (mvd_hor!=0)?1:0, "abs_mvd_greater0_flag_hor"); CABAC_BIN(&cabac, (mvd_ver!=0)?1:0, "abs_mvd_greater0_flag_ver"); @@ -1077,10 +1083,14 @@ void encode_coding_tree(encoder_control* encoder,uint16_t xCtb,uint16_t yCtb, ui /* Inter reconstruction */ inter_recon(encoder->ref->pics[0],xCtb*CU_MIN_SIZE_PIXELS,yCtb*CU_MIN_SIZE_PIXELS,LCU_WIDTH>>depth,cur_CU->inter.mv,encoder->in.cur_pic); + + /* Mark this block as "coded" (can be used for predictions..) */ + picture_setBlockCoded(encoder->in.cur_pic,xCtb, yCtb, depth, 1); } { - int32_t iSymbol = cur_CU->inter.mv_ref;//pcCU->getMVPIdx(eRefList, uiAbsPartIdx); + /* Signal which candidate MV to use */ + int32_t iSymbol = cur_CU->inter.mv_ref; int32_t iNum = AMVP_MAX_NUM_CANDS; cabac_writeUnaryMaxSymbol(&cabac,g_cMVPIdxSCModel, iSymbol,1,iNum-1); } diff --git a/src/inter.c b/src/inter.c index 12a3c5ea..fb5ca546 100644 --- a/src/inter.c +++ b/src/inter.c @@ -163,4 +163,93 @@ void inter_recon(picture* ref,int32_t xpos, int32_t ypos,int32_t width, int16_t } } +} + +/*! + \brief Get MV prediction for current block + \param encoder encoder control struct to use + \param xCtb block x position in SCU + \param yCtb block y position in SCU + \param depth current block depth + \param mv_pred[2][2] 2x motion vector prediction + \returns Void +*/ +void inter_get_mv_cand(encoder_control *encoder,int32_t xCtb, int32_t yCtb,int8_t depth, int16_t mv_cand[2][2]) +{ + uint8_t cur_block_in_scu = (LCU_WIDTH>>depth) / CU_MIN_SIZE_PIXELS; + CU_info *cur_cu = &encoder->in.cur_pic->CU[depth][xCtb+yCtb*(encoder->in.width_in_LCU<in.cur_pic->CU[depth][xCtb-1+(yCtb+cur_block_in_scu-1)*(encoder->in.width_in_LCU<coded) a1 = NULL; + + if (yCtb+cur_block_in_scu < encoder->in.height_in_LCU<in.cur_pic->CU[depth][xCtb-1+(yCtb+cur_block_in_scu)*(encoder->in.width_in_LCU<coded) a0 = NULL; + } + } + + if (yCtb != 0) { + b0 = &encoder->in.cur_pic->CU[depth][xCtb+cur_block_in_scu+(yCtb-1)*(encoder->in.width_in_LCU<coded) b0 = NULL; + b1 = &encoder->in.cur_pic->CU[depth][xCtb+cur_block_in_scu-1+(yCtb-1)*(encoder->in.width_in_LCU<coded) b1 = NULL; + + if (xCtb != 0) { + b2 = &encoder->in.cur_pic->CU[depth][xCtb-1+(yCtb-1)*(encoder->in.width_in_LCU<coded) b2 = NULL; + } + } + + /* Left predictors */ + if (a0 && a0->type == CU_INTER) { + mv_cand[candidates][0] = a0->inter.mv[0]; + mv_cand[candidates][1] = a0->inter.mv[1]; + candidates++; + } else if (a1 && a1->type == CU_INTER) { + mv_cand[candidates][0] = a1->inter.mv[0]; + mv_cand[candidates][1] = a1->inter.mv[1]; + candidates++; + } + + /* Top predictors */ + if (b0 && b0->type == CU_INTER) { + mv_cand[candidates][0] = b0->inter.mv[0]; + mv_cand[candidates][1] = b0->inter.mv[1]; + candidates++; + } else if (b1 && b1->type == CU_INTER) { + mv_cand[candidates][0] = b1->inter.mv[0]; + mv_cand[candidates][1] = b1->inter.mv[1]; + candidates++; + } else if(b2 && b2->type == CU_INTER) { + mv_cand[candidates][0] = b2->inter.mv[0]; + mv_cand[candidates][1] = b2->inter.mv[1]; + candidates++; + } + + if(candidates < 2) { + //TODO: add temporal mv predictor + } + + for (;candidates < 2; candidates++) { + mv_cand[candidates][0] = 0; + mv_cand[candidates][1] = 0; + candidates++; + } + } \ No newline at end of file diff --git a/src/inter.h b/src/inter.h index d2bc807b..f0262b93 100644 --- a/src/inter.h +++ b/src/inter.h @@ -14,5 +14,8 @@ #define __INTER_H void inter_setBlockMode(picture* pic,uint32_t xCtb, uint32_t yCtb, uint8_t depth, CU_info* cur_cu); -void inter_recon(picture* ref,int32_t xpos, int32_t ypos,int32_t width, int16_t mv[2], picture* dst); +void inter_recon(picture *ref,int32_t xpos, int32_t ypos,int32_t width, int16_t mv[2], picture* dst); + +void inter_get_mv_cand(encoder_control *encoder, int32_t xCtb, int32_t yCtb, int8_t depth, int16_t mv_cand[2][2]); + #endif diff --git a/src/search.c b/src/search.c index 695acb77..615546ba 100644 --- a/src/search.c +++ b/src/search.c @@ -19,9 +19,9 @@ #include "config.h" #include "bitstream.h" #include "picture.h" +#include "encoder.h" #include "intra.h" #include "inter.h" -#include "encoder.h" #include "filter.h" #include "search.h" From 6a4011a90afe86bb63514756962917f624b94703 Mon Sep 17 00:00:00 2001 From: Marko Viitanen Date: Mon, 16 Sep 2013 16:51:13 +0300 Subject: [PATCH 2/3] Added motion vector candidate selector --- src/encoder.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/src/encoder.c b/src/encoder.c index 3f8cb64b..b010f021 100644 --- a/src/encoder.c +++ b/src/encoder.c @@ -1036,7 +1036,18 @@ void encode_coding_tree(encoder_control* encoder,uint16_t xCtb,uint16_t yCtb, ui /* Get MV candidates */ inter_get_mv_cand(encoder, xCtb, yCtb, depth, mv_cand); - cur_CU->inter.mv_ref = 0; + + /* Select better candidate */ + cur_CU->inter.mv_ref = 0; /* Default to candidate 0 + /* Only check when candidates are different */ + if (mv_cand[0][0] != mv_cand[1][0] || mv_cand[0][1] != mv_cand[1][1]) { + uint16_t cand_1_diff = abs(cur_CU->inter.mv[0]-mv_cand[0][0]) + abs(cur_CU->inter.mv[1]-mv_cand[0][1]); + uint16_t cand_2_diff = abs(cur_CU->inter.mv[0]-mv_cand[1][0]) + abs(cur_CU->inter.mv[1]-mv_cand[1][1]); + /* Select candidate 1 if it's closer */ + if (cand_2_diff < cand_1_diff) { + cur_CU->inter.mv_ref = 1; + } + } if (!(/*pcCU->getSlice()->getMvdL1ZeroFlag() &&*/ encoder->ref_list == REF_PIC_LIST_1 && cur_CU->inter.mv_dir==3)) { @@ -1087,13 +1098,8 @@ void encode_coding_tree(encoder_control* encoder,uint16_t xCtb,uint16_t yCtb, ui /* Mark this block as "coded" (can be used for predictions..) */ picture_setBlockCoded(encoder->in.cur_pic,xCtb, yCtb, depth, 1); } - - { - /* Signal which candidate MV to use */ - int32_t iSymbol = cur_CU->inter.mv_ref; - int32_t iNum = AMVP_MAX_NUM_CANDS; - cabac_writeUnaryMaxSymbol(&cabac,g_cMVPIdxSCModel, iSymbol,1,iNum-1); - } + /* Signal which candidate MV to use */ + cabac_writeUnaryMaxSymbol(&cabac,g_cMVPIdxSCModel, cur_CU->inter.mv_ref,1,AMVP_MAX_NUM_CANDS-1); } } } From 3ff3318980e9b4ef62ee3e3ff596518c70059808 Mon Sep 17 00:00:00 2001 From: Marko Viitanen Date: Mon, 16 Sep 2013 17:15:54 +0300 Subject: [PATCH 3/3] Fixed bug(s) in inter_recon() --- src/encoder.c | 4 +-- src/inter.c | 68 +++++++++++++++++++++------------------------------ 2 files changed, 30 insertions(+), 42 deletions(-) diff --git a/src/encoder.c b/src/encoder.c index b010f021..84416936 100644 --- a/src/encoder.c +++ b/src/encoder.c @@ -1038,7 +1038,7 @@ void encode_coding_tree(encoder_control* encoder,uint16_t xCtb,uint16_t yCtb, ui inter_get_mv_cand(encoder, xCtb, yCtb, depth, mv_cand); /* Select better candidate */ - cur_CU->inter.mv_ref = 0; /* Default to candidate 0 + cur_CU->inter.mv_ref = 0; /* Default to candidate 0 */ /* Only check when candidates are different */ if (mv_cand[0][0] != mv_cand[1][0] || mv_cand[0][1] != mv_cand[1][1]) { uint16_t cand_1_diff = abs(cur_CU->inter.mv[0]-mv_cand[0][0]) + abs(cur_CU->inter.mv[1]-mv_cand[0][1]); @@ -1102,7 +1102,7 @@ void encode_coding_tree(encoder_control* encoder,uint16_t xCtb,uint16_t yCtb, ui cabac_writeUnaryMaxSymbol(&cabac,g_cMVPIdxSCModel, cur_CU->inter.mv_ref,1,AMVP_MAX_NUM_CANDS-1); } } - } + } cabac.ctx = &g_cCUQtRootCbfSCModel; CABAC_BIN(&cabac, 0, "rqt_root_cbf"); diff --git a/src/inter.c b/src/inter.c index fb5ca546..e2582c91 100644 --- a/src/inter.c +++ b/src/inter.c @@ -80,31 +80,28 @@ void inter_recon(picture* ref,int32_t xpos, int32_t ypos,int32_t width, int16_t mv[1] = mv[1]>>2; /* With overflow present, more checking */ - if(overflow_neg_x || overflow_neg_y || overflow_pos_x || overflow_pos_y) - { + if (overflow_neg_x || overflow_neg_y || overflow_pos_x || overflow_pos_y) { /* Copy Luma with boundary checking */ - for(y = ypos; y < ypos+width; y++) - { - for(x = xpos; x < xpos+width; x++) - { + for (y = ypos; y < ypos+width; y++) { + for (x = xpos; x < xpos+width; x++) { coord_x = x; coord_y = y; - overflow_neg_x = (x < 0)?1:0; - overflow_neg_y = (y < 0)?1:0; + overflow_neg_x = (x+mv[0] < 0)?1:0; + overflow_neg_y = (y+mv[1] < 0)?1:0; - overflow_pos_x = (x >= ref->width )?1:0; - overflow_pos_y = (y >= ref->height)?1:0; + overflow_pos_x = (x+mv[0] >= ref->width )?1:0; + overflow_pos_y = (y+mv[1] >= ref->height)?1:0; if(overflow_neg_x) { - coord_x = 0; + coord_x = -mv[0]; } else if(overflow_pos_x) { - coord_x = ref->width-1; + coord_x = ref->width-1-mv[0]; } if(overflow_neg_y) { - coord_y = 0; + coord_y = -mv[1]; } else if(overflow_pos_y) { - coord_y = ref->height-1; + coord_y = ref->height-1-mv[1]; } dst->yRecData[y*dst->width+x] = ref->yRecData[(coord_y+mv[1])*ref->width+(coord_x+mv[0])]; @@ -112,57 +109,48 @@ void inter_recon(picture* ref,int32_t xpos, int32_t ypos,int32_t width, int16_t } /* Copy Chroma with boundary checking */ - for(y = ypos>>1; y < (ypos+width)>>1; y++) - { - for(x = xpos>>1; x < (xpos+width)>>1; x++) - { + for (y = ypos>>1; y < (ypos+width)>>1; y++) { + for (x = xpos>>1; x < (xpos+width)>>1; x++) { coord_x = x; coord_y = y; - overflow_neg_x = (x < 0)?1:0; - overflow_neg_y = (y < 0)?1:0; + overflow_neg_x = (x+(mv[0]>>1) < 0)?1:0; + overflow_neg_y = (y+(mv[1]>>1) < 0)?1:0; - overflow_pos_x = (x >= ref->width>>1 )?1:0; - overflow_pos_y = (y >= ref->height>>1)?1:0; + overflow_pos_x = (x+(mv[0]>>1) >= ref->width>>1 )?1:0; + overflow_pos_y = (y+(mv[1]>>1) >= ref->height>>1)?1:0; if(overflow_neg_x) { - coord_x = 0; + coord_x = -(mv[0]>>1); } else if(overflow_pos_x) { - coord_x = (ref->width>>1)-1; + coord_x = ((ref->width-mv[0])>>1)-1; } if(overflow_neg_y) { - coord_y = 0; + coord_y = -(mv[1]>>1); } else if(overflow_pos_y) { - coord_y = (ref->height>>1)-1; + coord_y = ((ref->height-mv[1])>>1)-1; } - dst->uRecData[y*(dst->width>>1)+x] = ref->uRecData[(coord_y+(mv[1]>>1))*ref->width+(coord_x+(mv[0]>>1))]; - dst->vRecData[y*(dst->width>>1)+x] = ref->vRecData[(coord_y+(mv[1]>>1))*ref->width+(coord_x+(mv[0]>>1))]; + dst->uRecData[y*(dst->width>>1)+x] = ref->uRecData[(coord_y+(mv[1]>>1))*(ref->width>>1)+(coord_x+(mv[0]>>1))]; + dst->vRecData[y*(dst->width>>1)+x] = ref->vRecData[(coord_y+(mv[1]>>1))*(ref->width>>1)+(coord_x+(mv[0]>>1))]; } } - } - else - { + } else { /* Copy Luma */ - for(y = ypos; y < ypos+width; y++) - { - for(x = xpos; x < xpos+width; x++) - { + for (y = ypos; y < ypos+width; y++) { + for (x = xpos; x < xpos+width; x++) { dst->yRecData[y*dst->width+x] = ref->yRecData[(y+mv[1])*ref->width+x+mv[0]]; } } /* Copy Chroma */ - for(y = ypos>>1; y < (ypos+width)>>1; y++) - { - for(x = xpos>>1; x < (xpos+width)>>1; x++) - { + for (y = ypos>>1; y < (ypos+width)>>1; y++) { + for (x = xpos>>1; x < (xpos+width)>>1; x++) { dst->uRecData[y*(dst->width>>1)+x] = ref->uRecData[(y+(mv[1]>>1))*(ref->width>>1)+x+(mv[0]>>1)]; dst->vRecData[y*(dst->width>>1)+x] = ref->vRecData[(y+(mv[1]>>1))*(ref->width>>1)+x+(mv[0]>>1)]; } } } - } /*!