[x265] [PATCH 2 of 3] Implementation for Intra-refresh

Santhoshini Sekar santhoshini at multicorewareinc.com
Wed Sep 9 05:21:09 CEST 2015


Thanks Steve, will modify and resend the patches.

On Wed, Sep 9, 2015 at 1:32 AM, Steve Borho <steve at borho.org> wrote:

> On 09/07, santhoshini at multicorewareinc.com wrote:
> > # HG changeset patch
> > # User Santhoshini Sekar<santhoshini at multicorewareinc.com>
> > # Date 1441625035 -19800
> > #      Mon Sep 07 16:53:55 2015 +0530
> > # Node ID d91760d89cbd0e6f124fab60d7e4d684299b89a1
> > # Parent  2ba81f60f111c12a8f668ece13b23123702f2582
> > Implementation for Intra-refresh
> >
> > diff -r 2ba81f60f111 -r d91760d89cbd source/common/cudata.cpp
> > --- a/source/common/cudata.cpp        Mon Sep 07 15:20:53 2015 +0530
> > +++ b/source/common/cudata.cpp        Mon Sep 07 16:53:55 2015 +0530
> > @@ -1813,6 +1813,14 @@
> >      int16_t ymax = (int16_t)((m_slice->m_sps->picHeightInLumaSamples +
> offset - m_cuPelY - 1) << mvshift);
> >      int16_t ymin = -(int16_t)((g_maxCUSize + offset + m_cuPelY - 1) <<
> mvshift);
> >
> > +    if (m_encData->m_param->bIntraRefresh && m_slice->m_sliceType ==
> P_SLICE)
> > +    {
> > +        int maxX =
> (m_slice->m_refFrameList[0][0]->m_encData->m_pir->pirEndPelX * 16 - 3) <<
> mvshift;
> > +        int maxMv = maxX - 4* 16 * outMV.x;
> > +        if (maxMv > 0 && m_cuPelX < m_encData->m_pir->pirStartPelX)
> > +            xmax = X265_MIN(xmax, (int16_t)maxX);
> > +    }
> > +
> >      outMV.x = X265_MIN(xmax, X265_MAX(xmin, outMV.x));
> >      outMV.y = X265_MIN(ymax, X265_MAX(ymin, outMV.y));
> >  }
> > diff -r 2ba81f60f111 -r d91760d89cbd source/common/cudata.h
> > --- a/source/common/cudata.h  Mon Sep 07 15:20:53 2015 +0530
> > +++ b/source/common/cudata.h  Mon Sep 07 16:53:55 2015 +0530
> > @@ -208,6 +208,7 @@
> >      const CUData* m_cuAbove;          // pointer to above neighbor CTU
> >      const CUData* m_cuLeft;           // pointer to left neighbor CTU
> >
> > +    int           bForceIntra;        // For Periodic Intra
> Refresh.Supported only in P-frames
>
> this could be a member of Analysis instead of CUData
>
> >      CUData();
> >
> >      void     initialize(const CUDataMemPool& dataPool, uint32_t depth,
> int csp, int instance);
> > diff -r 2ba81f60f111 -r d91760d89cbd source/encoder/analysis.cpp
> > --- a/source/encoder/analysis.cpp     Mon Sep 07 15:20:53 2015 +0530
> > +++ b/source/encoder/analysis.cpp     Mon Sep 07 16:53:55 2015 +0530
> > @@ -170,6 +170,9 @@
> >      }
> >      else
> >      {
> > +        ctu.bForceIntra = m_param->bIntraRefresh &&
> m_slice->m_sliceType == P_SLICE &&
> > +                          ctu.m_cuPelX / g_maxCUSize >=
> frame.m_encData->m_pir->pirStartPelX && ctu.m_cuPelX / g_maxCUSize <
> frame.m_encData->m_pir->pirEndPelX;
> > +
> >          if (!m_param->rdLevel)
> >          {
> >              /* In RD Level 0/1, copy source pixels into the
> reconstructed block so
> > @@ -828,7 +831,7 @@
> >      bool splitIntra = true;
> >      uint32_t splitRefs[4] = { 0, 0, 0, 0 };
> >      /* Step 1. Evaluate Merge/Skip candidates for likely early-outs */
> > -    if (mightNotSplit && depth >= minDepth)
> > +    if (mightNotSplit && depth >= minDepth && !parentCTU.bForceIntra)
> >      {
> >          /* Compute Merge Cost */
> >          md.pred[PRED_MERGE].cu.initSubCU(parentCTU, cuGeom, qp);
> > @@ -909,7 +912,7 @@
> >          if (m_slice->m_pps->bUseDQP && depth <=
> m_slice->m_pps->maxCuDQPDepth && m_slice->m_pps->maxCuDQPDepth != 0)
> >              setLambdaFromQP(parentCTU, qp);
> >
> > -        if (!earlyskip)
> > +        if (!earlyskip && !parentCTU.bForceIntra)
> >          {
> >              uint32_t refMasks[2];
> >              refMasks[0] = allSplitRefs;
> > @@ -1119,7 +1122,21 @@
> >                      }
> >                  }
> >              }
> > -        } // !earlyskip
> > +        }
> > +        if (!earlyskip && parentCTU.bForceIntra)
> > +        {
> > +            ProfileCounter(parentCTU, totalIntraCU[cuGeom.depth]);
> > +            md.pred[PRED_INTRA].cu.initSubCU(parentCTU, cuGeom, qp);
> > +            checkIntra(md.pred[PRED_INTRA], cuGeom, SIZE_2Nx2N, NULL,
> NULL);
> > +            checkBestMode(md.pred[PRED_INTRA], depth);
> > +
> > +            if (cuGeom.log2CUSize == 3 &&
> m_slice->m_sps->quadtreeTULog2MinSize < 3)
> > +            {
> > +                md.pred[PRED_INTRA_NxN].cu.initSubCU(parentCTU, cuGeom,
> qp);
> > +                checkIntra(md.pred[PRED_INTRA_NxN], cuGeom, SIZE_NxN,
> NULL, NULL);
> > +                checkBestMode(md.pred[PRED_INTRA_NxN], depth);
> > +            }
> > +        }// !earlyskip
> >
> >          if (m_bTryLossless)
> >              tryLossless(cuGeom);
> > @@ -1189,23 +1206,36 @@
> >      {
> >          uint8_t* reuseDepth  =
> &m_reuseInterDataCTU->depth[parentCTU.m_cuAddr * parentCTU.m_numPartitions];
> >          uint8_t* reuseModes  =
> &m_reuseInterDataCTU->modes[parentCTU.m_cuAddr * parentCTU.m_numPartitions];
> > -        if (mightNotSplit && depth == reuseDepth[zOrder] && zOrder ==
> cuGeom.absPartIdx && reuseModes[zOrder] == MODE_SKIP)
> > +        if (!parentCTU.bForceIntra)
> >          {
> > -            md.pred[PRED_SKIP].cu.initSubCU(parentCTU, cuGeom, qp);
> > -            md.pred[PRED_MERGE].cu.initSubCU(parentCTU, cuGeom, qp);
> > -            checkMerge2Nx2N_rd5_6(md.pred[PRED_SKIP],
> md.pred[PRED_MERGE], cuGeom, true);
> > +            if (mightNotSplit && depth == reuseDepth[zOrder] && zOrder
> == cuGeom.absPartIdx && reuseModes[zOrder] == MODE_SKIP)
> > +            {
> > +                md.pred[PRED_SKIP].cu.initSubCU(parentCTU, cuGeom, qp);
> > +                md.pred[PRED_MERGE].cu.initSubCU(parentCTU, cuGeom, qp);
> > +                checkMerge2Nx2N_rd5_6(md.pred[PRED_SKIP],
> md.pred[PRED_MERGE], cuGeom, true);
> >
> > -            if (m_bTryLossless)
> > -                tryLossless(cuGeom);
> > +                if (m_bTryLossless)
> > +                    tryLossless(cuGeom);
> >
> > -            if (mightSplit)
> > -                addSplitFlagCost(*md.bestMode, cuGeom.depth);
> > +                if (mightSplit)
> > +                    addSplitFlagCost(*md.bestMode, cuGeom.depth);
> >
> > -            // increment zOrder offset to point to next best depth in
> sharedDepth buffer
> > -            zOrder += g_depthInc[g_maxCUDepth - 1][reuseDepth[zOrder]];
> > +                // increment zOrder offset to point to next best depth
> in sharedDepth buffer
> > +                zOrder += g_depthInc[g_maxCUDepth -
> 1][reuseDepth[zOrder]];
> >
> > -            mightSplit = false;
> > -            mightNotSplit = false;
> > +                mightSplit = false;
> > +                mightNotSplit = false;
> > +            }
> > +        }
> > +        else
> > +        {
> > +            char* reusePartSizes =
> &m_reuseIntraDataCTU->partSizes[parentCTU.m_cuAddr *
> parentCTU.m_numPartitions];
> > +            uint8_t* reuseChromaModes =
> &m_reuseIntraDataCTU->chromaModes[parentCTU.m_cuAddr *
> parentCTU.m_numPartitions];
> > +            PartSize size = (PartSize)reusePartSizes[zOrder];
> > +            Mode& mode = size == SIZE_2Nx2N ? md.pred[PRED_INTRA] :
> md.pred[PRED_INTRA_NxN];
> > +            int ipOffset = (int)(6.0 * X265_LOG2(m_param->rc.ipFactor)
> + 0.5);
> > +            mode.cu.initSubCU(parentCTU, cuGeom,
> X265_MAX(mode.cu.m_qp[0] - ipOffset, QP_MIN));
> > +            checkIntra(mode, cuGeom, size, &reuseModes[zOrder],
> &reuseChromaModes[zOrder]);
> >          }
> >      }
> >
> > @@ -1213,7 +1243,7 @@
> >      bool splitIntra = true;
> >      uint32_t splitRefs[4] = { 0, 0, 0, 0 };
> >      /* Step 1. Evaluate Merge/Skip candidates for likely early-outs */
> > -    if (mightNotSplit)
> > +    if (mightNotSplit && !parentCTU.bForceIntra)
> >      {
> >          md.pred[PRED_SKIP].cu.initSubCU(parentCTU, cuGeom, qp);
> >          md.pred[PRED_MERGE].cu.initSubCU(parentCTU, cuGeom, qp);
> > @@ -1282,7 +1312,7 @@
> >          if (m_slice->m_pps->bUseDQP && depth <=
> m_slice->m_pps->maxCuDQPDepth && m_slice->m_pps->maxCuDQPDepth != 0)
> >              setLambdaFromQP(parentCTU, qp);
> >
> > -        if (!(foundSkip && m_param->bEnableEarlySkip))
> > +        if (!(foundSkip && m_param->bEnableEarlySkip) &&
> !parentCTU.bForceIntra)
> >          {
> >              uint32_t refMasks[2];
> >              refMasks[0] = allSplitRefs;
> > @@ -1389,6 +1419,20 @@
> >                  }
> >              }
> >          }
> > +        if (!(foundSkip && m_param->bEnableEarlySkip) &&
> parentCTU.bForceIntra)
> > +        {
> > +            ProfileCounter(parentCTU, totalIntraCU[cuGeom.depth]);
> > +            md.pred[PRED_INTRA].cu.initSubCU(parentCTU, cuGeom, qp);
> > +            checkIntra(md.pred[PRED_INTRA], cuGeom, SIZE_2Nx2N, NULL,
> NULL);
> > +            checkBestMode(md.pred[PRED_INTRA], depth);
> > +
> > +            if (cuGeom.log2CUSize == 3 &&
> m_slice->m_sps->quadtreeTULog2MinSize < 3)
> > +            {
> > +                md.pred[PRED_INTRA_NxN].cu.initSubCU(parentCTU, cuGeom,
> qp);
> > +                checkIntra(md.pred[PRED_INTRA_NxN], cuGeom, SIZE_NxN,
> NULL, NULL);
> > +                checkBestMode(md.pred[PRED_INTRA_NxN], depth);
> > +            }
> > +        }
> >
> >          if (m_bTryLossless)
> >              tryLossless(cuGeom);
> > @@ -1464,7 +1508,13 @@
> >              (candMvField[i][0].mv.y >= (m_param->searchRange + 1) * 4 ||
> >              candMvField[i][1].mv.y >= (m_param->searchRange + 1) * 4))
> >              continue;
> > -
> > +        if (m_param->bIntraRefresh && m_slice->m_sliceType == P_SLICE)
> > +        {
> > +            int maxX =
> (m_slice->m_refFrameList[0][0]->m_encData->m_pir->pirEndPelX * 16 - 3) * 4;
> > +            int maxMv = maxX - 4 * 16 * candMvField[i][0].mv.x;
> > +            if (maxMv > 0 && tempPred->cu.m_cuPelX <
> m_frame->m_encData->m_pir->pirEndPelX)
> > +                continue;
> > +        }
> >          tempPred->cu.m_mvpIdx[0][0] = (uint8_t)i; // merge candidate ID
> is stored in L0 MVP idx
> >          X265_CHECK(m_slice->m_sliceType == B_SLICE || !(candDir[i] &
> 0x10), " invalid merge for P slice\n");
> >          tempPred->cu.m_interDir[0] = candDir[i];
> > @@ -1592,7 +1642,13 @@
> >                  continue;
> >              triedBZero = true;
> >          }
> > -
> > +        if (m_param->bIntraRefresh && m_slice->m_sliceType == P_SLICE)
> > +        {
> > +            int maxX =
> (m_slice->m_refFrameList[0][0]->m_encData->m_pir->pirEndPelX * 16 - 3) * 4;
> > +            int maxMv = maxX - 4 * 16 * candMvField[i][0].mv.x;
> > +            if (maxMv > 0 && tempPred->cu.m_cuPelX <
> m_frame->m_encData->m_pir->pirEndPelX)
> > +                continue;
> > +        }
> >          tempPred->cu.m_mvpIdx[0][0] = (uint8_t)i;    /* merge candidate
> ID is stored in L0 MVP idx */
> >          tempPred->cu.m_interDir[0] = candDir[i];
> >          tempPred->cu.m_mv[0][0] = candMvField[i][0].mv;
> > diff -r 2ba81f60f111 -r d91760d89cbd source/encoder/api.cpp
> > --- a/source/encoder/api.cpp  Mon Sep 07 15:20:53 2015 +0530
> > +++ b/source/encoder/api.cpp  Mon Sep 07 16:53:55 2015 +0530
> > @@ -245,6 +245,12 @@
> >      }
> >  }
> >
> > +void x265_encoder_intra_refresh(x265_encoder *enc)
> > +{
> > +    Encoder *encoder = static_cast<Encoder*>(enc);
>
> do not crash if enc is NULL
>
> > +    encoder->m_param->bQueuedIntraRefresh = 1;
> > +}
> > +
> >  void x265_cleanup(void)
> >  {
> >      if (!g_ctuSizeConfigured)
> > diff -r 2ba81f60f111 -r d91760d89cbd source/encoder/encoder.cpp
> > --- a/source/encoder/encoder.cpp      Mon Sep 07 15:20:53 2015 +0530
> > +++ b/source/encoder/encoder.cpp      Mon Sep 07 16:53:55 2015 +0530
> > @@ -767,6 +767,43 @@
> >              if (m_param->rc.rateControlMode != X265_RC_CQP)
> >                  m_lookahead->getEstimatedPictureCost(frameEnc);
> >
> > +            if (m_param->bIntraRefresh)
> > +            {
> > +                Slice* slice = frameEnc->m_encData->m_slice;
> > +                if (slice->m_sliceType == I_SLICE)
> > +                {
> > +                    frameEnc->m_encData->m_pir->framesSinceLastPir = 0;
> > +                    m_param->bQueuedIntraRefresh = 0;
> > +                    /* PIR is currently only supported with ref == 1,
> so any intra frame effectively refreshes
> > +                     * the whole frame and counts as an intra refresh.
> */
> > +                    frameEnc->m_encData->m_pir->position =
> frameEnc->m_lowres.maxBlocksInRow;
> > +                }
> > +                else if (slice->m_sliceType == P_SLICE)
> > +                {
> > +                    Frame* ref =
> frameEnc->m_encData->m_slice->m_refFrameList[0][0];
> > +                    int pocdiff = (frameEnc->m_poc - ref->m_poc);
> > +                    float increment =
> X265_MAX(((float)frameEnc->m_lowres.maxBlocksInRow - 1) /
> m_param->keyframeMax, 1);
> > +                    frameEnc->m_encData->m_pir->position =
> ref->m_encData->m_pir->position;
> > +                    frameEnc->m_encData->m_pir->framesSinceLastPir =
> ref->m_encData->m_pir->framesSinceLastPir + pocdiff;
> > +                    if (frameEnc->m_encData->m_pir->framesSinceLastPir
> >= m_param->keyframeMax ||
> > +                        (m_param->bQueuedIntraRefresh &&
> frameEnc->m_encData->m_pir->position + 0.5 >=
> frameEnc->m_lowres.maxBlocksInRow))
> > +                    {
> > +                        frameEnc->m_encData->m_pir->position = 0;
> > +                        frameEnc->m_encData->m_pir->framesSinceLastPir
> = 0;
> > +                        m_param->bQueuedIntraRefresh = 0;
> > +                        frameEnc->m_lowres.bKeyframe = 1;
> > +                    }
> > +                    frameEnc->m_encData->m_pir->pirStartPelX =
> (uint32_t)(frameEnc->m_encData->m_pir->position + 0.5);
> > +                    frameEnc->m_encData->m_pir->position += increment *
> pocdiff;
> > +                    frameEnc->m_encData->m_pir->pirEndPelX =
> (uint32_t)(frameEnc->m_encData->m_pir->position + 0.5);
> > +                    /* If our intra refresh has reached the right side
> of the frame, we're done. */
> > +                    if (frameEnc->m_encData->m_pir->pirEndPelX >=
> frameEnc->m_lowres.maxBlocksInRow - 1)
> > +                    {
> > +                        frameEnc->m_encData->m_pir->position =
> frameEnc->m_lowres.maxBlocksInRow;
> > +                        frameEnc->m_encData->m_pir->pirEndPelX =
> frameEnc->m_lowres.maxBlocksInRow - 1;
> > +                    }
> > +                }
> > +            }
> >              /* Allow FrameEncoder::compressFrame() to start in the
> frame encoder thread */
> >              if (!curEncoder->startCompressFrame(frameEnc))
> >                  m_aborted = true;
> > diff -r 2ba81f60f111 -r d91760d89cbd source/encoder/slicetype.cpp
> > --- a/source/encoder/slicetype.cpp    Mon Sep 07 15:20:53 2015 +0530
> > +++ b/source/encoder/slicetype.cpp    Mon Sep 07 16:53:55 2015 +0530
> > @@ -774,6 +774,7 @@
> >              for (uint32_t cnt = 0; cnt < scale && lowresRow <
> heightInLowresCu; lowresRow++, cnt++)
> >              {
> >                  sum = 0; intraSum = 0;
> > +                int diff = 0;
> >                  lowresCuIdx = lowresRow * widthInLowresCu;
> >                  for (lowresCol = 0; lowresCol < widthInLowresCu;
> lowresCol++, lowresCuIdx++)
> >                  {
> > @@ -781,14 +782,18 @@
> >                      if (qp_offset)
> >                      {
> >                          lowresCuCost = (uint16_t)((lowresCuCost *
> x265_exp2fix8(qp_offset[lowresCuIdx]) + 128) >> 8);
> > -                        int32_t intraCuCost =
> curFrame->m_lowres.intraCost[lowresCuIdx];
> > +                        int32_t intraCuCost =
> curFrame->m_lowres.intraCost[lowresCuIdx];
> >                          curFrame->m_lowres.intraCost[lowresCuIdx] =
> (intraCuCost * x265_exp2fix8(qp_offset[lowresCuIdx]) + 128) >> 8;
> >                      }
> > +                    if (m_param->bIntraRefresh && slice->m_sliceType ==
> X265_TYPE_P)
> > +                        for (uint32_t x =
> curFrame->m_encData->m_pir->pirStartPelX; x <=
> curFrame->m_encData->m_pir->pirEndPelX; x++)
> > +                            diff +=
> curFrame->m_lowres.intraCost[lowresCuIdx] - lowresCuCost;
> >                      curFrame->m_lowres.lowresCostForRc[lowresCuIdx] =
> lowresCuCost;
> >                      sum += lowresCuCost;
> >                      intraSum +=
> curFrame->m_lowres.intraCost[lowresCuIdx];
> >                  }
> >                  curFrame->m_encData->m_rowStat[row].satdForVbv += sum;
> > +                curFrame->m_encData->m_rowStat[row].satdForVbv += diff;
> >                  curFrame->m_encData->m_rowStat[row].intraSatdForVbv +=
> intraSum;
> >              }
> >          }
> > @@ -900,8 +905,7 @@
> >              x265_log(m_param, X265_LOG_WARNING, "B-ref at frame %d
> incompatible with B-pyramid and %d reference frames\n",
> >                       frm.sliceType, m_param->maxNumReferences);
> >          }
> > -
> > -        if (/* (!param->intraRefresh || frm.frameNum == 0) && */
> frm.frameNum - m_lastKeyframe >= m_param->keyframeMax)
> > +        if ((!m_param->bIntraRefresh || frm.frameNum == 0) &&
> frm.frameNum - m_lastKeyframe >= m_param->keyframeMax)
> >          {
> >              if (frm.sliceType == X265_TYPE_AUTO || frm.sliceType ==
> X265_TYPE_I)
> >                  frm.sliceType = m_param->bOpenGOP && m_lastKeyframe >=
> 0 ? X265_TYPE_I : X265_TYPE_IDR;
> > @@ -1184,7 +1188,7 @@
> >      frames[framecnt + 1] = NULL;
> >
> >      keyintLimit = m_param->keyframeMax - frames[0]->frameNum +
> m_lastKeyframe - 1;
> > -    origNumFrames = numFrames = X265_MIN(framecnt, keyintLimit);
> > +    origNumFrames = numFrames = m_param->bIntraRefresh ? framecnt :
> X265_MIN(framecnt, keyintLimit);
> >
> >      if (bIsVbvLookahead)
> >          numFrames = framecnt;
> > @@ -1384,7 +1388,7 @@
> >      if (m_param->rc.cuTree)
> >          cuTree(frames, X265_MIN(numFrames, m_param->keyframeMax),
> bKeyframe);
> >
> > -    // if (!param->bIntraRefresh)
> > +     if (!m_param->bIntraRefresh)
>
> w/s
>
> >      for (int j = keyintLimit + 1; j <= numFrames; j +=
> m_param->keyframeMax)
> >      {
> >          frames[j]->sliceType = X265_TYPE_I;
> > @@ -1504,7 +1508,7 @@
> >      {
> >          if (m_param->keyframeMin == m_param->keyframeMax)
> >              threshMin = threshMax;
> > -        if (gopSize <= m_param->keyframeMin / 4)
> > +        if (gopSize <= m_param->keyframeMin / 4 ||
> m_param->bIntraRefresh)
> >              bias = threshMin / 4;
> >          else if (gopSize <= m_param->keyframeMin)
> >              bias = threshMin * gopSize / m_param->keyframeMin;
> > diff -r 2ba81f60f111 -r d91760d89cbd source/x265.h
> > --- a/source/x265.h   Mon Sep 07 15:20:53 2015 +0530
> > +++ b/source/x265.h   Mon Sep 07 16:53:55 2015 +0530
> > @@ -707,6 +707,8 @@
> >       * big keyframe, the keyframe is "spread" over many frames. */
> >      int       bIntraRefresh;
> >
> > +    int       bQueuedIntraRefresh;
> > +
> >      /*== Coding Unit (CU) definitions ==*/
> >
> >      /* Maximum CU width and height in pixels.  The size must be 64, 32,
> or 16.
> > @@ -1373,6 +1375,22 @@
> >   *      close an encoder handler */
> >  void x265_encoder_close(x265_encoder *);
> >
> > +/* x265_encoder_intra_refresh:
> > + *      If an intra refresh is not in progress, begin one with the next
> P-frame.
> > + *      If an intra refresh is in progress, begin one as soon as the
> current one finishes.
> > + *      Requires bIntraRefresh to be set.
> > + *
> > + *      Useful for interactive streaming where the client can tell the
> server that packet loss has
> > + *      occurred.  In this case, keyint can be set to an extremely high
> value so that intra refreshes
> > + *      occur only when calling x265_encoder_intra_refresh.
> > + *
> > + *      In multi-pass encoding, if x265_encoder_intra_refresh is called
> differently in each pass,
> > + *      behavior is undefined.
> > + *
> > + *      Should not be called during an x265_encoder_encode. */
> > +
> > +void x265_encoder_intra_refresh(x265_encoder *);
> > +
> >  /* x265_cleanup:
> >   *       release library static allocations, reset configured CTU size
> */
> >  void x265_cleanup(void);
>
> New APIs must be added to .defs.in and to the end of the API struct
>
> --
> Steve Borho
> _______________________________________________
> x265-devel mailing list
> x265-devel at videolan.org
> https://mailman.videolan.org/listinfo/x265-devel
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mailman.videolan.org/pipermail/x265-devel/attachments/20150909/e44c0474/attachment-0001.html>


More information about the x265-devel mailing list