private void ResetStats() { Vp8EncProba proba = this.Proba; proba.CalculateLevelCosts(); proba.NbSkip = 0; }
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); }
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(); }
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); }
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); }
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); } }
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); }
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); }