Пример #1
0
        private void SetSegmentProbas()
        {
            int[] p = new int[NumMbSegments];
            int   n;

            for (n = 0; n < this.Mbw * this.Mbh; ++n)
            {
                Vp8MacroBlockInfo mb = this.MbInfo[n];
                ++p[mb.Segment];
            }

            if (this.SegmentHeader.NumSegments > 1)
            {
                byte[] probas = this.Proba.Segments;
                probas[0] = (byte)GetProba(p[0] + p[1], p[2] + p[3]);
                probas[1] = (byte)GetProba(p[0], p[1]);
                probas[2] = (byte)GetProba(p[2], p[3]);

                this.SegmentHeader.UpdateMap = probas[0] != 255 || probas[1] != 255 || probas[2] != 255;
                if (!this.SegmentHeader.UpdateMap)
                {
                    this.ResetSegments();
                }

                this.SegmentHeader.Size = (p[0] * (LossyUtils.Vp8BitCost(0, probas[0]) + LossyUtils.Vp8BitCost(0, probas[1]))) +
                                          (p[1] * (LossyUtils.Vp8BitCost(0, probas[0]) + LossyUtils.Vp8BitCost(1, probas[1]))) +
                                          (p[2] * (LossyUtils.Vp8BitCost(1, probas[0]) + LossyUtils.Vp8BitCost(0, probas[2]))) +
                                          (p[3] * (LossyUtils.Vp8BitCost(1, probas[0]) + LossyUtils.Vp8BitCost(1, probas[2])));
            }
            else
            {
                this.SegmentHeader.UpdateMap = false;
                this.SegmentHeader.Size      = 0;
            }
        }
Пример #2
0
        public int FastMbAnalyze(int quality)
        {
            // Empirical cut-off value, should be around 16 (~=block size). We use the
            // [8-17] range and favor intra4 at high quality, intra16 for low quality.
            int         q          = quality;
            int         kThreshold = 8 + ((17 - 8) * q / 100);
            int         k;
            Span <uint> dc = stackalloc uint[16];
            uint        m;
            uint        m2;

            for (k = 0; k < 16; k += 4)
            {
                LossyUtils.Mean16x4(this.YuvIn.AsSpan(YOffEnc + (k * WebpConstants.Bps)), dc.Slice(k, 4));
            }

            for (m = 0, m2 = 0, k = 0; k < 16; k++)
            {
                m  += dc[k];
                m2 += dc[k] * dc[k];
            }

            if (kThreshold * m2 < m * m)
            {
                this.SetIntra16Mode(0);   // DC16
            }
            else
            {
                byte[] modes = new byte[16];  // DC4
                this.SetIntra4Mode(modes);
            }

            return(0);
        }
Пример #3
0
        private static void RunHadamardTransformTest()
        {
            // arrange
            byte[] a =
            {
                27,   27,  28,  29,  29,  28,  27,  27,  27,  28,  28,  29,  29,  28,  28,  27, 129, 129, 129, 129, 129, 129, 129,
                129, 128, 128, 128, 128, 128, 128, 128, 128,  27,  27,  27,  27,  27,  27,  27,  27,  27,  28,  28,  29,  29,  28,
                28,   27, 129, 129, 129, 129, 129, 129, 129, 129, 128, 128, 128, 128, 128, 128, 128, 128,  27,  27,  26,
                26,   26,  26,  27,  27,  27,  28,  28,  29,  29,  28,  28,  27, 129, 129, 129, 129, 129, 129, 129, 129, 128,
                128, 128, 128, 128, 128, 128, 128,  28,  27,  27,  26,  26,  27,  27,  28,  27,  28,  28,  29,  29,  28,  28, 27
            };

            byte[] b =
            {
                28,   28,  28,  28,  28,  28,  28,  28,  28,  28,  28,  28,  28,  28,  28,  28, 204, 204, 204, 204, 204, 204, 204,
                204, 204, 204, 204, 204, 204, 204, 204, 204,  28,  28,  28,  28,  28,  28,  28,  28,  28,  28,  28,  28,  28,  28,
                28,   28, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204,  28,  28,  28,
                28,   28,  28,  28,  28,  28,  28,  28,  28,  28,  28,  28,  28, 204, 204, 204, 204, 204, 204, 204, 204, 204,
                204, 204, 204, 204, 204, 204, 204,  28,  28,  28,  28,  28,  28,  28,  28,  28,  28,  28,  28,  28,  28,  28, 28
            };

            ushort[] w        = { 38, 32, 20, 9, 32, 28, 17, 7, 20, 17, 10, 4, 9, 7, 4, 2 };
            int      expected = 2;

            // act
            int actual = LossyUtils.Vp8Disto4X4(a, b, w, new int[16]);

            // assert
            Assert.Equal(expected, actual);
        }
