コード例 #1
0
        private void ResetStats()
        {
            Vp8EncProba proba = this.Proba;

            proba.CalculateLevelCosts();
            proba.NbSkip = 0;
        }
コード例 #2
0
ファイル: Vp8EncIterator.cs プロジェクト: br3aker/ImageSharp
        public int GetCostLuma16(Vp8ModeScore rd, Vp8EncProba proba, Vp8Residual res)
        {
            int r = 0;

            // re-import the non-zero context.
            this.NzToBytes();

            // DC
            res.Init(0, 1, proba);
            res.SetCoeffs(rd.YDcLevels);
            r += res.GetResidualCost(this.TopNz[8] + this.LeftNz[8]);

            // AC
            res.Init(1, 0, proba);
            for (int y = 0; y < 4; y++)
            {
                for (int x = 0; x < 4; x++)
                {
                    int ctx = this.TopNz[x] + this.LeftNz[y];
                    res.SetCoeffs(rd.YAcLevels.AsSpan((x + (y * 4)) * 16, 16));
                    r            += res.GetResidualCost(ctx);
                    this.TopNz[x] = this.LeftNz[y] = res.Last >= 0 ? 1 : 0;
                }
            }

            return(r);
        }
コード例 #3
0
ファイル: Vp8Residual.cs プロジェクト: br3aker/ImageSharp
 public void Init(int first, int coeffType, Vp8EncProba prob)
 {
     this.First     = first;
     this.CoeffType = coeffType;
     this.Prob      = prob.Coeffs[this.CoeffType];
     this.Stats     = prob.Stats[this.CoeffType];
     this.Costs     = prob.RemappedCosts[this.CoeffType];
     this.Coeffs.AsSpan().Clear();
 }
コード例 #4
0
ファイル: Vp8EncIterator.cs プロジェクト: br3aker/ImageSharp
        public int GetCostLuma4(Span <short> levels, Vp8EncProba proba, Vp8Residual res)
        {
            int x = this.I4 & 3;
            int y = this.I4 >> 2;
            int r = 0;

            res.Init(0, 3, proba);
            int ctx = this.TopNz[x] + this.LeftNz[y];

            res.SetCoeffs(levels);
            r += res.GetResidualCost(ctx);
            return(r);
        }
コード例 #5
0
ファイル: Vp8EncIterator.cs プロジェクト: br3aker/ImageSharp
        public int GetCostUv(Vp8ModeScore rd, Vp8EncProba proba, Vp8Residual res)
        {
            int r = 0;

            // re-import the non-zero context.
            this.NzToBytes();

            res.Init(0, 2, proba);
            for (int ch = 0; ch <= 2; ch += 2)
            {
                for (int y = 0; y < 2; y++)
                {
                    for (int x = 0; x < 2; x++)
                    {
                        int ctx = this.TopNz[4 + ch + x] + this.LeftNz[4 + ch + y];
                        res.SetCoeffs(rd.UvLevels.AsSpan(((ch * 2) + x + (y * 2)) * 16, 16));
                        r += res.GetResidualCost(ctx);
                        this.TopNz[4 + ch + x] = this.LeftNz[4 + ch + y] = res.Last >= 0 ? 1 : 0;
                    }
                }
            }

            return(r);
        }
