vp8enc

package
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 14, 2026 License: MIT Imports: 7 Imported by: 0

Documentation

Overview

Package vp8enc implements a VP8 (lossy) keyframe encoder for WebP.

All constants in this file are taken directly from RFC 6386 (The VP8 Data Format and Decoding Guide). They are facts about the codec, not original authorship, and are used here as specification constants.

Cross-referenced against the pure-Go decoder at golang.org/x/image/vp8 (BSD-3-Clause) to guarantee bit-exact roundtrip compatibility.

Index

Constants

View Source
const (
	ModeDC = 0
	ModeVE = 1
	ModeHE = 2
	ModeTM = 3
)

Y16 mode enum used by WriteMBModes. The decoder tree is:

readBit(156) -> if 0: readBit(163) -> 0:DC, 1:VE
              -> if 1: readBit(128) -> 0:HE, 1:TM
View Source
const (
	PlaneY1WithY2 = 0 // Y AC coefficients when MB has a Y2 block
	PlaneY2       = 1 // Y2 DC-plane (16 DC coefficients combined via WHT)
	PlaneUV       = 2 // Chroma
	PlaneY1SansY2 = 3 // Y coefficients when MB has no Y2 (B_PRED mode)
	NumPlanes     = 4
)

Plane indices (RFC 6386 section 13.3).

View Source
const (
	NumBands    = 8
	NumContexts = 3
	NumProbs    = 11
)
View Source
const (
	DctEOB    = 0 // End of block
	DctZero   = 1
	DctVal1   = 2
	DctVal2   = 3
	DctVal3   = 4
	DctVal4   = 5
	DctCat1   = 6  // [5..6]
	DctCat2   = 7  // [7..10]
	DctCat3   = 8  // [11..18]
	DctCat4   = 9  // [19..34]
	DctCat5   = 10 // [35..66]
	DctCat6   = 11 // [67..2048]
	NumTokens = 12
)

Token values (RFC 6386 section 13.2).

View Source
const (
	ModeI4DC = 0
	ModeI4TM = 1
	ModeI4VE = 2
	ModeI4HE = 3
	ModeI4RD = 4
	ModeI4VR = 5
	ModeI4LD = 6
	ModeI4VL = 7
	ModeI4HD = 8
	ModeI4HU = 9
)

I4 mode enum (extends the I16/UV8 Mode* constants). These match the decoder's predDC..predHU values so we can use them as array indices into PredProb.

View Source
const (
	// VP8 image dimension is stored in 14 bits, so the cap is one less than
	// VP8L's 16384-pixel cap.
	MaxDimension = (1 << 14) - 1
)
View Source
const NumPredModes = 10

NumPredModes is the number of I4 prediction modes.

View Source
const UniformProb = 128

UniformProb is the canonical 50/50 probability used for uncoded bits carried through the boolean coder (RFC 6386 section 7).

Variables

View Source
var CoefBands = [16]int{0, 1, 2, 3, 6, 4, 5, 6, 6, 6, 6, 6, 6, 6, 6, 7}

CoefBands maps a coefficient's zigzag position to one of 8 coding bands (RFC 6386 section 13.3). Used as an index into the token probability table.

View Source
var CoefFirst = [NumPlanes]int{
	PlaneY1WithY2: 1,
	PlaneY2:       0,
	PlaneUV:       0,
	PlaneY1SansY2: 0,
}

Block scan order: for coding coefficients, we walk position 0..15 in zigzag order. When a block has a Y2 (DC predicted separately), the Y1 plane starts at zigzag index 1 (i.e. skips DC).

CoefFirst[plane] = starting zigzag index.

View Source
var CoefTree = [22]int8{
	-DctEOB, 2,
	-DctZero, 4,
	-DctVal1, 6,
	8, 12,
	-DctVal2, 10,
	-DctVal3, -DctVal4,
	14, 16,
	-DctCat1, -DctCat2,
	18, 20,
	-DctCat3, -DctCat4,
	-DctCat5, -DctCat6,
}

Token tree structure (RFC 6386 section 13.2 figure). Each internal node has a probability (from the context tables) and two children. Traversing left on a "0" bit, right on a "1" bit. The encoder walks the tree from the token value back to the root to produce the bit sequence.

Tree layout (-token means leaf with that token value):

   root
   /  \
EOB    node1
      /    \
   Zero   node2
         /    \
      Val1   node3
            /    \
         node4  node5
        /   \    /  \
     Val2 Val3 Cat1 node6 ...
View Source
var DctCategories = [6]CategoryInfo{
	{Base: 5, Bits: []int{159}},
	{Base: 7, Bits: []int{165, 145}},
	{Base: 11, Bits: []int{173, 148, 140}},
	{Base: 19, Bits: []int{176, 155, 140, 135}},
	{Base: 35, Bits: []int{180, 157, 141, 134, 130}},
	{Base: 67, Bits: []int{254, 254, 243, 230, 196, 177, 153, 140, 133, 130, 129}},
}

DctCategories is indexed by (token-DctCat1). Each entry gives the base value of the category and the fixed probability table used to code the magnitude extra bits.