Пример #4
0
        private static void RunTransformOneTest()
        {
            // arrange
            short[] src = { -176, 0, 0, 0, 29, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
            byte[]  dst =
            {
                128, 128, 128, 128, 128, 128, 128, 128,   0,   0,   0,   0,   0,   0,   0, 129, 128, 128, 128, 128,
                128, 128, 128, 128,   0,   0,   0,   0,   0,   0,   0, 129, 128, 128, 128, 128, 128, 128, 128, 128,
                0,     0,   0,   0,   0,   0,   0, 129, 128, 128, 128, 128, 128, 128, 128, 128,   0,   0,   0,   0,
                0,     0,   0, 129, 128, 128, 128, 128, 128, 128, 128, 128,   0,   0,   0,   0,   0,   0,   0, 129,
                128, 128, 128, 128, 128, 128, 128, 128,   0,   0,   0,   0,   0,   0,   0, 129, 128, 128, 128, 128,
                128, 128, 128, 128,   0,   0,   0,   0,   0,   0,   0, 129, 128, 128, 128, 128, 128, 128, 128, 128,
                0,     0,   0,   0,   0,   0,   0, 129
            };
            byte[] expected =
            {
                111, 111, 111, 111, 128, 128, 128, 128,   0,   0,   0,   0,   0,   0,   0, 129, 128, 128, 128, 128,
                128, 128, 128, 128,   0,   0,   0,   0,   0,   0,   0, 129, 108, 108, 108, 108, 128, 128, 128, 128,
                0,     0,   0,   0,   0,   0,   0, 129, 128, 128, 128, 128, 128, 128, 128, 128,   0,   0,   0,   0,
                0,     0,   0, 129, 104, 104, 104, 104, 128, 128, 128, 128,   0,   0,   0,   0,   0,   0,   0, 129,
                128, 128, 128, 128, 128, 128, 128, 128,   0,   0,   0,   0,   0,   0,   0, 129, 101, 101, 101, 101,
                128, 128, 128, 128,   0,   0,   0,   0,   0,   0,   0, 129, 128, 128, 128, 128, 128, 128, 128, 128,
                0,     0,   0,   0,   0,   0,   0, 129
            };
            int[] scratch = new int[16];

            // act
            LossyUtils.TransformOne(src, dst, scratch);

            // assert
            Assert.True(expected.SequenceEqual(dst));
        }
Пример #5
0
        private static void RunVp8Sse4X4Test()
        {
            // arrange
            byte[] a =
            {
                27,   27,  28,  29,  29,  28,  27,  27,  27,  28,  28,  29,  29,  28,  28,  27, 129, 129, 129, 129, 129, 129, 129,
                129, 128, 128, 128, 128, 128, 128, 128, 128,  27,  27,  27,  27,  27,  27,  27,  27,  27,  28,  28,  29,  29,  28,
                28,   27, 129, 129, 129, 129, 129, 129, 129, 129, 128, 128, 128, 128, 128, 128, 128, 128,  27,  27,  26,
                26,   26,  26,  27,  27,  27,  28,  28,  29,  29,  28,  28,  27, 129, 129, 129, 129, 129, 129, 129, 129, 128,
                128, 128, 128, 128, 128, 128, 128,  28,  27,  27,  26,  26,  27,  27,  28,  27,  28,  28,  29,  29,  28,  28,  27,
                129, 129, 129, 129, 129, 129, 129, 129, 128, 128, 128, 128, 128, 128, 128, 128
            };

            byte[] b =
            {
                26,   26,  26,  26,  28,  28,  28,  28,  28,  28,  28,  28,  28,  28,  28,  28, 204, 204, 204, 204, 204, 204, 204,
                204, 204, 204, 204, 204, 204, 204, 204, 204,  26,  26,  26,  26,  28,  28,  28,  28,  28,  28,  28,  28,  28,  28,
                28,   28, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204,  26,  26,  26,
                26,   28,  28,  28,  28,  28,  28,  28,  28,  28,  28,  28,  28, 204, 204, 204, 204, 204, 204, 204, 204, 204,
                204, 204, 204, 204, 204, 204, 204,  26,  26,  26,  26,  28,  28,  28,  28,  28,  28,  28,  28,  28,  28,  28,  28,
                204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204
            };

            int expected = 27;

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

            // assert
            Assert.Equal(expected, actual);
        }
Пример #6
0
        private static void RunTransformTwoTest()
        {
            // arrange
            short[] src = { 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 23, 0, 0, -23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
            byte[]  dst =
            {
                103, 103, 103, 103, 103, 103, 103, 103,   0,   0,   0,   0, 169, 169, 169, 169, 171, 171, 171, 171,
                171, 171, 171, 171,   0,   0,   0,   0, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103,
                0,     0,   0,   0, 169, 169, 169, 169, 171, 171, 171, 171, 171, 171, 171, 171,   0,   0,   0,   0,
                103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103,   0,   0,   0,   0, 169, 169, 169, 169,
                171, 171, 171, 171, 171, 171, 171, 171,   0,   0,   0,   0, 103, 103, 103, 103, 103, 103, 103, 103,
                103, 103, 103, 103,   0,   0,   0,   0, 169, 169, 169, 169, 171, 171, 171, 171, 171, 171, 171, 171,
                0,     0,   0,   0,   0,   0,   0, 0
            };
            byte[] expected =
            {
                105, 105, 105, 105, 105, 103, 100,  98,   0,   0,   0,   0, 169, 169, 169, 169, 171, 171, 171, 171, 171, 171,
                171, 171,   0,   0,   0,   0, 103, 103, 103, 103, 105, 105, 105, 105, 108, 105, 102, 100,   0,   0,   0,   0, 169,
                169, 169, 169, 171, 171, 171, 171, 171, 171, 171, 171,   0,   0,   0,   0, 103, 103, 103, 103, 105, 105,
                105, 105, 111, 109, 106, 103,   0,   0,   0,   0, 169, 169, 169, 169, 171, 171, 171, 171, 171, 171, 171,
                171,   0,   0,   0,   0, 103, 103, 103, 103, 105, 105, 105, 105, 113, 111, 108, 106,   0,   0,   0,   0, 169, 169,
                169, 169, 171, 171, 171, 171, 171, 171, 171, 171,   0,   0,   0,   0,   0,   0,   0, 0
            };
            int[] scratch = new int[16];

            // act
            LossyUtils.TransformTwo(src, dst, scratch);

            // assert
            Assert.True(expected.SequenceEqual(dst));
        }
Пример #7
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);
        }
