Пример #1
0
        private static void RunVp8Sse16X8Test()
        {
            // arrange
            byte[] a =
            {
                107, 104, 104, 103, 101, 106, 123, 119, 170, 171, 172, 171, 168, 175, 171, 173, 151, 151, 149, 150,
                147, 147, 146, 159, 164, 165, 154, 129,  92,  90, 101, 105, 104, 103, 104, 101, 100, 105, 123, 117,
                172, 172, 172, 168, 170, 177, 170, 175, 151, 149, 150, 150, 147, 147, 156, 161, 161, 161, 151, 126,
                93,   90, 102, 107, 104, 103, 104, 101, 104, 104, 122, 117, 172, 172, 170, 168, 170, 177, 172, 175,
                150, 149, 152, 151, 148, 151, 160, 159, 157, 157, 148, 133,  96,  90, 103, 107, 104, 104, 101, 100,
                102, 102, 121, 117, 170, 170, 169, 171, 171, 179, 173, 175, 149, 151, 152, 151, 148, 154, 162, 157,
                154, 154, 151, 132,  92,  89, 101, 108, 104, 102, 101, 101, 103, 103, 123, 118, 171, 168, 177, 173,
                171, 178, 172, 176, 152, 152, 152, 151, 154, 162, 161, 155, 149, 157, 156, 129,  92,  87, 101, 107,
                102, 100, 107, 100, 101, 102, 123, 118, 170, 175, 182, 172, 171, 179, 173, 175, 152, 151, 154, 155,
                160, 162, 161, 153, 150, 156, 153, 129,  92,  91, 102, 106, 100, 109, 115,  99, 101, 102, 124, 120,
                171, 179, 178, 172, 171, 181, 171, 173, 154, 154, 154, 162, 160, 158, 156, 152, 153, 157, 151, 128,
                86,   86, 102, 105, 102, 122, 114,  99, 101, 102, 125, 120, 178, 173, 177, 172, 171, 180, 172, 173,
                154, 152, 158, 163, 150, 148, 148, 156, 151, 158, 152, 129,  87,  87, 101, 105
            };

            byte[] b =
            {
                103, 103, 103, 103, 101, 106, 122, 114, 171, 171, 171, 171, 171, 177, 169, 175, 150, 150, 150, 150,
                146, 149, 152, 154, 161, 164, 151, 130,  93,  86, 100, 106, 103, 103, 103, 103, 101, 106, 122, 114,
                171, 171, 171, 171, 171, 177, 169, 175, 150, 150, 150, 150, 146, 149, 152, 154, 158, 161, 148, 127,
                93,   86, 100, 106, 103, 103, 103, 103, 101, 106, 122, 114, 171, 171, 171, 171, 171, 177, 169, 175,
                150, 150, 150, 150, 146, 149, 152, 154, 156, 159, 146, 125,  99,  92, 106, 112, 103, 103, 103, 103,
                101, 106, 122, 114, 171, 171, 171, 171, 171, 177, 169, 175, 148, 148, 148, 148, 149, 158, 162, 159,
                155, 155, 153, 129,  94,  87, 101, 106, 102, 100, 100, 102, 100, 101, 120, 122, 170, 176, 176, 170,
                174, 180, 171, 177, 151, 151, 151, 151, 152, 159, 161, 156, 155, 155, 153, 129,  94,  87, 101, 106,
                102, 105, 105, 102, 100, 101, 120, 122, 170, 176, 176, 170, 174, 180, 171, 177, 154, 154, 154, 154,
                156, 161, 159, 152, 155, 155, 153, 129,  94,  87, 101, 106, 102, 112, 112, 102, 100, 101, 120, 122,
                170, 176, 176, 170, 174, 180, 171, 177, 156, 156, 156, 156, 159, 162, 158, 149, 155, 155, 153, 129,
                94,   87, 101, 106, 102, 117, 117, 102, 100, 101, 120, 122, 170, 176, 176, 170, 174, 180, 171, 177,
                152, 153, 157, 162, 150, 149, 149, 151, 155, 160, 150, 131,  91,  90, 104, 104
            };

            int expected = 749;

            // act
            int actual = LossyUtils.Vp8_Sse16X8(a, b);

            // assert
            Assert.Equal(expected, actual);
        }