View Source
var DefaultTokenProb = [NumPlanes][NumBands][NumContexts][NumProbs]uint8{
	{
		{
			{128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128},
			{128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128},
			{128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128},
		},
		{
			{253, 136, 254, 255, 228, 219, 128, 128, 128, 128, 128},
			{189, 129, 242, 255, 227, 213, 255, 219, 128, 128, 128},
			{106, 126, 227, 252, 214, 209, 255, 255, 128, 128, 128},
		},
		{
			{1, 98, 248, 255, 236, 226, 255, 255, 128, 128, 128},
			{181, 133, 238, 254, 221, 234, 255, 154, 128, 128, 128},
			{78, 134, 202, 247, 198, 180, 255, 219, 128, 128, 128},
		},
		{
			{1, 185, 249, 255, 243, 255, 128, 128, 128, 128, 128},
			{184, 150, 247, 255, 236, 224, 128, 128, 128, 128, 128},
			{77, 110, 216, 255, 236, 230, 128, 128, 128, 128, 128},
		},
		{
			{1, 101, 251, 255, 241, 255, 128, 128, 128, 128, 128},
			{170, 139, 241, 252, 236, 209, 255, 255, 128, 128, 128},
			{37, 116, 196, 243, 228, 255, 255, 255, 128, 128, 128},
		},
		{
			{1, 204, 254, 255, 245, 255, 128, 128, 128, 128, 128},
			{207, 160, 250, 255, 238, 128, 128, 128, 128, 128, 128},
			{102, 103, 231, 255, 211, 171, 128, 128, 128, 128, 128},
		},
		{
			{1, 152, 252, 255, 240, 255, 128, 128, 128, 128, 128},
			{177, 135, 243, 255, 234, 225, 128, 128, 128, 128, 128},
			{80, 129, 211, 255, 194, 224, 128, 128, 128, 128, 128},
		},
		{
			{1, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128},
			{246, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128},
			{255, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128},
		},
	},
	{
		{
			{198, 35, 237, 223, 193, 187, 162, 160, 145, 155, 62},
			{131, 45, 198, 221, 172, 176, 220, 157, 252, 221, 1},
			{68, 47, 146, 208, 149, 167, 221, 162, 255, 223, 128},
		},
		{
			{1, 149, 241, 255, 221, 224, 255, 255, 128, 128, 128},
			{184, 141, 234, 253, 222, 220, 255, 199, 128, 128, 128},
			{81, 99, 181, 242, 176, 190, 249, 202, 255, 255, 128},
		},
		{
			{1, 129, 232, 253, 214, 197, 242, 196, 255, 255, 128},
			{99, 121, 210, 250, 201, 198, 255, 202, 128, 128, 128},
			{23, 91, 163, 242, 170, 187, 247, 210, 255, 255, 128},
		},
		{
			{1, 200, 246, 255, 234, 255, 128, 128, 128, 128, 128},
			{109, 178, 241, 255, 231, 245, 255, 255, 128, 128, 128},
			{44, 130, 201, 253, 205, 192, 255, 255, 128, 128, 128},
		},
		{
			{1, 132, 239, 251, 219, 209, 255, 165, 128, 128, 128},
			{94, 136, 225, 251, 218, 190, 255, 255, 128, 128, 128},
			{22, 100, 174, 245, 186, 161, 255, 199, 128, 128, 128},
		},
		{
			{1, 182, 249, 255, 232, 235, 128, 128, 128, 128, 128},
			{124, 143, 241, 255, 227, 234, 128, 128, 128, 128, 128},
			{35, 77, 181, 251, 193, 211, 255, 205, 128, 128, 128},
		},
		{
			{1, 157, 247, 255, 236, 231, 255, 255, 128, 128, 128},
			{121, 141, 235, 255, 225, 227, 255, 255, 128, 128, 128},
			{45, 99, 188, 251, 195, 217, 255, 224, 128, 128, 128},
		},
		{
			{1, 1, 251, 255, 213, 255, 128, 128, 128, 128, 128},
			{203, 1, 248, 255, 255, 128, 128, 128, 128, 128, 128},
			{137, 1, 177, 255, 224, 255, 128, 128, 128, 128, 128},
		},
	},
	{
		{
			{253, 9, 248, 251, 207, 208, 255, 192, 128, 128, 128},
			{175, 13, 224, 243, 193, 185, 249, 198, 255, 255, 128},
			{73, 17, 171, 221, 161, 179, 236, 167, 255, 234, 128},
		},
		{
			{1, 95, 247, 253, 212, 183, 255, 255, 128, 128, 128},
			{239, 90, 244, 250, 211, 209, 255, 255, 128, 128, 128},
			{155, 77, 195, 248, 188, 195, 255, 255, 128, 128, 128},
		},
		{
			{1, 24, 239, 251, 218, 219, 255, 205, 128, 128, 128},
			{201, 51, 219, 255, 196, 186, 128, 128, 128, 128, 128},
			{69, 46, 190, 239, 201, 218, 255, 228, 128, 128, 128},
		},
		{
			{1, 191, 251, 255, 255, 128, 128, 128, 128, 128, 128},
			{223, 165, 249, 255, 213, 255, 128, 128, 128, 128, 128},
			{141, 124, 248, 255, 255, 128, 128, 128, 128, 128, 128},
		},
		{
			{1, 16, 248, 255, 255, 128, 128, 128, 128, 128, 128},
			{190, 36, 230, 255, 236, 255, 128, 128, 128, 128, 128},
			{149, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128},
		},
		{
			{1, 226, 255, 128, 128, 128, 128, 128, 128, 128, 128},
			{247, 192, 255, 128, 128, 128, 128, 128, 128, 128, 128},
			{240, 128, 255, 128, 128, 128, 128, 128, 128, 128, 128},
		},
		{
			{1, 134, 252, 255, 255, 128, 128, 128, 128, 128, 128},
			{213, 62, 250, 255, 255, 128, 128, 128, 128, 128, 128},
			{55, 93, 255, 128, 128, 128, 128, 128, 128, 128, 128},
		},
		{
			{128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128},
			{128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128},
			{128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128},
		},
	},
	{
		{
			{202, 24, 213, 235, 186, 191, 220, 160, 240, 175, 255},
			{126, 38, 182, 232, 169, 184, 228, 174, 255, 187, 128},
			{61, 46, 138, 219, 151, 178, 240, 170, 255, 216, 128},
		},
		{
			{1, 112, 230, 250, 199, 191, 247, 159, 255, 255, 128},
			{166, 109, 228, 252, 211, 215, 255, 174, 128, 128, 128},
			{39, 77, 162, 232, 172, 180, 245, 178, 255, 255, 128},
		},
		{
			{1, 52, 220, 246, 198, 199, 249, 220, 255, 255, 128},
			{124, 74, 191, 243, 183, 193, 250, 221, 255, 255, 128},
			{24, 71, 130, 219, 154, 170, 243, 182, 255, 255, 128},
		},
		{
			{1, 182, 225, 249, 219, 240, 255, 224, 128, 128, 128},
			{149, 150, 226, 252, 216, 205, 255, 171, 128, 128, 128},
			{28, 108, 170, 242, 183, 194, 254, 223, 255, 255, 128},
		},
		{
			{1, 81, 230, 252, 204, 203, 255, 192, 128, 128, 128},
			{123, 102, 209, 247, 188, 196, 255, 233, 128, 128, 128},
			{20, 95, 153, 243, 164, 173, 255, 203, 128, 128, 128},
		},
		{
			{1, 222, 248, 255, 216, 213, 128, 128, 128, 128, 128},
			{168, 175, 246, 252, 235, 205, 255, 255, 128, 128, 128},
			{47, 116, 215, 255, 211, 212, 255, 255, 128, 128, 128},
		},
		{
			{1, 121, 236, 253, 212, 214, 255, 255, 128, 128, 128},
			{141, 84, 213, 252, 201, 202, 255, 219, 128, 128, 128},
			{42, 80, 160, 240, 162, 185, 255, 205, 128, 128, 128},
		},
		{
			{1, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128},
			{244, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128},
			{238, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128},
		},
	},
}