Пример #8
0
        public int FinalizeSkipProba(int mbw, int mbh)
        {
            int nbMbs    = mbw * mbh;
            int nbEvents = this.NbSkip;

            this.SkipProba    = (byte)CalcSkipProba(nbEvents, nbMbs);
            this.UseSkipProba = this.SkipProba < SkipProbaThreshold;

            int size = 256;

            if (this.UseSkipProba)
            {
                size += (nbEvents * LossyUtils.Vp8BitCost(1, this.SkipProba)) + ((nbMbs - nbEvents) * LossyUtils.Vp8BitCost(0, this.SkipProba));
                size += 8 * 256;   // cost of signaling the skipProba itself.
            }

            return(size);
        }
Пример #9
0
        public static int ReconstructIntra16(Vp8EncIterator it, Vp8SegmentInfo dqm, Vp8ModeScore rd, Span <byte> yuvOut, int mode)
        {
            Span <byte>  reference = it.YuvP.AsSpan(Vp8Encoding.Vp8I16ModeOffsets[mode]);
            Span <byte>  src       = it.YuvIn.AsSpan(Vp8EncIterator.YOffEnc);
            int          nz        = 0;
            int          n;
            Span <short> shortScratchSpan = it.Scratch2.AsSpan();
            Span <int>   scratch          = it.Scratch3.AsSpan(0, 16);

            shortScratchSpan.Clear();
            scratch.Clear();
            Span <short> dcTmp = shortScratchSpan.Slice(0, 16);
            Span <short> tmp   = shortScratchSpan.Slice(16, 16 * 16);

            for (n = 0; n < 16; n += 2)
            {
                Vp8Encoding.FTransform2(
                    src.Slice(WebpLookupTables.Vp8Scan[n]),
                    reference.Slice(WebpLookupTables.Vp8Scan[n]),
                    tmp.Slice(n * 16, 16),
                    tmp.Slice((n + 1) * 16, 16),
                    scratch);
            }

            Vp8Encoding.FTransformWht(tmp, dcTmp, scratch);
            nz |= QuantizeBlock(dcTmp, rd.YDcLevels, ref dqm.Y2) << 24;

            for (n = 0; n < 16; n += 2)
            {
                // Zero-out the first coeff, so that: a) nz is correct below, and
                // b) finding 'last' non-zero coeffs in SetResidualCoeffs() is simplified.
                tmp[n * 16] = tmp[(n + 1) * 16] = 0;
                nz         |= Quantize2Blocks(tmp.Slice(n * 16, 32), rd.YAcLevels.AsSpan(n * 16, 32), ref dqm.Y1) << n;
            }

            // Transform back.
            LossyUtils.TransformWht(dcTmp, tmp, scratch);
            for (n = 0; n < 16; n += 2)
            {
                Vp8Encoding.ITransformTwo(reference.Slice(WebpLookupTables.Vp8Scan[n]), tmp.Slice(n * 16, 32), yuvOut.Slice(WebpLookupTables.Vp8Scan[n]), scratch);
            }

            return(nz);
        }