Пример #2
0
        // Refine intra16/intra4 sub-modes based on distortion only (not rate).
        public static void RefineUsingDistortion(Vp8EncIterator it, Vp8SegmentInfo[] segmentInfos, Vp8ModeScore rd, bool tryBothModes, bool refineUvMode, int mbHeaderLimit)
        {
            long           bestScore = Vp8ModeScore.MaxCost;
            int            nz        = 0;
            int            mode;
            bool           isI16 = tryBothModes || it.CurrentMacroBlockInfo.MacroBlockType == Vp8MacroBlockType.I16X16;
            Vp8SegmentInfo dqm   = segmentInfos[it.CurrentMacroBlockInfo.Segment];

            // Some empiric constants, of approximate order of magnitude.
            const int lambdaDi16 = 106;
            const int lambdaDi4  = 11;
            const int lambdaDuv  = 120;
            long      scoreI4    = dqm.I4Penalty;
            long      i4BitSum   = 0;
            long      bitLimit   = tryBothModes
                ? mbHeaderLimit
                : Vp8ModeScore.MaxCost; // no early-out allowed.

            if (isI16)
            {
                int         bestMode = -1;
                Span <byte> src      = it.YuvIn.AsSpan(Vp8EncIterator.YOffEnc);
                for (mode = 0; mode < WebpConstants.NumPredModes; ++mode)
                {
                    Span <byte> reference = it.YuvP.AsSpan(Vp8Encoding.Vp8I16ModeOffsets[mode]);
                    long        score     = (LossyUtils.Vp8_Sse16X16(src, reference) * WebpConstants.RdDistoMult) + (WebpConstants.Vp8FixedCostsI16[mode] * lambdaDi16);

                    if (mode > 0 && WebpConstants.Vp8FixedCostsI16[mode] > bitLimit)
                    {
                        continue;
                    }

                    if (score < bestScore)
                    {
                        bestMode  = mode;
                        bestScore = score;
                    }
                }

                if (it.X == 0 || it.Y == 0)
                {
                    // Avoid starting a checkerboard resonance from the border. See bug #432 of libwebp.
                    if (IsFlatSource16(src))
                    {
                        bestMode     = it.X == 0 ? 0 : 2;
                        tryBothModes = false; // Stick to i16.
                    }
                }

                it.SetIntra16Mode(bestMode);

                // We'll reconstruct later, if i16 mode actually gets selected.
            }

            // Next, evaluate Intra4.
            if (tryBothModes || !isI16)
            {
                // We don't evaluate the rate here, but just account for it through a
                // constant penalty (i4 mode usually needs more bits compared to i16).
                isI16 = false;
                it.StartI4();
                do
                {
                    int         bestI4Mode  = -1;
                    long        bestI4Score = Vp8ModeScore.MaxCost;
                    Span <byte> src         = it.YuvIn.AsSpan(Vp8EncIterator.YOffEnc + WebpLookupTables.Vp8Scan[it.I4]);
                    short[]     modeCosts   = it.GetCostModeI4(rd.ModesI4);

                    it.MakeIntra4Preds();
                    for (mode = 0; mode < WebpConstants.NumBModes; ++mode)
                    {
                        Span <byte> reference = it.YuvP.AsSpan(Vp8Encoding.Vp8I4ModeOffsets[mode]);
                        long        score     = (LossyUtils.Vp8_Sse4X4(src, reference) * WebpConstants.RdDistoMult) + (modeCosts[mode] * lambdaDi4);
                        if (score < bestI4Score)
                        {
                            bestI4Mode  = mode;
                            bestI4Score = score;
                        }
                    }

                    i4BitSum         += modeCosts[bestI4Mode];
                    rd.ModesI4[it.I4] = (byte)bestI4Mode;
                    scoreI4          += bestI4Score;
                    if (scoreI4 >= bestScore || i4BitSum > bitLimit)
                    {
                        // Intra4 won't be better than Intra16. Bail out and pick Intra16.
                        isI16 = true;
                        break;
                    }
                    else
                    {
                        // Reconstruct partial block inside YuvOut2 buffer
                        Span <byte> tmpDst = it.YuvOut2.AsSpan(Vp8EncIterator.YOffEnc + WebpLookupTables.Vp8Scan[it.I4]);
                        nz |= ReconstructIntra4(it, dqm, rd.YAcLevels.AsSpan(it.I4 * 16, 16), src, tmpDst, bestI4Mode) << it.I4;
                    }
                }while (it.RotateI4(it.YuvOut2.AsSpan(Vp8EncIterator.YOffEnc)));
            }

            // Final reconstruction, depending on which mode is selected.
            if (!isI16)
            {
                it.SetIntra4Mode(rd.ModesI4);
                it.SwapOut();
                bestScore = scoreI4;
            }
            else
            {
                int intra16Mode = it.Preds[it.PredIdx];
                nz = ReconstructIntra16(it, dqm, rd, it.YuvOut.AsSpan(Vp8EncIterator.YOffEnc), intra16Mode);
            }

            // ... and UV!
            if (refineUvMode)
            {
                int         bestMode    = -1;
                long        bestUvScore = Vp8ModeScore.MaxCost;
                Span <byte> src         = it.YuvIn.AsSpan(Vp8EncIterator.UOffEnc);
                for (mode = 0; mode < WebpConstants.NumPredModes; ++mode)
                {
                    Span <byte> reference = it.YuvP.AsSpan(Vp8Encoding.Vp8UvModeOffsets[mode]);
                    long        score     = (LossyUtils.Vp8_Sse16X8(src, reference) * WebpConstants.RdDistoMult) + (WebpConstants.Vp8FixedCostsUv[mode] * lambdaDuv);
                    if (score < bestUvScore)
                    {
                        bestMode    = mode;
                        bestUvScore = score;
                    }
                }

                it.SetIntraUvMode(bestMode);
            }

            nz |= ReconstructUv(it, dqm, rd, it.YuvOut.AsSpan(Vp8EncIterator.UOffEnc), it.CurrentMacroBlockInfo.UvMode);

            rd.Nz    = (uint)nz;
            rd.Score = bestScore;
        }
Пример #3
0
        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);
        }