DefaultTokenProb is the default probability table used to arithmetic-code DCT/WHT coefficients (RFC 6386 section 13.5). Indexed by [plane][band]context[prob].

View Source
var DequantTableAC = [128]uint16{}/* 128 elements not displayed */
View Source
var DequantTableDC = [128]uint16{}/* 128 elements not displayed */

DequantTableDC and DequantTableAC are the quantizer lookup tables (RFC 6386 section 14.1). Index is the "quantizer index" in [0, 127].

View Source
var PredProb = [NumPredModes][NumPredModes][9]uint8{
	{
		{231, 120, 48, 89, 115, 113, 120, 152, 112},
		{152, 179, 64, 126, 170, 118, 46, 70, 95},
		{175, 69, 143, 80, 85, 82, 72, 155, 103},
		{56, 58, 10, 171, 218, 189, 17, 13, 152},
		{114, 26, 17, 163, 44, 195, 21, 10, 173},
		{121, 24, 80, 195, 26, 62, 44, 64, 85},
		{144, 71, 10, 38, 171, 213, 144, 34, 26},
		{170, 46, 55, 19, 136, 160, 33, 206, 71},
		{63, 20, 8, 114, 114, 208, 12, 9, 226},
		{81, 40, 11, 96, 182, 84, 29, 16, 36},
	},
	{
		{134, 183, 89, 137, 98, 101, 106, 165, 148},
		{72, 187, 100, 130, 157, 111, 32, 75, 80},
		{66, 102, 167, 99, 74, 62, 40, 234, 128},
		{41, 53, 9, 178, 241, 141, 26, 8, 107},
		{74, 43, 26, 146, 73, 166, 49, 23, 157},
		{65, 38, 105, 160, 51, 52, 31, 115, 128},
		{104, 79, 12, 27, 217, 255, 87, 17, 7},
		{87, 68, 71, 44, 114, 51, 15, 186, 23},
		{47, 41, 14, 110, 182, 183, 21, 17, 194},
		{66, 45, 25, 102, 197, 189, 23, 18, 22},
	},
	{
		{88, 88, 147, 150, 42, 46, 45, 196, 205},
		{43, 97, 183, 117, 85, 38, 35, 179, 61},
		{39, 53, 200, 87, 26, 21, 43, 232, 171},
		{56, 34, 51, 104, 114, 102, 29, 93, 77},
		{39, 28, 85, 171, 58, 165, 90, 98, 64},
		{34, 22, 116, 206, 23, 34, 43, 166, 73},
		{107, 54, 32, 26, 51, 1, 81, 43, 31},
		{68, 25, 106, 22, 64, 171, 36, 225, 114},
		{34, 19, 21, 102, 132, 188, 16, 76, 124},
		{62, 18, 78, 95, 85, 57, 50, 48, 51},
	},
	{
		{193, 101, 35, 159, 215, 111, 89, 46, 111},
		{60, 148, 31, 172, 219, 228, 21, 18, 111},
		{112, 113, 77, 85, 179, 255, 38, 120, 114},
		{40, 42, 1, 196, 245, 209, 10, 25, 109},
		{88, 43, 29, 140, 166, 213, 37, 43, 154},
		{61, 63, 30, 155, 67, 45, 68, 1, 209},
		{100, 80, 8, 43, 154, 1, 51, 26, 71},
		{142, 78, 78, 16, 255, 128, 34, 197, 171},
		{41, 40, 5, 102, 211, 183, 4, 1, 221},
		{51, 50, 17, 168, 209, 192, 23, 25, 82},
	},
	{
		{138, 31, 36, 171, 27, 166, 38, 44, 229},
		{67, 87, 58, 169, 82, 115, 26, 59, 179},
		{63, 59, 90, 180, 59, 166, 93, 73, 154},
		{40, 40, 21, 116, 143, 209, 34, 39, 175},
		{47, 15, 16, 183, 34, 223, 49, 45, 183},
		{46, 17, 33, 183, 6, 98, 15, 32, 183},
		{57, 46, 22, 24, 128, 1, 54, 17, 37},
		{65, 32, 73, 115, 28, 128, 23, 128, 205},
		{40, 3, 9, 115, 51, 192, 18, 6, 223},
		{87, 37, 9, 115, 59, 77, 64, 21, 47},
	},
	{
		{104, 55, 44, 218, 9, 54, 53, 130, 226},
		{64, 90, 70, 205, 40, 41, 23, 26, 57},
		{54, 57, 112, 184, 5, 41, 38, 166, 213},
		{30, 34, 26, 133, 152, 116, 10, 32, 134},
		{39, 19, 53, 221, 26, 114, 32, 73, 255},
		{31, 9, 65, 234, 2, 15, 1, 118, 73},
		{75, 32, 12, 51, 192, 255, 160, 43, 51},
		{88, 31, 35, 67, 102, 85, 55, 186, 85},
		{56, 21, 23, 111, 59, 205, 45, 37, 192},
		{55, 38, 70, 124, 73, 102, 1, 34, 98},
	},
	{
		{125, 98, 42, 88, 104, 85, 117, 175, 82},
		{95, 84, 53, 89, 128, 100, 113, 101, 45},
		{75, 79, 123, 47, 51, 128, 81, 171, 1},
		{57, 17, 5, 71, 102, 57, 53, 41, 49},
		{38, 33, 13, 121, 57, 73, 26, 1, 85},
		{41, 10, 67, 138, 77, 110, 90, 47, 114},
		{115, 21, 2, 10, 102, 255, 166, 23, 6},
		{101, 29, 16, 10, 85, 128, 101, 196, 26},
		{57, 18, 10, 102, 102, 213, 34, 20, 43},
		{117, 20, 15, 36, 163, 128, 68, 1, 26},
	},
	{
		{102, 61, 71, 37, 34, 53, 31, 243, 192},
		{69, 60, 71, 38, 73, 119, 28, 222, 37},
		{68, 45, 128, 34, 1, 47, 11, 245, 171},
		{62, 17, 19, 70, 146, 85, 55, 62, 70},
		{37, 43, 37, 154, 100, 163, 85, 160, 1},
		{63, 9, 92, 136, 28, 64, 32, 201, 85},
		{75, 15, 9, 9, 64, 255, 184, 119, 16},
		{86, 6, 28, 5, 64, 255, 25, 248, 1},
		{56, 8, 17, 132, 137, 255, 55, 116, 128},
		{58, 15, 20, 82, 135, 57, 26, 121, 40},
	},
	{
		{164, 50, 31, 137, 154, 133, 25, 35, 218},
		{51, 103, 44, 131, 131, 123, 31, 6, 158},
		{86, 40, 64, 135, 148, 224, 45, 183, 128},
		{22, 26, 17, 131, 240, 154, 14, 1, 209},
		{45, 16, 21, 91, 64, 222, 7, 1, 197},
		{56, 21, 39, 155, 60, 138, 23, 102, 213},
		{83, 12, 13, 54, 192, 255, 68, 47, 28},
		{85, 26, 85, 85, 128, 128, 32, 146, 171},
		{18, 11, 7, 63, 144, 171, 4, 4, 246},
		{35, 27, 10, 146, 174, 171, 12, 26, 128},
	},
	{
		{190, 80, 35, 99, 180, 80, 126, 54, 45},
		{85, 126, 47, 87, 176, 51, 41, 20, 32},
		{101, 75, 128, 139, 118, 146, 116, 128, 85},
		{56, 41, 15, 176, 236, 85, 37, 9, 62},
		{71, 30, 17, 119, 118, 255, 17, 18, 138},
		{101, 38, 60, 138, 55, 70, 43, 26, 142},
		{146, 36, 19, 30, 171, 255, 97, 27, 20},
		{138, 45, 61, 62, 219, 1, 81, 188, 64},
		{32, 41, 20, 117, 151, 142, 20, 21, 163},
		{112, 19, 12, 61, 195, 128, 48, 4, 24},
	},
}

