Пример #1
0
        private long OneStatPass(int width, int height, int yStride, int uvStride, Vp8RdLevel rdOpt, int nbMbs, PassStats stats)
        {
            Span <byte> y          = this.Y.GetSpan();
            Span <byte> u          = this.U.GetSpan();
            Span <byte> v          = this.V.GetSpan();
            var         it         = new Vp8EncIterator(this.YTop, this.UvTop, this.Nz, this.MbInfo, this.Preds, this.TopDerr, this.Mbw, this.Mbh);
            long        size       = 0;
            long        sizeP0     = 0;
            long        distortion = 0;
            long        pixelCount = nbMbs * 384;

            it.Init();
            this.SetLoopParams(stats.Q);
            var info = new Vp8ModeScore();

            do
            {
                info.Clear();
                it.Import(y, u, v, yStride, uvStride, width, height, false);
                if (this.Decimate(it, ref info, rdOpt))
                {
                    // Just record the number of skips and act like skipProba is not used.
                    ++this.Proba.NbSkip;
                }

                this.RecordResiduals(it, info);
                size       += info.R + info.H;
                sizeP0     += info.H;
                distortion += info.D;

                it.SaveBoundary();
            }while (it.Next() && --nbMbs > 0);

            sizeP0 += this.SegmentHeader.Size;
            if (stats.DoSizeSearch)
            {
                size       += this.Proba.FinalizeSkipProba(this.Mbw, this.Mbh);
                size       += this.Proba.FinalizeTokenProbas();
                size        = ((size + sizeP0 + 1024) >> 11) + HeaderSizeEstimate;
                stats.Value = size;
            }
            else
            {
                stats.Value = GetPsnr(distortion, pixelCount);
            }

            return(sizeP0);
        }
Пример #2
0
        /// <summary>
        /// Only collect statistics(number of skips, token usage, ...).
        /// This is used for deciding optimal probabilities. It also modifies the
        /// quantizer value if some target (size, PSNR) was specified.
        /// </summary>
        private void StatLoop(int width, int height, int yStride, int uvStride)
        {
            int        targetSize  = 0;    // TODO: target size is hardcoded.
            float      targetPsnr  = 0.0f; // TODO: targetPsnr is hardcoded.
            bool       doSearch    = targetSize > 0 || targetPsnr > 0;
            bool       fastProbe   = (this.method == 0 || this.method == WebpEncodingMethod.Level3) && !doSearch;
            int        numPassLeft = this.entropyPasses;
            Vp8RdLevel rdOpt       = this.method >= WebpEncodingMethod.Level3 || doSearch ? Vp8RdLevel.RdOptBasic : Vp8RdLevel.RdOptNone;
            int        nbMbs       = this.Mbw * this.Mbh;

            var stats = new PassStats(targetSize, targetPsnr, QMin, QMax, this.quality);

            this.Proba.ResetTokenStats();

            // Fast mode: quick analysis pass over few mbs. Better than nothing.
            if (fastProbe)
            {
                if (this.method == WebpEncodingMethod.Level3)
                {
                    // We need more stats for method 3 to be reliable.
                    nbMbs = nbMbs > 200 ? nbMbs >> 1 : 100;
                }
                else
                {
                    nbMbs = nbMbs > 200 ? nbMbs >> 2 : 50;
                }
            }

            while (numPassLeft-- > 0)
            {
                bool isLastPass = (MathF.Abs(stats.Dq) <= DqLimit) || (numPassLeft == 0) || (this.maxI4HeaderBits == 0);
                long sizeP0     = this.OneStatPass(width, height, yStride, uvStride, rdOpt, nbMbs, stats);
                if (sizeP0 == 0)
                {
                    return;
                }

                if (this.maxI4HeaderBits > 0 && sizeP0 > (long)Partition0SizeLimit)
                {
                    ++numPassLeft;
                    this.maxI4HeaderBits >>= 1;  // strengthen header bit limitation...
                    continue;                    // ...and start over
                }

                if (isLastPass)
                {
                    break;
                }

                // If no target size: just do several pass without changing 'q'
                if (doSearch)
                {
                    stats.ComputeNextQ();
                    if (MathF.Abs(stats.Dq) <= DqLimit)
                    {
                        break;
                    }
                }
            }

            if (!doSearch || !stats.DoSizeSearch)
            {
                // Need to finalize probas now, since it wasn't done during the search.
                this.Proba.FinalizeSkipProba(this.Mbw, this.Mbh);
                this.Proba.FinalizeTokenProbas();
            }

            // Finalize costs.
            this.Proba.CalculateLevelCosts();
        }