Пример #10
0
        private static int VariableLevelCost(int level, Span <byte> probas)
        {
            int pattern = WebpLookupTables.Vp8LevelCodes[level - 1][0];
            int bits    = WebpLookupTables.Vp8LevelCodes[level - 1][1];
            int cost    = 0;

            for (int i = 2; pattern != 0; i++)
            {
                if ((pattern & 1) != 0)
                {
                    cost += LossyUtils.Vp8BitCost(bits & 1, probas[i]);
                }

                bits    >>= 1;
                pattern >>= 1;
            }

            return(cost);
        }
Пример #11
0
        public int FinalizeTokenProbas()
        {
            bool hasChanged = false;
            int  size       = 0;

            for (int t = 0; t < WebpConstants.NumTypes; ++t)
            {
                for (int b = 0; b < WebpConstants.NumBands; ++b)
                {
                    for (int c = 0; c < WebpConstants.NumCtx; ++c)
                    {
                        for (int p = 0; p < WebpConstants.NumProbas; ++p)
                        {
                            uint stats       = this.Stats[t][b].Stats[c].Stats[p];
                            int  nb          = (int)((stats >> 0) & 0xffff);
                            int  total       = (int)((stats >> 16) & 0xffff);
                            int  updateProba = WebpLookupTables.CoeffsUpdateProba[t, b, c, p];
                            int  oldP        = WebpLookupTables.DefaultCoeffsProba[t, b, c, p];
                            int  newP        = CalcTokenProba(nb, total);
                            int  oldCost     = BranchCost(nb, total, oldP) + LossyUtils.Vp8BitCost(0, (byte)updateProba);
                            int  newCost     = BranchCost(nb, total, newP) + LossyUtils.Vp8BitCost(1, (byte)updateProba) + (8 * 256);
                            bool useNewP     = oldCost > newCost;
                            size += LossyUtils.Vp8BitCost(useNewP ? 1 : 0, (byte)updateProba);
                            if (useNewP)
                            {
                                // Only use proba that seem meaningful enough.
                                this.Coeffs[t][b].Probabilities[c].Probabilities[p] = (byte)newP;
                                hasChanged |= newP != oldP;
                                size       += 8 * 256;
                            }
                            else
                            {
                                this.Coeffs[t][b].Probabilities[c].Probabilities[p] = (byte)oldP;
                            }
                        }
                    }
                }
            }

            this.Dirty = hasChanged;
            return(size);
        }
Пример #12
0
        public void CalculateLevelCosts()
        {
            if (!this.Dirty)
            {
                return; // Nothing to do.
            }

            for (int ctype = 0; ctype < WebpConstants.NumTypes; ++ctype)
            {
                for (int band = 0; band < WebpConstants.NumBands; ++band)
                {
                    for (int ctx = 0; ctx < WebpConstants.NumCtx; ++ctx)
                    {
                        Vp8ProbaArray p        = this.Coeffs[ctype][band].Probabilities[ctx];
                        Vp8CostArray  table    = this.LevelCost[ctype][band].Costs[ctx];
                        int           cost0    = ctx > 0 ? LossyUtils.Vp8BitCost(1, p.Probabilities[0]) : 0;
                        int           costBase = LossyUtils.Vp8BitCost(1, p.Probabilities[1]) + cost0;
                        int           v;
                        table.Costs[0] = (ushort)(LossyUtils.Vp8BitCost(0, p.Probabilities[1]) + cost0);
                        for (v = 1; v <= MaxVariableLevel; ++v)
                        {
                            table.Costs[v] = (ushort)(costBase + VariableLevelCost(v, p.Probabilities));
                        }

                        // Starting at level 67 and up, the variable part of the cost is actually constant
                    }
                }

                for (int n = 0; n < 16; ++n)
                {
                    for (int ctx = 0; ctx < WebpConstants.NumCtx; ++ctx)
                    {
                        Vp8CostArray dst = this.RemappedCosts[ctype][n].Costs[ctx];
                        Vp8CostArray src = this.LevelCost[ctype][WebpConstants.Vp8EncBands[n]].Costs[ctx];
                        src.Costs.CopyTo(dst.Costs.AsSpan());
                    }
                }
            }

            this.Dirty = false;
        }
Пример #13
0
        private static void RunMean16x4Test()
        {
            // arrange
            byte[] input =
            {
                154, 145, 102, 115, 127, 129, 126, 125, 126, 120, 133, 152, 157, 153, 119,  94, 104, 116, 111, 113,
                113, 109, 105, 124, 173, 175, 177, 170, 175, 172, 166, 164, 151, 141,  99, 114, 125, 126, 135, 150,
                133, 115, 127, 149, 141, 168, 100,  54, 110, 117, 115, 116, 119, 115, 117, 130, 174, 174, 174, 157,
                146, 171, 166, 158, 117, 140,  96, 111, 119, 119, 136, 171, 188, 134, 121, 126, 136, 119,  59,  77,
                109, 115, 113, 120, 120, 117, 128, 115, 174, 173, 173, 161, 152, 148, 153, 162, 105, 140,  96, 114,
                115, 122, 141, 173, 190, 190, 142, 106, 151,  78,  66, 141, 110, 117, 123, 136, 118, 124, 127, 114,
                173, 175, 166, 155, 155, 159, 159, 158
            };
            uint[] dc         = new uint[4];
            uint[] expectedDc = { 1940, 2139, 2252, 1813 };

            // act
            LossyUtils.Mean16x4(input, dc);

            // assert
            Assert.True(dc.SequenceEqual(expectedDc));
        }
Пример #14
0
        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);
        }
Пример #15
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);
            }
        }
Пример #16
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;
        }
Пример #17
0
        private static void RunVp8Sse16X16Test()
        {
            // arrange
            byte[] a =
            {
                154, 154, 151, 151, 149, 148, 151, 157, 163, 163, 154, 132, 102,  98, 104, 108, 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, 204, 204, 204, 204, 204, 204, 204, 204,
                204, 204, 204, 204, 204, 204, 204, 204, 154, 151, 165, 156, 141, 137, 146, 158, 152, 159, 152, 133,
                90,   88,  99, 106, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204,
                154, 160, 164, 150, 126, 127, 149, 159, 155, 161, 153, 131,  84,  86,  97, 103, 204, 204, 204, 204,
                204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 157, 167, 157, 137, 102, 128, 155, 161,
                157, 159, 154, 134,  84,  82,  97, 102, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204,
                204, 204, 204, 204, 163, 163, 150, 113,  78, 132, 156, 162, 159, 160, 154, 132,  83,  78,  91,  97, 204,
                204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 163, 157, 137,  80,  78,
                131, 154, 163, 157, 159, 149, 131,  82,  77,  94, 100, 204, 204, 204, 204, 204, 204, 204, 204, 204,
                204, 204, 204, 204, 204, 204, 204, 159, 151, 108,  72,  88, 132, 156, 162, 159, 157, 151, 130,  79,  78,
                95,  102, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 151, 130,
                82,   82,  89, 134, 154, 161, 161, 157, 152, 129,  81,  77,  95, 102, 204, 204, 204, 204, 204, 204, 204,
                204, 204, 204, 204, 204, 204, 204, 204, 204
            };

            byte[] b =
            {
                150, 150, 150, 150, 146, 149, 152, 154, 164, 166, 154, 132,  99,  92, 106, 112, 204, 204, 204, 204,
                204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 150, 150, 150, 150, 146, 149, 152, 154,
                161, 164, 151, 130,  93,  86, 100, 106, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204,
                204, 204, 204, 204, 150, 150, 150, 150, 146, 149, 152, 154, 158, 161, 148, 127,  93,  86, 100, 106,
                204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 150, 150, 150, 150,
                146, 149, 152, 154, 156, 159, 146, 125,  99,  92, 106, 112, 204, 204, 204, 204, 204, 204, 204, 204,
                204, 204, 204, 204, 204, 204, 204, 204, 148, 148, 148, 148, 149, 158, 162, 159, 155, 155, 153, 129,
                94,   87, 101, 106, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204,
                151, 151, 151, 151, 152, 159, 161, 156, 155, 155, 153, 129,  94,  87, 101, 106, 204, 204, 204, 204,
                204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 154, 154, 154, 154, 156, 161, 159, 152,
                155, 155, 153, 129,  94,  87, 101, 106, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204,
                204, 204, 204, 204, 156, 156, 156, 156, 159, 162, 158, 149, 155, 155, 153, 129,  94,  87, 101, 106,
                204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 152, 153, 157, 162,
                150, 149, 149, 151, 155, 160, 150, 131,  91,  90, 104, 104, 204, 204, 204, 204, 204, 204, 204, 204,
                204, 204, 204, 204, 204, 204, 204, 204, 152, 156, 158, 157, 140, 137, 145, 159, 155, 160, 150, 131,
                89,   88, 102, 101, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204,
                153, 161, 160, 149, 118, 128, 147, 162, 155, 160, 150, 131,  86,  85,  99,  98, 204, 204, 204, 204, 204,
                204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 154, 165, 161, 144,  96, 128, 154, 159, 155,
                160, 150, 131,  83,  82,  97,  96, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204,
                204, 204, 161, 160, 149, 105,  78, 127, 156, 170, 156, 156, 154, 130,  81,  77,  95, 102, 204, 204, 204,
                204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 160, 160, 133,  85,  81, 129, 155,
                167, 156, 156, 154, 130,  81,  77,  95, 102, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204,
                204, 204, 204, 204, 204, 156, 147, 109,  76,  85, 130, 153, 163, 156, 156, 154, 130,  81,  77,  95, 102,
                204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 152, 128,  87,  83,
                88,  132, 152, 159, 156, 156, 154, 130,  81,  77,  95, 102, 204, 204, 204, 204, 204, 204, 204, 204, 204,
                204, 204, 204, 204, 204, 204, 204
            };

            int expected = 2063;

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

            // assert
            Assert.Equal(expected, actual);
        }
Пример #18
0
 // Cost of coding 'nb' 1's and 'total-nb' 0's using 'proba' probability.
 private static int BranchCost(int nb, int total, int proba) => (nb * LossyUtils.Vp8BitCost(1, (byte)proba)) + ((total - nb) * LossyUtils.Vp8BitCost(0, (byte)proba));
Пример #19
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);
        }