PredProb is the probability table used to tree-code I4 sub-block modes given the modes of the sub-blocks above and to the left (RFC 6386 section 11.5). Indexed [above][left][prob-index 0..8].

View Source
var TokenProbUpdateProb = [NumPlanes][NumBands][NumContexts][NumProbs]uint8{
	{
		{
			{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
			{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
			{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
		},
		{
			{176, 246, 255, 255, 255, 255, 255, 255, 255, 255, 255},
			{223, 241, 252, 255, 255, 255, 255, 255, 255, 255, 255},
			{249, 253, 253, 255, 255, 255, 255, 255, 255, 255, 255},
		},
		{
			{255, 244, 252, 255, 255, 255, 255, 255, 255, 255, 255},
			{234, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255},
			{253, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
		},
		{
			{255, 246, 254, 255, 255, 255, 255, 255, 255, 255, 255},
			{239, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255},
			{254, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255},
		},
		{
			{255, 248, 254, 255, 255, 255, 255, 255, 255, 255, 255},
			{251, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255},
			{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
		},
		{
			{255, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255},
			{251, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255},
			{254, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255},
		},
		{
			{255, 254, 253, 255, 254, 255, 255, 255, 255, 255, 255},
			{250, 255, 254, 255, 254, 255, 255, 255, 255, 255, 255},
			{254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
		},
		{
			{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
			{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
			{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
		},
	},
	{
		{
			{217, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
			{225, 252, 241, 253, 255, 255, 254, 255, 255, 255, 255},
			{234, 250, 241, 250, 253, 255, 253, 254, 255, 255, 255},
		},
		{
			{255, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255},
			{223, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255},
			{238, 253, 254, 254, 255, 255, 255, 255, 255, 255, 255},
		},
		{
			{255, 248, 254, 255, 255, 255, 255, 255, 255, 255, 255},
			{249, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255},
			{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
		},
		{
			{255, 253, 255, 255, 255, 255, 255, 255, 255, 255, 255},
			{247, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255},
			{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
		},
		{
			{255, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255},
			{252, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
			{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
		},
		{
			{255, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255},
			{253, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
			{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
		},
		{
			{255, 254, 253, 255, 255, 255, 255, 255, 255, 255, 255},
			{250, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
			{254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
		},
		{
			{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
			{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
			{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
		},
	},
	{
		{
			{186, 251, 250, 255, 255, 255, 255, 255, 255, 255, 255},
			{234, 251, 244, 254, 255, 255, 255, 255, 255, 255, 255},
			{251, 251, 243, 253, 254, 255, 254, 255, 255, 255, 255},
		},
		{
			{255, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255},
			{236, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255},
			{251, 253, 253, 254, 254, 255, 255, 255, 255, 255, 255},
		},
		{
			{255, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255},
			{254, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255},
			{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
		},
		{
			{255, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255},
			{254, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255},
			{254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
		},
		{
			{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
			{254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
			{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
		},
		{
			{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
			{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
			{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
		},
		{
			{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
			{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
			{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
		},
		{
			{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
			{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
			{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
		},
	},
	{
		{
			{248, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
			{250, 254, 252, 254, 255, 255, 255, 255, 255, 255, 255},
			{248, 254, 249, 253, 255, 255, 255, 255, 255, 255, 255},
		},
		{
			{255, 253, 253, 255, 255, 255, 255, 255, 255, 255, 255},
			{246, 253, 253, 255, 255, 255, 255, 255, 255, 255, 255},
			{252, 254, 251, 254, 254, 255, 255, 255, 255, 255, 255},
		},
		{
			{255, 254, 252, 255, 255, 255, 255, 255, 255, 255, 255},
			{248, 254, 253, 255, 255, 255, 255, 255, 255, 255, 255},
			{253, 255, 254, 254, 255, 255, 255, 255, 255, 255, 255},
		},
		{
			{255, 251, 254, 255, 255, 255, 255, 255, 255, 255, 255},
			{245, 251, 254, 255, 255, 255, 255, 255, 255, 255, 255},
			{253, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255},
		},
		{
			{255, 251, 253, 255, 255, 255, 255, 255, 255, 255, 255},
			{252, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255},
			{255, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255},
		},
		{
			{255, 252, 255, 255, 255, 255, 255, 255, 255, 255, 255},
			{249, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255},
			{255, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255},
		},
		{
			{255, 255, 253, 255, 255, 255, 255, 255, 255, 255, 255},
			{250, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
			{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
		},
		{
			{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
			{254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
			{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
		},
	},
}

TokenProbUpdateProb is the probability of a token-probability update bit (RFC 6386 section 13.4). The encoder emits 4*8*3*11=1056 arithmetic-coded bits against this table, each indicating whether the corresponding DefaultTokenProb entry is overridden. We currently never override, so every emitted bit is 0; but they must still be emitted or the decoder misaligns.

View Source
var VP8Norm = [256]uint8{}/* 256 elements not displayed */

VP8Norm[i] returns the number of left-shifts needed to bring value i into the range [128, 255]. Used during boolean-coder range renormalization. Indexed 0..255; VP8Norm[0] is unused (range can never be zero).

View Source
var Zigzag4x4 = [16]int{0, 1, 4, 8, 5, 2, 3, 6, 9, 12, 13, 10, 7, 11, 14, 15}

Zigzag4x4 maps DCT zigzag order to raster 4x4 indices (RFC 6386 section 13). IMPORTANT: this is NOT the JPEG zigzag.

Functions

func DequantizeBlock

func DequantizeBlock(q []int16, coef []int16, dcFactor, acFactor uint16)

DequantizeBlock reconstructs coefficients from a quantized block in the zigzag-ordered input `q`. Writes to `coef` in raster 4x4 order. (This is the operation the decoder performs implicitly via the coefficient stream; exposed here for encoder-side reconstruction / RDO.)

func EncodeFrame

func EncodeFrame(w io.Writer, img image.Image, opts EncodeOptions) error

EncodeFrame writes a single VP8 keyframe (no RIFF/VP8 chunk wrapper) to w. Callers are responsible for wrapping the output in a VP8 chunk header and a RIFF container when building a full .webp file.

The current encoder implements I16 + UV8 prediction (DC/V/H/TM) with forward DCT + Walsh-Hadamard, deadzone quantization, and token-tree coefficient coding. Mode selection is SSE-based. I4 modes (10 per MB) and rate-distortion optimization are later-phase work.

func EncodeWebP

func EncodeWebP(w io.Writer, img image.Image, opts EncodeOptions) error

EncodeWebP wraps EncodeFrame in the RIFF/WEBP/VP8 container format.

func ExtractAlpha

func ExtractAlpha(img image.Image) []byte

ExtractAlpha returns the 8-bit alpha plane for img, sized exactly (w, h) — no MB padding. Returns nil if the image has no alpha channel or is fully opaque. Used by the ALPH chunk encoder.

func FDCT4x4

func FDCT4x4(src []int16, dst []int16)

FDCT4x4 performs a forward 4x4 DCT on 16 residual values in src and writes 16 coefficients to dst. Both slices are row-major 4x4 blocks.

This is the libvpx vp8_short_fdct4x4_c form, which pairs exactly with the libvpx IDCT implemented below (and with the decoder at golang.org/x/image/vp8/idct.go).

Known property: because the pass-1 rounding biases (14500, 7500) exceed their >>12 divisor, an all-zero residual produces tiny non-zero outputs in some odd-harmonic positions. These values are smaller than any realistic quantizer and quantize to 0 in practice; encoders rely on the "skip" flag to avoid emitting empty blocks.

Input residual range is [-510, 510] (signed 10-bit). Output fits in int16.

func FWHT4x4

func FWHT4x4(src []int16, dst []int16)

FWHT4x4 performs the forward Walsh-Hadamard transform on the 16 DC coefficients of an I16 macroblock's Y plane. Input is the 16 DC values (one per 4x4 Y sub-block, in raster order); output is the Y2 block.

func IDCT4x4

func IDCT4x4(src []int16, dst []int16)

IDCT4x4 performs the inverse 4x4 DCT on 16 coefficients in src, writing 16 reconstructed residuals to dst. Output residuals may overshoot the input range by small amounts and must be clipped to [0, 255] after adding prediction.

func IWHT4x4

func IWHT4x4(src []int16, dst []int16)

IWHT4x4 performs the inverse WHT on the 16 Y2 coefficients, producing 16 reconstructed Y-DC values in dst.

func PredictI4

func PredictI4(dst *[16]byte, mode int, tl byte, top *[8]byte, left *[4]byte)

PredictI4 fills dst with the 16 predicted pixels of one 4x4 sub-block for the given mode. Neighbors:

  • tl: top-left corner pixel (at y-1, x-1)
  • top[0..3]: 4 pixels directly above (at y-1, x..x+3)
  • top[4..7]: 4 pixels to the top-right (at y-1, x+4..x+7); for right-column sub-blocks these are the MB-level overhang values (RFC 6386 section 12.2 / x/image/vp8 prepareYBR's column-24..27 fill)
  • left[0..3]: 4 pixels along the left column (at y..y+3, x-1)

func PredictI16

func PredictI16(dst *[256]byte, mode int, topRow, leftCol *[16]byte, topLeft byte, hasTop, hasLeft bool)

PredictI16 fills dst[0..16][0..16] (row-major, stride 16) with the predicted pixels of a 16x16 block, given the reconstructed neighbors:

  • topLeft: single pixel at (x-1, y-1)
  • topRow: 16 pixels along the top edge at (x..x+15, y-1)
  • leftCol: 16 pixels along the left edge at (x-1, y..y+15)
  • hasTop, hasLeft indicate whether those neighbors are valid MBs (i.e. mby > 0 for top, mbx > 0 for left). When false, the corresponding side uses the default filler (0x7f for top, 0x81 for left) and DC mode switches to the appropriate variant.

func PredictUV8

func PredictUV8(dst *[64]byte, mode int, topRow, leftCol *[8]byte, topLeft byte, hasTop, hasLeft bool)

PredictUV8 fills an 8x8 block with predicted chroma values. Semantics match PredictI16 but sized to 8.

func QuantizeBlock

func QuantizeBlock(
	coef []int16, qOut []int16, dqOut []int16,
	dcFactor, acFactor uint16, deadzone int32,
) int

QuantizeBlock performs deadzone quantization of 16 coefficients given (dcFactor, acFactor) dequant values and a uniform deadzone bias. It writes the quantized integer coefficients to qOut and the reconstructed (dequantized) coefficients to dqOut. Returns the end-of-block index (1 + position of last non-zero coefficient in zigzag order) or 0 for an all-zero block.

For per-position deadzone tuning (smaller bias on DC, larger on AC), use QuantizeBlockSplit instead.

func QuantizeBlockSplit

func QuantizeBlockSplit(
	coef []int16, qOut []int16, dqOut []int16,
	dcFactor, acFactor uint16, dcDeadzone, acDeadzone int32,
) int

QuantizeBlockSplit performs deadzone quantization with separate deadzones for DC (zigzag position 0) and AC (all other positions). Typical use: dcDeadzone=0 (preserve DC accuracy, critical for perceived color and brightness) and acDeadzone=acFactor/4 (zero out small AC noise, saves entropy bits at little perceptual cost).

func SumSquaredError

func SumSquaredError(a, b []byte) int64

SumSquaredError returns the sum of squared differences between two equal-length byte slices, reinterpreted as pixel values. Used for mode selection (min-SSE search).

func TrellisTrim

func TrellisTrim(q *[16]int16, dq *[16]int16, acFactor uint16) int

TrellisTrim performs a simple trailing-noise trellis pass on a quantized 4x4 block: examines non-zero coefficients at mid-to-high zigzag positions with magnitude 1 and zeroes them in place. Moving the EOB earlier saves ~3-5 arithmetic-coded bits per coefficient at the cost of a small reconstruction error.

This isn't the full Viterbi trellis (which would track token-context transitions across all 16 positions simultaneously), but captures the common pathology where the last few non-zero coefficients are ±1s that barely survived rounding.

Returns the new EOB (count of coefficients up to and including the last non-zero in zigzag order).

func WriteCoefBlock

func WriteCoefBlock(
	enc *BoolEncoder,
	coefs *[16]int16,
	plane, context int,
	tokenProb *[NumPlanes][NumBands][NumContexts][NumProbs]uint8,
	skipFirstCoeff bool,
) int

WriteCoefBlock encodes 16 quantized coefficients (raster order) for one 4x4 block. Returns 1 if the block had any non-zero coefficient, 0 otherwise — matches the decoder's return value, which the caller propagates as the "non-zero" context for subsequent blocks.

coefs is indexed by raster (0..15); the zigzag mapping is applied internally. plane selects the probability plane; context is 0/1/2 from neighbor non-zero counts; tokenProb is the current probability table (we always use DefaultTokenProb, but passed in for future prob-update support). skipFirstCoeff == true for I16 Y1 blocks (DC is in the Y2 block, not this one), starting from zigzag position 1.

func WriteFilterHeader

func WriteFilterHeader(e *BoolEncoder, simple bool, level, sharpness int)

WriteFilterHeader emits the loop-filter header:

simple (1 bit) | level (6 bits) | sharpness (3 bits) | useLFDelta (1 bit)

level=0 disables the filter entirely (RFC 6386 section 15). Otherwise the decoder applies the normal filter (simple=false) or simple filter (simple=true) to the reconstructed frame as a post-processing pass that smooths block boundaries.

func WriteFilterHeaderOff

func WriteFilterHeaderOff(e *BoolEncoder)

WriteFilterHeaderOff is a backward-compatible shortcut for WriteFilterHeader(e, false, 0, 0).

func WriteHeaderInit

func WriteHeaderInit(e *BoolEncoder)

WriteHeaderInit writes the keyframe-only fields at the top of partition 0:

  • color_space (1 bit, must be 0)
  • clamp_type (1 bit, typically 0 meaning "bicubic clamping")

func WriteLog2NumParts

func WriteLog2NumParts(e *BoolEncoder, log2 int)

WriteLog2NumParts writes the log2 of the number of coefficient partitions (0..3 → 1, 2, 4, 8 partitions).

func WriteMBModes

func WriteMBModes(e *BoolEncoder, predY16, predC8 int)

WriteMBModes writes the per-macroblock mode fields for an I16 MB:

usePredY16 (1 bit at prob 145), predY16, predC8.

Must be called once per MB, after any skip bit, in MB raster order.

func WriteMBModesBPred

func WriteMBModesBPred(e *BoolEncoder, modes *[4][4]int, aboveModes *[4]int, leftModes *[4]int, predC8 int)

WriteMBModesBPred writes the per-macroblock mode fields for a B_PRED MB: usePredY16=0, 16 I4 modes (tree-coded against PredProb[above][left]), then the UV mode.

modes[j][i] is the I4 mode for sub-block at (i, j) in the MB. aboveModes[i] is the mode of the sub-block above sub-block column i

(bottom-row modes of the MB above, or ModeI4DC if on the frame edge).

leftModes is updated in place: on entry, leftModes[j] is the mode of

the sub-block to the left of sub-block row j; on return, leftModes[j]
holds the mode of this MB's rightmost sub-block in row j (i.e. the
input context for the NEXT MB to the right).

aboveModes is also updated in place to reflect the bottom-row modes of this MB.

func WriteQuantHeader

func WriteQuantHeader(e *BoolEncoder, baseQ int)

WriteQuantHeader emits the quantizer indexer: base Y AC index in 7 bits followed by five optional deltas (Y1 DC, Y2 DC, Y2 AC, UV DC, UV AC). Set all deltas to 0 for simple mode.

func WriteRefreshEntropyProbs

func WriteRefreshEntropyProbs(e *BoolEncoder)

WriteRefreshEntropyProbs emits the single "refresh entropy probs" flag. Keyframe-only. 0 means the next frame does not inherit updated probs (we're still a static image encoder so this is always 0).

func WriteSegmentHeaderOff

func WriteSegmentHeaderOff(e *BoolEncoder)

WriteSegmentHeaderOff emits a "no segmentation" segment header: a single zero bit indicating use_segment is false.

func WriteSkipProb

func WriteSkipProb(e *BoolEncoder, skipProbOn bool, prob uint8)

WriteSkipProb emits mb_no_skip_coeff plus, if true, an 8-bit skip probability. If skipProbOn is true, per-MB skip bits follow; if false, every MB carries full residuals.

func WriteTokenProbUpdates

func WriteTokenProbUpdates(e *BoolEncoder)

WriteTokenProbUpdates emits the 4×8×3×11 = 1056 "should we update this prob?" bits, each coded against TokenProbUpdateProb. We never update, so every emitted bit is 0. The decoder MUST consume exactly this many bits in this exact order.

Types

type BoolEncoder

type BoolEncoder struct {
	// contains filtered or unexported fields
}

BoolEncoder is the VP8 boolean arithmetic coder in write (encode) mode.

The algorithm is specified in RFC 6386 section 7 and follows the libvpx reference implementation. The output byte sequence is designed to be decoded by the matching decoder described in section 7.3; we verify this with a round-trip test against a mirror decoder that is bit-compatible with golang.org/x/image/vp8's `partition` type.

Invariants held between calls to WriteBit:

  • rng (range) is in [128, 255]
  • low holds up to 24 bits of "pending" output
  • count tracks bits committed into low but not yet emitted; initial value -24 means we need 24 shift-ins before the first emit.

Carry propagation: when an emitted byte would overflow due to a late addition in low, we propagate a +1 back through any preceding 0xff bytes, turning them into 0x00 and incrementing the first non-0xff byte before the run.

func NewBoolEncoder

func NewBoolEncoder() *BoolEncoder

NewBoolEncoder returns a freshly initialized encoder writing to an internal buffer. Retrieve the output via Bytes after calling Finish.

func (*BoolEncoder) Bytes

func (e *BoolEncoder) Bytes() []byte

Bytes returns the currently encoded bytes without flushing. Only meaningful for diagnostics; call Finish for a decodable stream.

func (*BoolEncoder) Finish

func (e *BoolEncoder) Finish() []byte

Finish flushes any pending bits and returns the encoded byte stream. It emits enough trailing zero bits at prob 128 to drain the internal state, so every previously written bit is recoverable by the decoder.

The returned slice is the encoder's internal buffer; callers that want to retain it across subsequent encodes must copy it.

func (*BoolEncoder) Len

func (e *BoolEncoder) Len() int

Len returns the number of bytes emitted so far.

func (*BoolEncoder) Reset

func (e *BoolEncoder) Reset()

Reset re-initializes the encoder to a fresh state, reusing the backing byte slice's capacity.

func (*BoolEncoder) WriteBit

func (e *BoolEncoder) WriteBit(bit int, prob int)

WriteBit encodes a single bit against the given probability.

prob is an 8-bit probability in [0, 255] where higher values bias toward the "0" branch being taken. 128 is the 50/50 (uniform) probability.

func (*BoolEncoder) WriteFlag

func (e *BoolEncoder) WriteFlag(v bool)

WriteFlag encodes a 1-bit flag against uniform probability (128).

func (*BoolEncoder) WriteInt

func (e *BoolEncoder) WriteInt(v int32, n int, prob int)

WriteInt encodes a signed value as magnitude + sign. Signed values are stored as |v| in n bits followed by a sign bit. Each bit is coded against prob (typically UniformProb).

func (*BoolEncoder) WriteOptionalInt

func (e *BoolEncoder) WriteOptionalInt(v int32, n int, prob int)

WriteOptionalInt encodes a possibly-zero signed value. When v == 0 a single "not present" bit is emitted; otherwise a "present" bit followed by the magnitude+sign encoding.

func (*BoolEncoder) WriteUint

func (e *BoolEncoder) WriteUint(v uint32, n int, prob int)

WriteUint encodes n bits of value v high-bit first, each against prob.

type CategoryInfo

type CategoryInfo struct {
	Base int   // base value for this category
	Bits []int // probabilities for each extra bit (high bit first)
}

Category extra-bits specifications (RFC 6386 section 13.2).

type EncodeOptions

type EncodeOptions struct {
	// Quality maps 0..100 to the VP8 base quantizer index; higher Quality
	// → lower QI → finer quantization. Default 75.
	Quality float32
	// Method is the speed/quality tradeoff; 0 = fastest, 6 = slowest.
	// Currently only toggles whether mode search explores all 4 I16/UV8
	// modes (>=1) or hard-selects DC (0).
	Method int
}

EncodeOptions carries VP8 frame-level tuning that the package-level encoder wrapper translates from gowebp.Options.

type Frame

type Frame struct {
	Width, Height int
	MBWidth       int // ceil(Width/16)
	MBHeight      int // ceil(Height/16)

	Y  []byte // YStride * MBHeight*16
	Cb []byte // UVStride * MBHeight*8
	Cr []byte // UVStride * MBHeight*8

	YStride  int // == MBWidth*16
	UVStride int // == MBWidth*8
}

Frame is a macroblock-aligned YCbCr 4:2:0 image in planar layout.

The display size is (Width, Height) in pixels. The allocated planes are padded up to the next multiple of 16 (luma) or 8 (chroma) so macroblock loops can read uniformly. Edge rows/columns are filled by replicating the last valid pixel, matching libwebp's padding policy.

func NewFrame

func NewFrame(w, h int) *Frame

NewFrame allocates a Frame with zeroed planes sized for (w, h) display dimensions. The planes are MB-aligned.

func RGBAToFrame

func RGBAToFrame(img image.Image) *Frame

RGBAToFrame converts an image.Image to a macroblock-aligned 4:2:0 YCbCr Frame using BT.601 fixed-point coefficients (matching RFC 6386 and libwebp's picture_csp_enc.c). Padding pixels beyond (Width, Height) replicate the nearest edge pixel.

Alpha is ignored here; ALPH chunk handling is the caller's responsibility.

type Quantizer

type Quantizer struct {
	Y1 [2]uint16 // Y AC blocks
	Y2 [2]uint16 // Y DC (Walsh) block
	UV [2]uint16 // Chroma AC blocks
}

Quantizer bundles the six VP8 dequant factors needed to (de)quantize Y, Y2, and UV blocks. Indices: [0] = DC factor, [1] = AC factor.

func NewQuantizer

func NewQuantizer(qi int) Quantizer

NewQuantizer derives dequant factors from a base quantizer index in [0, 127] using the exact lookup + adjustments specified in RFC 6386 section 9.6 (mirrored from x/image/vp8 quant.go).

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL