Skip to content

Commit

Permalink
motion: Modify "--refine-mv" option
Browse files Browse the repository at this point in the history
Add MV refinement level 1,2 and 3.
Based on the MV refinement level, number of search increases.
  • Loading branch information
Pooja Venkatesan committed Aug 23, 2019
1 parent 071bc93 commit 3a05f77
Show file tree
Hide file tree
Showing 7 changed files with 82 additions and 38 deletions.
11 changes: 7 additions & 4 deletions doc/reST/cli.rst
Expand Up @@ -997,11 +997,14 @@ will not reuse analysis if slice type parameters do not match.
the encoder settings. It is recommended to use :option:`--refine-intra` 4 with dynamic
refinement. Default disabled.

.. option:: --refine-mv
.. option:: --refine-mv <0..3>

Enables refinement of motion vector for scaled video. Evaluates the best
motion vector by searching the surrounding eight integer and subpel pixel
positions.
motion vector based on the level selected. Default 0 - disabled.

Level 1 - Search around scaled MV.
Level 2 - Level 1 + Search around best AMVP cand.
Level 3 - Level 2 + Search around the other AMVP cand.

Options which affect the transform unit quad-tree, sometimes referred to
as the residual quad-tree (RQT).
Expand Down
4 changes: 3 additions & 1 deletion source/common/param.cpp
Expand Up @@ -1209,7 +1209,7 @@ int x265_param_parse(x265_param* p, const char* name, const char* value)
OPT("scale-factor") p->scaleFactor = atoi(value);
OPT("refine-intra")p->intraRefine = atoi(value);
OPT("refine-inter")p->interRefine = atoi(value);
OPT("refine-mv")p->mvRefine = atobool(value);
OPT("refine-mv")p->mvRefine = atoi(value);
OPT("force-flush")p->forceFlush = atoi(value);
OPT("splitrd-skip") p->bEnableSplitRdSkip = atobool(value);
OPT("lowpass-dct") p->bLowPassDct = atobool(value);
Expand Down Expand Up @@ -1650,6 +1650,8 @@ int x265_check_params(x265_param* param)
"Strict-cbr cannot be applied without specifying target bitrate or vbv bufsize");
CHECK((param->analysisSave || param->analysisLoad) && (param->analysisReuseLevel < 1 || param->analysisReuseLevel > 10),
"Invalid analysis refine level. Value must be between 1 and 10 (inclusive)");
CHECK(param->analysisLoad && (param->mvRefine < 0 || param->mvRefine > 3),
"Invalid mv refinement level. Value must be between 0 and 3 (inclusive)");
CHECK(param->scaleFactor > 2, "Invalid scale-factor. Supports factor <= 2");
CHECK(param->rc.qpMax < QP_MIN || param->rc.qpMax > QP_MAX_MAX,
"qpmax exceeds supported range (0 to 69)");
Expand Down
16 changes: 10 additions & 6 deletions source/encoder/analysis.cpp
Expand Up @@ -2488,14 +2488,18 @@ void Analysis::recodeCU(const CUData& parentCTU, const CUGeom& cuGeom, int32_t q
MV mvp;

int numMvc = mode.cu.getPMV(mode.interNeighbours, list, ref, mode.amvpCand[list][ref], mvc);
if (m_param->interRefine != 1)
mvp = mode.amvpCand[list][ref][mode.cu.m_mvpIdx[list][pu.puAbsPartIdx]];
else
mvp = interDataCTU->mv[list][cuIdx + part].word;
mvp = mode.amvpCand[list][ref][mode.cu.m_mvpIdx[list][pu.puAbsPartIdx]];
if (m_param->mvRefine || m_param->interRefine == 1)
{
MV outmv;
searchMV(mode, pu, list, ref, outmv, mvp, numMvc, mvc);
MV outmv, mvpSelect[3];
mvpSelect[0] = interDataCTU->mv[list][cuIdx + part].word;
switch (m_param->mvRefine)
{
case 3: mvpSelect[2] = mode.amvpCand[list][ref][!(mode.cu.m_mvpIdx[list][pu.puAbsPartIdx])];
case 2: mvpSelect[1] = mvp;
default: break;
}
searchMV(mode, list, ref, outmv, mvpSelect, numMvc, mvc);
mode.cu.setPUMv(list, outmv, pu.puAbsPartIdx, part);
}
mode.cu.m_mvd[list][pu.puAbsPartIdx] = mode.cu.m_mv[list][pu.puAbsPartIdx] - mode.amvpCand[list][ref][mode.cu.m_mvpIdx[list][pu.puAbsPartIdx]]/*mvp*/;
Expand Down
10 changes: 5 additions & 5 deletions source/encoder/encoder.cpp
Expand Up @@ -2983,11 +2983,11 @@ void Encoder::configure(x265_param *p)
x265_log(p, X265_LOG_WARNING, "MV refinement requires analysis load, analysis-reuse-level 10. Disabling MV refine.\n");
p->mvRefine = 0;
}
else if (p->interRefine >= 2)
{
x265_log(p, X265_LOG_WARNING, "MVs are recomputed when refine-inter >= 2. MV refinement not applicable. Disabling MV refine\n");
p->mvRefine = 0;
}
}
if (p->scaleFactor && p->analysisLoad && p->interRefine && p->analysisReuseLevel == 10 && !p->mvRefine)
{
x265_log(p, X265_LOG_WARNING, "Enabling MV refinement level 1 with scaling and analysis-reuse-level=10.\n");
p->mvRefine = 1;
}

if (p->ctuDistortionRefine == CTU_DISTORTION_INTERNAL)
Expand Down
72 changes: 54 additions & 18 deletions source/encoder/search.cpp
Expand Up @@ -2152,23 +2152,27 @@ void Search::singleMotionEstimation(Search& master, Mode& interMode, const Predi
bestME[list].mvCost = mvCost;
}
}
void Search::searchMV(Mode& interMode, const PredictionUnit& pu, int list, int ref, MV& outmv, MV mvp, int numMvc, MV* mvc)
void Search::searchMV(Mode& interMode, int list, int ref, MV& outmv, MV mvp[3], int numMvc, MV* mvc)
{
CUData& cu = interMode.cu;
const Slice *slice = m_slice;
MV mv;
if (m_param->interRefine == 1)
mv = mvp;
else
mv = cu.m_mv[list][pu.puAbsPartIdx];
MV mv, mvmin, mvmax;
cu.clipMv(mv);
MV mvmin, mvmax;
setSearchRange(cu, mv, m_param->searchRange, mvmin, mvmax);
if (m_param->interRefine == 1)
m_me.motionEstimate(&m_slice->m_mref[list][ref], mvmin, mvmax, mv, numMvc, mvc, m_param->searchRange, outmv, m_param->maxSlices,
int cand = 0, bestcost = INT_MAX;
do
{
if (cand && (mvp[cand] == mvp[cand - 1] || (cand == 2 && mvp[cand] == mvp[cand - 2])))
continue;
MV bestMV;
mv = mvp[cand];
setSearchRange(cu, mv, m_param->searchRange, mvmin, mvmax);
int cost = m_me.motionEstimate(&m_slice->m_mref[list][ref], mvmin, mvmax, mv, numMvc, mvc, m_param->searchRange, bestMV, m_param->maxSlices,
m_param->bSourceReferenceEstimation ? m_slice->m_refFrameList[list][ref]->m_fencPic->getLumaAddr(0) : 0);
else
m_me.refineMV(&slice->m_mref[list][ref], mvmin, mvmax, mv, outmv);
if (bestcost > cost)
{
bestcost = cost;
outmv = bestMV;
}
}while (++cand < m_param->mvRefine);
}
/* find the best inter prediction for each PU of specified mode */
void Search::predInterSearch(Mode& interMode, const CUGeom& cuGeom, bool bChromaMC, uint32_t refMasks[2])
Expand Down Expand Up @@ -2229,7 +2233,6 @@ void Search::predInterSearch(Mode& interMode, const CUGeom& cuGeom, bool bChroma
int ref = -1;
if (useAsMVP)
ref = interDataCTU->refIdx[list][cuIdx + puIdx];

else
ref = bestME[list].ref;
if (ref < 0)
Expand All @@ -2243,7 +2246,7 @@ void Search::predInterSearch(Mode& interMode, const CUGeom& cuGeom, bool bChroma
const MV* amvp = interMode.amvpCand[list][ref];
int mvpIdx = selectMVP(cu, pu, amvp, list, ref);
MV mvmin, mvmax, outmv, mvp;
if (useAsMVP)
if (useAsMVP && !m_param->mvRefine)
{
mvp = interDataCTU->mv[list][cuIdx + puIdx].word;
mvpIdx = interDataCTU->mvpIdx[list][cuIdx + puIdx];
Expand All @@ -2259,11 +2262,44 @@ void Search::predInterSearch(Mode& interMode, const CUGeom& cuGeom, bool bChroma
}
setSearchRange(cu, mvp, m_param->searchRange, mvmin, mvmax);
MV mvpIn = mvp;
int satdCost;
if (m_param->analysisMultiPassRefine && m_param->rc.bStatRead && mvpIdx == bestME[list].mvpIdx)
mvpIn = bestME[list].mv;

int satdCost = m_me.motionEstimate(&slice->m_mref[list][ref], mvmin, mvmax, mvpIn, numMvc, mvc, m_param->searchRange, outmv, m_param->maxSlices,
m_param->bSourceReferenceEstimation ? m_slice->m_refFrameList[list][ref]->m_fencPic->getLumaAddr(0) : 0);
if (useAsMVP && m_param->mvRefine)
{
MV bestmv, mvpSel[3];
int mvpIdxSel[3];
satdCost = m_me.COST_MAX;
switch (m_param->mvRefine)
{
case 3: mvpSel[2] = interMode.amvpCand[list][ref][!mvpIdx];
mvpIdxSel[2] = !mvpIdx;
case 2: mvpSel[1] = interMode.amvpCand[list][ref][mvpIdx];
mvpIdxSel[1] = mvpIdx;
case 1: mvpSel[0] = interDataCTU->mv[list][cuIdx + puIdx].word;
mvpIdxSel[0] = interDataCTU->mvpIdx[list][cuIdx + puIdx];
}
for (int cand = 0; cand < m_param->mvRefine; cand++)
{
if (cand && (mvpSel[cand] == mvpSel[cand - 1] || (cand == 2 && mvpSel[cand] == mvpSel[cand - 2])))
continue;
setSearchRange(cu, mvp, m_param->searchRange, mvmin, mvmax);
int bcost = m_me.motionEstimate(&m_slice->m_mref[list][ref], mvmin, mvmax, mvpSel[cand], numMvc, mvc, m_param->searchRange, bestmv, m_param->maxSlices,
m_param->bSourceReferenceEstimation ? m_slice->m_refFrameList[list][ref]->m_fencPic->getLumaAddr(0) : 0);
if (satdCost > bcost)
{
satdCost = bcost;
outmv = bestmv;
mvp = mvpSel[cand];
mvpIdx = mvpIdxSel[cand];
}
}
}
else
{
satdCost = m_me.motionEstimate(&slice->m_mref[list][ref], mvmin, mvmax, mvpIn, numMvc, mvc, m_param->searchRange, outmv, m_param->maxSlices,
m_param->bSourceReferenceEstimation ? m_slice->m_refFrameList[list][ref]->m_fencPic->getLumaAddr(0) : 0);
}

/* Get total cost of partition, but only include MV bit cost once */
bits += m_me.bitcost(outmv);
Expand Down
2 changes: 1 addition & 1 deletion source/encoder/search.h
Expand Up @@ -310,7 +310,7 @@ class Search : public Predict

// estimation inter prediction (non-skip)
void predInterSearch(Mode& interMode, const CUGeom& cuGeom, bool bChromaMC, uint32_t masks[2]);
void searchMV(Mode& interMode, const PredictionUnit& pu, int list, int ref, MV& outmv, MV mvp, int numMvc, MV* mvc);
void searchMV(Mode& interMode, int list, int ref, MV& outmv, MV mvp[3], int numMvc, MV* mvc);
// encode residual and compute rd-cost for inter mode
void encodeResAndCalcRdInterCU(Mode& interMode, const CUGeom& cuGeom);
void encodeResAndCalcRdSkipCU(Mode& interMode);
Expand Down
5 changes: 2 additions & 3 deletions source/x265cli.h
Expand Up @@ -297,8 +297,7 @@ static const struct option long_options[] =
{ "dhdr10-opt", no_argument, NULL, 0},
{ "no-dhdr10-opt", no_argument, NULL, 0},
{ "dolby-vision-profile", required_argument, NULL, 0 },
{ "refine-mv", no_argument, NULL, 0 },
{ "no-refine-mv", no_argument, NULL, 0 },
{ "refine-mv", required_argument, NULL, 0 },
{ "refine-ctu-distortion", required_argument, NULL, 0 },
{ "force-flush", required_argument, NULL, 0 },
{ "splitrd-skip", no_argument, NULL, 0 },
Expand Down Expand Up @@ -549,7 +548,7 @@ static void showHelp(x265_param *param)
" - 3 : Functionality of (1) + irrespective of size evaluate all inter modes.\n"
" Default:%d\n", param->interRefine);
H0(" --[no-]dynamic-refine Dynamically changes refine-inter level for each CU. Default %s\n", OPT(param->bDynamicRefine));
H0(" --[no-]refine-mv Enable mv refinement for load mode. Default %s\n", OPT(param->mvRefine));
H0(" --refine-mv <0..3> Enable mv refinement for load mode. Default %d\n", param->mvRefine);
H0(" --refine-ctu-distortion Store/normalize ctu distortion in analysis-save/load.\n"
" - 0 : Disabled.\n"
" - 1 : Store/Load ctu distortion to/from the file specified in analysis-save/load.\n"
Expand Down

0 comments on commit 3a05f77

Please sign in to comment.