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; } }
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); }
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); }
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); }
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; }
// 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));