<div dir="ltr"><br><div class="gmail_extra"><br><div class="gmail_quote">On Tue, May 19, 2015 at 9:35 PM, Steve Borho <span dir="ltr"><<a href="mailto:steve@borho.org" target="_blank">steve@borho.org</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div class="HOEnZb"><div class="h5">On 05/19, <a href="mailto:santhoshini@multicorewareinc.com">santhoshini@multicorewareinc.com</a> wrote:<br>
> # HG changeset patch<br>
> # User Santhoshini Sekar<<a href="mailto:santhoshini@multicorewareinc.com">santhoshini@multicorewareinc.com</a>><br>
> # Date 1432028003 -19800<br>
> #      Tue May 19 15:03:23 2015 +0530<br>
> # Node ID 904ac8808858baaeaaa333b5a105af50c1107db0<br>
> # Parent  d7b100e51e828833eee006f1da93e499ac161d28<br>
> analysis: add an additional round of sub-pel refinement for inter 2Nx2N in rd 5 and 6<br>
><br>
> diff -r d7b100e51e82 -r 904ac8808858 source/common/cudata.cpp<br>
> --- a/source/common/cudata.cpp        Mon May 18 18:24:08 2015 -0500<br>
> +++ b/source/common/cudata.cpp        Tue May 19 15:03:23 2015 +0530<br>
> @@ -456,6 +456,41 @@<br>
>      memcpy(ctu.m_trCoeff[2] + tmpC2, m_trCoeff[2], sizeof(coeff_t) * tmpC);<br>
>  }<br>
><br>
> +void CUData::copyToCU(CUData& ctu) const<br>
> +{<br>
> +    m_partCopy((uint8_t*)ctu.m_qp, (uint8_t*)m_qp);<br>
> +    m_partCopy(ctu.m_log2CUSize, m_log2CUSize);<br>
> +    m_partCopy(ctu.m_lumaIntraDir, m_lumaIntraDir);<br>
> +    m_partCopy(ctu.m_tqBypass, m_tqBypass);<br>
> +    m_partCopy((uint8_t*)ctu.m_refIdx[0], (uint8_t*)m_refIdx[0]);<br>
> +    m_partCopy((uint8_t*)ctu.m_refIdx[1], (uint8_t*)m_refIdx[1]);<br>
> +    m_partCopy(ctu.m_cuDepth, m_cuDepth);<br>
> +    m_partCopy(ctu.m_predMode, m_predMode);<br>
> +    m_partCopy(ctu.m_partSize, m_partSize);<br>
> +    m_partCopy(ctu.m_mergeFlag, m_mergeFlag);<br>
> +    m_partCopy(ctu.m_interDir, m_interDir);<br>
> +    m_partCopy(ctu.m_mvpIdx[0], m_mvpIdx[0]);<br>
> +    m_partCopy(ctu.m_mvpIdx[1], m_mvpIdx[1]);<br>
> +    m_partCopy(ctu.m_tuDepth, m_tuDepth);<br>
> +    m_partCopy(ctu.m_transformSkip[0], m_transformSkip[0]);<br>
> +    m_partCopy(ctu.m_transformSkip[1], m_transformSkip[1]);<br>
> +    m_partCopy(ctu.m_transformSkip[2], m_transformSkip[2]);<br>
> +    m_partCopy(ctu.m_cbf[0], m_cbf[0]);<br>
> +    m_partCopy(ctu.m_cbf[1], m_cbf[1]);<br>
> +    m_partCopy(ctu.m_cbf[2], m_cbf[2]);<br>
> +    m_partCopy(ctu.m_chromaIntraDir, m_chromaIntraDir);<br>
> +<br>
> +    memcpy(ctu.m_mv[0],  m_mv[0],  m_numPartitions * sizeof(MV));<br>
> +    memcpy(ctu.m_mv[1],  m_mv[1],  m_numPartitions * sizeof(MV));<br>
> +    memcpy(ctu.m_mvd[0], m_mvd[0], m_numPartitions * sizeof(MV));<br>
> +    memcpy(ctu.m_mvd[1], m_mvd[1], m_numPartitions * sizeof(MV));<br>
> +<br>
> +    memcpy(ctu.m_trCoeff[0], m_trCoeff[0], sizeof(coeff_t));<br>
> +<br>
> +    memcpy(ctu.m_trCoeff[1], m_trCoeff[1], sizeof(coeff_t));<br>
> +    memcpy(ctu.m_trCoeff[2], m_trCoeff[2], sizeof(coeff_t));<br>
</div></div>w/s nit, remove the blank line above<br>
<div><div class="h5">> +}<br>
> +<br>
>  /* The reverse of copyToPic, called only by encodeResidue */<br>
>  void CUData::copyFromPic(const CUData& ctu, const CUGeom& cuGeom)<br>
>  {<br>
> diff -r d7b100e51e82 -r 904ac8808858 source/common/cudata.h<br>
> --- a/source/common/cudata.h  Mon May 18 18:24:08 2015 -0500<br>
> +++ b/source/common/cudata.h  Tue May 19 15:03:23 2015 +0530<br>
> @@ -188,6 +188,7 @@<br>
>      void     copyPartFrom(const CUData& cu, const CUGeom& childGeom, uint32_t subPartIdx);<br>
>      void     setEmptyPart(const CUGeom& childGeom, uint32_t subPartIdx);<br>
>      void     copyToPic(uint32_t depth) const;<br>
> +    void     copyToCU(CUData& ctu) const;<br>
><br>
>      /* RD-0 methods called only from encodeResidue */<br>
>      void     copyFromPic(const CUData& ctu, const CUGeom& cuGeom);<br>
> diff -r d7b100e51e82 -r 904ac8808858 source/encoder/analysis.cpp<br>
> --- a/source/encoder/analysis.cpp     Mon May 18 18:24:08 2015 -0500<br>
> +++ b/source/encoder/analysis.cpp     Tue May 19 15:03:23 2015 +0530<br>
> @@ -739,7 +739,31 @@<br>
>          cuStat.count[depth] += 1;<br>
>          cuStat.avgCost[depth] = (temp + md.bestMode->rdCost) / cuStat.count[depth];<br>
>      }<br>
> +    /* If zero-residual, do not bother doing subpelRefine */<br>
> +    bool subpelRefine = !!(md.bestMode->cu.m_predMode[0] & MODE_INTER) && !(md.bestMode->cu.m_mergeFlag[0]) && (md.bestMode->cu.m_partSize[0] == SIZE_2Nx2N) && (md.bestMode->cu.m_cuDepth[0] == depth);<br>
> +    if (subpelRefine && m_param->rdLevel > 4)<br>
> +    {<br>
> +        int hpelDirs = MotionEstimate::hpelDirCount(m_param->subpelRefine);<br>
><br>
> +        Mode* rdRefine = &md.pred[PRED_RD_REFINE];<br>
> +        rdRefine->initCosts();<br>
> +        rdRefine->cu.initSubCU(parentCTU, cuGeom, qp);<br>
> +        memcpy(rdRefine->bestME[0], md.bestMode->bestME[0], sizeof(MotionData));<br>
> +        if (m_slice->m_sliceType == B_SLICE)<br>
> +            memcpy(&rdRefine->bestME[0][1], &md.bestMode->bestME[0][1], sizeof(MotionData));<br>
<br>
</div></div>using copyToCU() here means cu.initSubCU() was probably a waste of time<br>
<span class=""><br>
> +        md.bestMode->cu.copyToCU(rdRefine->cu);<br>
> +        rdRefine->reconYuv.copyFromYuv(md.bestMode->reconYuv);<br>
> +        rdRefine->predYuv.copyFromYuv(md.bestMode->predYuv);<br>
> +<br>
> +        for (int i = 1; i <= hpelDirs; i++)<br>
> +        {<br>
> +            qPelRefine(*rdRefine, cuGeom, true, i);<br>
> +            if (m_slice->m_pps->bUseDQP && depth <= m_slice->m_pps->maxCuDQPDepth)<br>
> +                setLambdaFromQP(parentCTU, calculateQpforCuSize(parentCTU, cuGeom));<br>
<br>
</span>why is this necessary here? calculateQpforCuSize(parentCTU, cuGeom))<br>
better return the same 'qp' value in bestMode->cu else you are in a lot<br>
of trouble. Why do this inside the loop?<br></blockquote><div> </div><div>We need this step here because md.bestMode->cu.m_qp[0] will be changed if there was no residual and it will be set with RefQP inside checkDQP(). </div><div>But we want to pass the original QP. Yes this needn't be inside loop, can be done just once. </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><span class="">
> +            encodeResAndCalcRdInterCU(*rdRefine, cuGeom);<br>
> +            checkBestMode(*rdRefine, depth);<br>
> +        }<br>
<br>
</span>I fail to see how this works. If hpelDirs is 8, and at i=1 the RD cost<br>
is better than bestMode, then checkBestMode will point to rdRefine. So<br>
far so good.. but then at i=8 it could have worse cost and you're stuck<br>
because checkBestMode() is not going to go back to the original mode,<br>
there is only one bestMode pointer.<br>
<br></blockquote><div>Why do we want to go back to the original best mode? Can't we use the best mode chosen after each subpel refinement?</div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
You can't avoid doing an extra encodeResAndCalcRdInterCU() at the end,<br>
so you might as well forget about the extra PRED_RD_REFINE.<br></blockquote><div>By using PRED_RD_REFINE we'll have all temporary data in it and I need not do the final extra encode as the pointer md.bestMode will always have the best data. </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
    int bcost = bestMode->rdCost;<br>
    itn bdir = 0;<br>
<span class=""><br>
    for (int i = 1; i <= hpelDirs; i++)<br>
</span>    {<br>
       qPelRefine(*bestMode, cuGeom, true, i);<br>
       encodeResAndCalcRdInterCU(*bestMode, cuGeom);<br>
       COPY2_IF_LT(bcost, bestMode->rdCost, bdir, i);<br>
    }<br>
<br>
    qPelRefine(*bestMode, cuGeom, true, bdir);<br>
    encodeResAndCalcRdInterCU(*bestMode, cuGeom);<br>
<div><div class="h5"><br>
>      /* Copy best data to encData CTU and recon */<br>
>      md.bestMode->cu.copyToPic(depth);<br>
>      if (md.bestMode != &md.pred[PRED_SPLIT])<br>
> @@ -1207,7 +1231,31 @@<br>
>          checkDQPForSplitPred(*splitPred, cuGeom);<br>
>          checkBestMode(*splitPred, depth);<br>
>      }<br>
> +    /* If zero-residual, do not bother doing subpelRefine */<br>
> +    bool subpelRefine = !!(md.bestMode->cu.m_predMode[0] & MODE_INTER) && !(md.bestMode->cu.m_mergeFlag[0]) && (md.bestMode->cu.m_partSize[0] == SIZE_2Nx2N) && (md.bestMode->cu.m_cuDepth[0] == depth);<br>
> +    if (subpelRefine)<br>
> +    {<br>
> +        int hpelDirs = MotionEstimate::hpelDirCount(m_param->subpelRefine);<br>
><br>
> +        Mode* rdRefine = &md.pred[PRED_RD_REFINE];<br>
> +        rdRefine->initCosts();<br>
> +        rdRefine->cu.initSubCU(parentCTU, cuGeom, qp);<br>
> +        memcpy(rdRefine->bestME[0], md.bestMode->bestME[0], sizeof(MotionData));<br>
> +        if (m_slice->m_sliceType == B_SLICE)<br>
> +            memcpy(&rdRefine->bestME[0][1], &md.bestMode->bestME[0][1], sizeof(MotionData));<br>
> +        md.bestMode->cu.copyToCU(rdRefine->cu);<br>
> +        rdRefine->reconYuv.copyFromYuv(md.bestMode->reconYuv);<br>
> +        rdRefine->predYuv.copyFromYuv(md.bestMode->predYuv);<br>
> +<br>
> +        for (int i = 1; i <= hpelDirs; i++)<br>
> +        {<br>
> +            qPelRefine(*rdRefine, cuGeom, true, i);<br>
> +            if (m_slice->m_pps->bUseDQP && depth <= m_slice->m_pps->maxCuDQPDepth)<br>
> +                setLambdaFromQP(parentCTU, calculateQpforCuSize(parentCTU, cuGeom));<br>
> +            encodeResAndCalcRdInterCU(*rdRefine, cuGeom);<br>
> +            checkBestMode(*rdRefine, depth);<br>
> +        }<br>
> +    }<br>
>      /* Copy best data to encData CTU and recon */<br>
>      md.bestMode->cu.copyToPic(depth);<br>
>      if (md.bestMode != &md.pred[PRED_SPLIT])<br>
> diff -r d7b100e51e82 -r 904ac8808858 source/encoder/analysis.h<br>
> --- a/source/encoder/analysis.h       Mon May 18 18:24:08 2015 -0500<br>
> +++ b/source/encoder/analysis.h       Tue May 19 15:03:23 2015 +0530<br>
> @@ -59,6 +59,7 @@<br>
>          PRED_nRx2N,<br>
>          PRED_INTRA_NxN, /* 4x4 intra PU blocks for 8x8 CU */<br>
>          PRED_LOSSLESS,  /* lossless encode of best mode */<br>
> +        PRED_RD_REFINE,<br>
>          MAX_PRED_TYPES<br>
>      };<br>
><br>
> diff -r d7b100e51e82 -r 904ac8808858 source/encoder/motion.cpp<br>
> --- a/source/encoder/motion.cpp       Mon May 18 18:24:08 2015 -0500<br>
> +++ b/source/encoder/motion.cpp       Tue May 19 15:03:23 2015 +0530<br>
> @@ -155,6 +155,11 @@<br>
>             workload[subme].qpel_iters / 2;<br>
>  }<br>
><br>
> +int MotionEstimate::hpelDirCount(int subme)<br>
> +{<br>
> +    return workload[subme].hpel_dirs;<br>
> +}<br>
> +<br>
>  MotionEstimate::~MotionEstimate()<br>
>  {<br>
>      fencPUYuv.destroy();<br>
> @@ -1205,6 +1210,49 @@<br>
>      return bcost;<br>
>  }<br>
><br>
> +int MotionEstimate::qPelCompare(ReferencePlanes *ref,<br>
> +                                   const MV &       mvmin,<br>
> +                                   const MV &       mvmax,<br>
> +                                   const MV&        mvp,<br>
> +                                   const MV&        mv,<br>
> +                                   MV &             outQMv,<br>
> +                                   int halfPelIdx)<br>
> +{<br>
> +    setMVP(mvp);<br>
> +<br>
> +    MV qmvmin = mvmin.toQPel();<br>
> +    MV qmvmax = mvmax.toQPel();<br>
> +<br>
> +    MV fmv = mv.roundToFPel();<br>
> +    fmv = fmv.clipped(qmvmin, qmvmax);<br>
> +    int bcost = INT_MAX;<br>
> +    const SubpelWorkload& wl = workload[this->subpelRefine];<br>
> +<br>
> +    MV hmv = fmv + square1[halfPelIdx] * 2;<br>
> +    bcost = subpelCompare(ref, hmv, satd) + mvcost(hmv);<br>
> +    MV bmv = hmv;<br>
> +<br>
> +    for (int iter = 0; iter < wl.qpel_iters; iter++)<br>
> +    {<br>
> +        int bdir = 0;<br>
> +        for (int i = 1; i <= wl.qpel_dirs; i++)<br>
> +        {<br>
> +            MV qmv = hmv + square1[i];<br>
> +            int cost = subpelCompare(ref, qmv, satd) + mvcost(qmv);<br>
> +            COPY2_IF_LT(bcost, cost, bdir, i);<br>
> +        }<br>
> +<br>
> +        if (bdir)<br>
> +            bmv += square1[bdir];<br>
> +        else<br>
> +            break;<br>
> +    }<br>
> +<br>
> +    x265_emms();<br>
> +    outQMv = bmv;<br>
> +    return bcost;<br>
> +}<br>
> +<br>
>  int MotionEstimate::subpelCompare(ReferencePlanes *ref, const MV& qmv, pixelcmp_t cmp)<br>
>  {<br>
>      intptr_t refStride = ref->lumaStride;<br>
> diff -r d7b100e51e82 -r 904ac8808858 source/encoder/motion.h<br>
> --- a/source/encoder/motion.h Mon May 18 18:24:08 2015 -0500<br>
> +++ b/source/encoder/motion.h Tue May 19 15:03:23 2015 +0530<br>
> @@ -69,6 +69,7 @@<br>
><br>
>      static void initScales();<br>
>      static int hpelIterationCount(int subme);<br>
> +    static int hpelDirCount(int subme);<br>
>      void init(int method, int refine, int csp);<br>
><br>
>      /* Methods called at slice setup */<br>
> @@ -90,6 +91,7 @@<br>
>      }<br>
><br>
>      int motionEstimate(ReferencePlanes* ref, const MV & mvmin, const MV & mvmax, const MV & qmvp, int numCandidates, const MV * mvc, int merange, MV & outQMv);<br>
> +    int qPelCompare(ReferencePlanes* ref, const MV & mvmin, const MV & mvmax, const MV & mvp, const MV & mv, MV & outQMv, int halfPelIdx);<br>
><br>
>      int subpelCompare(ReferencePlanes* ref, const MV &qmv, pixelcmp_t);<br>
><br>
> diff -r d7b100e51e82 -r 904ac8808858 source/encoder/search.cpp<br>
> --- a/source/encoder/search.cpp       Mon May 18 18:24:08 2015 -0500<br>
> +++ b/source/encoder/search.cpp       Tue May 19 15:03:23 2015 +0530<br>
> @@ -2299,6 +2299,54 @@<br>
>      interMode.sa8dBits += totalmebits;<br>
>  }<br>
><br>
> +void Search::qPelRefine(Mode& interMode, const CUGeom& cuGeom, bool bChromaSA8D, int halfpelIdx)<br>
> +{<br>
> +    CUData& cu = interMode.cu;<br>
> +    Yuv* predYuv = &interMode.predYuv;<br>
> +<br>
> +    const Slice *slice = m_slice;<br>
> +    uint32_t interDir = cu.m_interDir[0];<br>
> +<br>
> +    const int* numRefIdx = slice->m_numRefIdx;<br>
> +<br>
> +    MotionData* bestME = interMode.bestME[0];<br>
> +    PredictionUnit pu(cu, cuGeom, 0);<br>
> +<br>
> +    for (uint32_t list = 0; list < 2; list++)<br>
> +    {<br>
> +        if (interDir & (1 << list))<br>
> +        {<br>
> +            int ref = bestME[list].ref;<br>
> +            uint32_t bits = m_listSelBits[list] + MVP_IDX_BITS;<br>
> +            bits += getTUBits(ref, numRefIdx[list]);<br>
> +<br>
> +            int merange = m_param->searchRange;<br>
> +<br>
> +            MV mvmin, mvmax, outmv, mvp = interMode.bestME[0][0].mvp;<br>
> +            MV mv = interMode.bestME[0][0].mv;<br>
> +<br>
> +            int satdCost;<br>
> +            setSearchRange(cu, mv, merange, mvmin, mvmax);<br>
> +            satdCost = m_me.qPelCompare(&slice->m_mref[list][ref], mvmin, mvmax, mvp, mv, outmv, halfpelIdx);<br>
> +<br>
> +            /* Get total cost of partition, but only include MV bit cost once */<br>
> +            bits += m_me.bitcost(outmv);<br>
> +            uint32_t cost = (satdCost - m_me.mvcost(outmv)) + m_rdCost.getCost(bits);<br>
> +<br>
> +            if (cost < bestME[list].cost)<br>
> +            {<br>
> +                bestME[list].mv = outmv;<br>
> +                bestME[list].cost = cost;<br>
> +                bestME[list].bits = bits;<br>
> +            }<br>
> +        }<br>
> +    }<br>
> +<br>
> +    motionCompensation(cu, pu, *predYuv, true, bChromaSA8D);<br>
> +<br>
> +    X265_CHECK(interMode.ok(), "inter mode is not ok");<br>
> +}<br>
> +<br>
>  void Search::getBlkBits(PartSize cuMode, bool bPSlice, int partIdx, uint32_t lastMode, uint32_t blockBit[3])<br>
>  {<br>
>      if (cuMode == SIZE_2Nx2N)<br>
> diff -r d7b100e51e82 -r 904ac8808858 source/encoder/search.h<br>
> --- a/source/encoder/search.h Mon May 18 18:24:08 2015 -0500<br>
> +++ b/source/encoder/search.h Tue May 19 15:03:23 2015 +0530<br>
> @@ -302,6 +302,7 @@<br>
><br>
>      // estimation inter prediction (non-skip)<br>
>      void     predInterSearch(Mode& interMode, const CUGeom& cuGeom, bool bChromaMC);<br>
> +    void     qPelRefine(Mode& interMode, const CUGeom& cuGeom, bool bChroma, int halfpelIdx);<br>
><br>
>      // encode residual and compute rd-cost for inter mode<br>
>      void     encodeResAndCalcRdInterCU(Mode& interMode, const CUGeom& cuGeom);<br>
</div></div>> _______________________________________________<br>
> x265-devel mailing list<br>
> <a href="mailto:x265-devel@videolan.org">x265-devel@videolan.org</a><br>
> <a href="https://mailman.videolan.org/listinfo/x265-devel" target="_blank">https://mailman.videolan.org/listinfo/x265-devel</a><br>
<span class="HOEnZb"><font color="#888888"><br>
--<br>
Steve Borho<br>
_______________________________________________<br>
x265-devel mailing list<br>
<a href="mailto:x265-devel@videolan.org">x265-devel@videolan.org</a><br>
<a href="https://mailman.videolan.org/listinfo/x265-devel" target="_blank">https://mailman.videolan.org/listinfo/x265-devel</a><br>
</font></span></blockquote></div><br></div></div>