コード例 #6
0
ファイル: QuantEnc.cs プロジェクト: br3aker/ImageSharp
        private const int DSCALE = 1; // storage descaling, needed to make the error fit byte

        public static void PickBestIntra16(Vp8EncIterator it, ref Vp8ModeScore rd, Vp8SegmentInfo[] segmentInfos, Vp8EncProba proba)
        {
            const int      numBlocks = 16;
            Vp8SegmentInfo dqm       = segmentInfos[it.CurrentMacroBlockInfo.Segment];
            int            lambda    = dqm.LambdaI16;
            int            tlambda   = dqm.TLambda;
            Span <byte>    src       = it.YuvIn.AsSpan(Vp8EncIterator.YOffEnc);
            Span <int>     scratch   = it.Scratch3;
            var            rdTmp     = new Vp8ModeScore();
            var            res       = new Vp8Residual();
            Vp8ModeScore   rdCur     = rdTmp;
            Vp8ModeScore   rdBest    = rd;
            int            mode;
            bool           isFlat = IsFlatSource16(src);

            rd.ModeI16 = -1;
            for (mode = 0; mode < WebpConstants.NumPredModes; ++mode)
            {
                // Scratch buffer.
                Span <byte> tmpDst = it.YuvOut2.AsSpan(Vp8EncIterator.YOffEnc);
                rdCur.ModeI16 = mode;

                // Reconstruct.
                rdCur.Nz = (uint)ReconstructIntra16(it, dqm, rdCur, tmpDst, mode);

                // Measure RD-score.
                rdCur.D  = LossyUtils.Vp8_Sse16X16(src, tmpDst);
                rdCur.SD = tlambda != 0 ? Mult8B(tlambda, LossyUtils.Vp8Disto16X16(src, tmpDst, WeightY, scratch)) : 0;
                rdCur.H  = WebpConstants.Vp8FixedCostsI16[mode];
                rdCur.R  = it.GetCostLuma16(rdCur, proba, res);

                if (isFlat)
                {
                    // Refine the first impression (which was in pixel space).
                    isFlat = IsFlat(rdCur.YAcLevels, numBlocks, WebpConstants.FlatnessLimitI16);
                    if (isFlat)
                    {
                        // Block is very flat. We put emphasis on the distortion being very low!
                        rdCur.D  *= 2;
                        rdCur.SD *= 2;
                    }
                }

                // Since we always examine Intra16 first, we can overwrite *rd directly.
                rdCur.SetRdScore(lambda);

                if (mode == 0 || rdCur.Score < rdBest.Score)
                {
                    Vp8ModeScore tmp = rdCur;
                    rdCur  = rdBest;
                    rdBest = tmp;
                    it.SwapOut();
                }
            }

            if (rdBest != rd)
            {
                rd = rdBest;
            }

            // Finalize score for mode decision.
            rd.SetRdScore(dqm.LambdaMode);
            it.SetIntra16Mode(rd.ModeI16);

            // We have a blocky macroblock (only DCs are non-zero) with fairly high
            // distortion, record max delta so we can later adjust the minimal filtering
            // strength needed to smooth these blocks out.
            if ((rd.Nz & 0x100ffff) == 0x1000000 && rd.D > dqm.MinDisto)
            {
                dqm.StoreMaxDelta(rd.YDcLevels);
            }
        }
コード例 #7
0
ファイル: QuantEnc.cs プロジェクト: br3aker/ImageSharp
        public static void PickBestUv(Vp8EncIterator it, ref Vp8ModeScore rd, Vp8SegmentInfo[] segmentInfos, Vp8EncProba proba)
        {
            const int      numBlocks = 8;
            Vp8SegmentInfo dqm       = segmentInfos[it.CurrentMacroBlockInfo.Segment];
            int            lambda    = dqm.LambdaUv;
            Span <byte>    src       = it.YuvIn.AsSpan(Vp8EncIterator.UOffEnc);
            Span <byte>    tmpDst    = it.YuvOut2.AsSpan(Vp8EncIterator.UOffEnc);
            Span <byte>    dst0      = it.YuvOut.AsSpan(Vp8EncIterator.UOffEnc);
            Span <byte>    dst       = dst0;
            var            rdBest    = new Vp8ModeScore();
            var            rdUv      = new Vp8ModeScore();
            var            res       = new Vp8Residual();
            int            mode;

            rd.ModeUv = -1;
            rdBest.InitScore();
            for (mode = 0; mode < WebpConstants.NumPredModes; ++mode)
            {
                rdUv.Clear();

                // Reconstruct
                rdUv.Nz = (uint)ReconstructUv(it, dqm, rdUv, tmpDst, mode);

                // Compute RD-score
                rdUv.D  = LossyUtils.Vp8_Sse16X8(src, tmpDst);
                rdUv.SD = 0;    // not calling TDisto here: it tends to flatten areas.
                rdUv.H  = WebpConstants.Vp8FixedCostsUv[mode];
                rdUv.R  = it.GetCostUv(rdUv, proba, res);
                if (mode > 0 && IsFlat(rdUv.UvLevels, numBlocks, WebpConstants.FlatnessLimitIUv))
                {
                    rdUv.R += WebpConstants.FlatnessPenality * numBlocks;
                }

                rdUv.SetRdScore(lambda);
                if (mode == 0 || rdUv.Score < rdBest.Score)
                {
                    rdBest.CopyScore(rdUv);
                    rd.ModeUv = mode;
                    rdUv.UvLevels.CopyTo(rd.UvLevels.AsSpan());
                    for (int i = 0; i < 2; i++)
                    {
                        rd.Derr[i, 0] = rdUv.Derr[i, 0];
                        rd.Derr[i, 1] = rdUv.Derr[i, 1];
                        rd.Derr[i, 2] = rdUv.Derr[i, 2];
                    }

                    Span <byte> tmp = dst;
                    dst    = tmpDst;
                    tmpDst = tmp;
                }
            }

            it.SetIntraUvMode(rd.ModeUv);
            rd.AddScore(rdBest);
            if (dst != dst0)
            {
                // copy 16x8 block if needed.
                LossyUtils.Vp8Copy16X8(dst, dst0);
            }

            // Store diffusion errors for next block.
            it.StoreDiffusionErrors(rd);
        }
コード例 #8
0
ファイル: QuantEnc.cs プロジェクト: br3aker/ImageSharp
        public static bool PickBestIntra4(Vp8EncIterator it, ref Vp8ModeScore rd, Vp8SegmentInfo[] segmentInfos, Vp8EncProba proba, int maxI4HeaderBits)
        {
            Vp8SegmentInfo dqm             = segmentInfos[it.CurrentMacroBlockInfo.Segment];
            int            lambda          = dqm.LambdaI4;
            int            tlambda         = dqm.TLambda;
            Span <byte>    src0            = it.YuvIn.AsSpan(Vp8EncIterator.YOffEnc);
            Span <byte>    bestBlocks      = it.YuvOut2.AsSpan(Vp8EncIterator.YOffEnc);
            Span <int>     scratch         = it.Scratch3;
            int            totalHeaderBits = 0;
            var            rdBest          = new Vp8ModeScore();

            if (maxI4HeaderBits == 0)
            {
                return(false);
            }

            rdBest.InitScore();
            rdBest.H = 211;  // '211' is the value of VP8BitCost(0, 145)
            rdBest.SetRdScore(dqm.LambdaMode);
            it.StartI4();
            var          rdi4      = new Vp8ModeScore();
            var          rdTmp     = new Vp8ModeScore();
            var          res       = new Vp8Residual();
            Span <short> tmpLevels = new short[16];

            do
            {
                int numBlocks = 1;
                rdi4.Clear();
                int         mode;
                int         bestMode  = -1;
                Span <byte> src       = src0.Slice(WebpLookupTables.Vp8Scan[it.I4]);
                short[]     modeCosts = it.GetCostModeI4(rd.ModesI4);
                Span <byte> bestBlock = bestBlocks.Slice(WebpLookupTables.Vp8Scan[it.I4]);
                Span <byte> tmpDst    = it.Scratch.AsSpan();
                tmpDst.Clear();

                rdi4.InitScore();
                it.MakeIntra4Preds();
                for (mode = 0; mode < WebpConstants.NumBModes; ++mode)
                {
                    rdTmp.Clear();
                    tmpLevels.Clear();

                    // Reconstruct.
                    rdTmp.Nz = (uint)ReconstructIntra4(it, dqm, tmpLevels, src, tmpDst, mode);

                    // Compute RD-score.
                    rdTmp.D  = LossyUtils.Vp8_Sse4X4(src, tmpDst);
                    rdTmp.SD = tlambda != 0 ? Mult8B(tlambda, LossyUtils.Vp8Disto4X4(src, tmpDst, WeightY, scratch)) : 0;
                    rdTmp.H  = modeCosts[mode];

                    // Add flatness penalty, to avoid flat area to be mispredicted by a complex mode.
                    if (mode > 0 && IsFlat(tmpLevels, numBlocks, WebpConstants.FlatnessLimitI4))
                    {
                        rdTmp.R = WebpConstants.FlatnessPenality * numBlocks;
                    }
                    else
                    {
                        rdTmp.R = 0;
                    }

                    // Early-out check.
                    rdTmp.SetRdScore(lambda);
                    if (bestMode >= 0 && rdTmp.Score >= rdi4.Score)
                    {
                        continue;
                    }

                    // Finish computing score.
                    rdTmp.R += it.GetCostLuma4(tmpLevels, proba, res);
                    rdTmp.SetRdScore(lambda);

                    if (bestMode < 0 || rdTmp.Score < rdi4.Score)
                    {
                        rdi4.CopyScore(rdTmp);
                        bestMode = mode;
                        Span <byte> tmp = tmpDst;
                        tmpDst    = bestBlock;
                        bestBlock = tmp;
                        tmpLevels.CopyTo(rdBest.YAcLevels.AsSpan(it.I4 * 16, 16));
                    }
                }

                rdi4.SetRdScore(dqm.LambdaMode);
                rdBest.AddScore(rdi4);
                if (rdBest.Score >= rd.Score)
                {
                    return(false);
                }

                totalHeaderBits += (int)rdi4.H;   // <- equal to modeCosts[bestMode];
                if (totalHeaderBits > maxI4HeaderBits)
                {
                    return(false);
                }

                // Copy selected samples to the right place.
                LossyUtils.Vp8Copy4X4(bestBlock, bestBlocks.Slice(WebpLookupTables.Vp8Scan[it.I4]));

                rd.ModesI4[it.I4]   = (byte)bestMode;
                it.TopNz[it.I4 & 3] = it.LeftNz[it.I4 >> 2] = rdi4.Nz != 0 ? 1 : 0;
            }while (it.RotateI4(bestBlocks));

            // Finalize state.
            rd.CopyScore(rdBest);
            it.SetIntra4Mode(rd.ModesI4);
            it.SwapOut();
            rdBest.YAcLevels.AsSpan().CopyTo(rd.YAcLevels);

            // Select intra4x4 over intra16x16.
            return(true);
        }