Ejemplo n.º 1
0
        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);
            }
        }