// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package vp8

// This file implements decoding DCT/WHT residual coefficients and
// reconstructing YCbCr data equal to predicted values plus residuals.
//
// There are 1*16*16 + 2*8*8 + 1*4*4 coefficients per macroblock:
//	- 1*16*16 luma DCT coefficients,
//	- 2*8*8 chroma DCT coefficients, and
//	- 1*4*4 luma WHT coefficients.
// Coefficients are read in lots of 16, and the later coefficients in each lot
// are often zero.
//
// The YCbCr data consists of 1*16*16 luma values and 2*8*8 chroma values,
// plus previously decoded values along the top and left borders. The combined
// values are laid out as a [1+16+1+8][32]uint8 so that vertically adjacent
// samples are 32 bytes apart. In detail, the layout is:
//
//	0 1 2 3 4 5 6 7  8 9 0 1 2 3 4 5  6 7 8 9 0 1 2 3  4 5 6 7 8 9 0 1
//	. . . . . . . a  b b b b b b b b  b b b b b b b b  c c c c . . . .	0
//	. . . . . . . d  Y Y Y Y Y Y Y Y  Y Y Y Y Y Y Y Y  . . . . . . . .	1
//	. . . . . . . d  Y Y Y Y Y Y Y Y  Y Y Y Y Y Y Y Y  . . . . . . . .	2
//	. . . . . . . d  Y Y Y Y Y Y Y Y  Y Y Y Y Y Y Y Y  . . . . . . . .	3
//	. . . . . . . d  Y Y Y Y Y Y Y Y  Y Y Y Y Y Y Y Y  c c c c . . . .	4
//	. . . . . . . d  Y Y Y Y Y Y Y Y  Y Y Y Y Y Y Y Y  . . . . . . . .	5
//	. . . . . . . d  Y Y Y Y Y Y Y Y  Y Y Y Y Y Y Y Y  . . . . . . . .	6
//	. . . . . . . d  Y Y Y Y Y Y Y Y  Y Y Y Y Y Y Y Y  . . . . . . . .	7
//	. . . . . . . d  Y Y Y Y Y Y Y Y  Y Y Y Y Y Y Y Y  c c c c . . . .	8
//	. . . . . . . d  Y Y Y Y Y Y Y Y  Y Y Y Y Y Y Y Y  . . . . . . . .	9
//	. . . . . . . d  Y Y Y Y Y Y Y Y  Y Y Y Y Y Y Y Y  . . . . . . . .	10
//	. . . . . . . d  Y Y Y Y Y Y Y Y  Y Y Y Y Y Y Y Y  . . . . . . . .	11
//	. . . . . . . d  Y Y Y Y Y Y Y Y  Y Y Y Y Y Y Y Y  c c c c . . . .	12
//	. . . . . . . d  Y Y Y Y Y Y Y Y  Y Y Y Y Y Y Y Y  . . . . . . . .	13
//	. . . . . . . d  Y Y Y Y Y Y Y Y  Y Y Y Y Y Y Y Y  . . . . . . . .	14
//	. . . . . . . d  Y Y Y Y Y Y Y Y  Y Y Y Y Y Y Y Y  . . . . . . . .	15
//	. . . . . . . d  Y Y Y Y Y Y Y Y  Y Y Y Y Y Y Y Y  . . . . . . . .	16
//	. . . . . . . e  f f f f f f f f  . . . . . . . g  h h h h h h h h	17
//	. . . . . . . i  B B B B B B B B  . . . . . . . j  R R R R R R R R	18
//	. . . . . . . i  B B B B B B B B  . . . . . . . j  R R R R R R R R	19
//	. . . . . . . i  B B B B B B B B  . . . . . . . j  R R R R R R R R	20
//	. . . . . . . i  B B B B B B B B  . . . . . . . j  R R R R R R R R	21
//	. . . . . . . i  B B B B B B B B  . . . . . . . j  R R R R R R R R	22
//	. . . . . . . i  B B B B B B B B  . . . . . . . j  R R R R R R R R	23
//	. . . . . . . i  B B B B B B B B  . . . . . . . j  R R R R R R R R	24
//	. . . . . . . i  B B B B B B B B  . . . . . . . j  R R R R R R R R	25
//
// Y, B and R are the reconstructed luma (Y) and chroma (B, R) values.
// The Y values are predicted (either as one 16x16 region or 16 4x4 regions)
// based on the row above's Y values (some combination of {abc} or {dYC}) and
// the column left's Y values (either {ad} or {bY}). Similarly, B and R values
// are predicted on the row above and column left of their respective 8x8
// region: {efi} for B, {ghj} for R.
//
// For uppermost macroblocks (i.e. those with mby == 0), the {abcefgh} values
// are initialized to 0x81. Otherwise, they are copied from the bottom row of
// the macroblock above. The {c} values are then duplicated from row 0 to rows
// 4, 8 and 12 of the ybr workspace.
// Similarly, for leftmost macroblocks (i.e. those with mbx == 0), the {adeigj}
// values are initialized to 0x7f. Otherwise, they are copied from the right
// column of the macroblock to the left.
// For the top-left macroblock (with mby == 0 && mbx == 0), {aeg} is 0x81.
//
// When moving from one macroblock to the next horizontally, the {adeigj}
// values can simply be copied from the workspace to itself, shifted by 8 or
// 16 columns. When moving from one macroblock to the next vertically,
// filtering can occur and hence the row values have to be copied from the
// post-filtered image instead of the pre-filtered workspace.

const (
	bCoeffBase   = 1*16*16 + 0*8*8
	rCoeffBase   = 1*16*16 + 1*8*8
	whtCoeffBase = 1*16*16 + 2*8*8
)

const (
	ybrYX = 8
	ybrYY = 1
	ybrBX = 8
	ybrBY = 18
	ybrRX = 24
	ybrRY = 18
)

// prepareYBR prepares the {abcdefghij} elements of ybr.
func ( *Decoder) (,  int) {
	if  == 0 {
		for  := 0;  < 17; ++ {
			.ybr[][7] = 0x81
		}
		for  := 17;  < 26; ++ {
			.ybr[][7] = 0x81
			.ybr[][23] = 0x81
		}
	} else {
		for  := 0;  < 17; ++ {
			.ybr[][7] = .ybr[][7+16]
		}
		for  := 17;  < 26; ++ {
			.ybr[][7] = .ybr[][15]
			.ybr[][23] = .ybr[][31]
		}
	}
	if  == 0 {
		for  := 7;  < 28; ++ {
			.ybr[0][] = 0x7f
		}
		for  := 7;  < 16; ++ {
			.ybr[17][] = 0x7f
		}
		for  := 23;  < 32; ++ {
			.ybr[17][] = 0x7f
		}
	} else {
		for  := 0;  < 16; ++ {
			.ybr[0][8+] = .img.Y[(16*-1)*.img.YStride+16*+]
		}
		for  := 0;  < 8; ++ {
			.ybr[17][8+] = .img.Cb[(8*-1)*.img.CStride+8*+]
		}
		for  := 0;  < 8; ++ {
			.ybr[17][24+] = .img.Cr[(8*-1)*.img.CStride+8*+]
		}
		if  == .mbw-1 {
			for  := 16;  < 20; ++ {
				.ybr[0][8+] = .img.Y[(16*-1)*.img.YStride+16*+15]
			}
		} else {
			for  := 16;  < 20; ++ {
				.ybr[0][8+] = .img.Y[(16*-1)*.img.YStride+16*+]
			}
		}
	}
	for  := 4;  < 16;  += 4 {
		.ybr[][24] = .ybr[0][24]
		.ybr[][25] = .ybr[0][25]
		.ybr[][26] = .ybr[0][26]
		.ybr[][27] = .ybr[0][27]
	}
}

// btou converts a bool to a 0/1 value.
func btou( bool) uint8 {
	if  {
		return 1
	}
	return 0
}

// pack packs four 0/1 values into four bits of a uint32.
func pack( [4]uint8,  int) uint32 {
	 := uint32([0])<<0 | uint32([1])<<1 | uint32([2])<<2 | uint32([3])<<3
	return  << uint()
}

// unpack unpacks four 0/1 values from a four-bit value.
var unpack = [16][4]uint8{
	{0, 0, 0, 0},
	{1, 0, 0, 0},
	{0, 1, 0, 0},
	{1, 1, 0, 0},
	{0, 0, 1, 0},
	{1, 0, 1, 0},
	{0, 1, 1, 0},
	{1, 1, 1, 0},
	{0, 0, 0, 1},
	{1, 0, 0, 1},
	{0, 1, 0, 1},
	{1, 1, 0, 1},
	{0, 0, 1, 1},
	{1, 0, 1, 1},
	{0, 1, 1, 1},
	{1, 1, 1, 1},
}

var (
	// The mapping from 4x4 region position to band is specified in section 13.3.
	bands = [17]uint8{0, 1, 2, 3, 6, 4, 5, 6, 6, 6, 6, 6, 6, 6, 6, 7, 0}
	// Category probabilities are specified in section 13.2.
	// Decoding categories 1 and 2 are done inline.
	cat3456 = [4][12]uint8{
		{173, 148, 140, 0, 0, 0, 0, 0, 0, 0, 0, 0},
		{176, 155, 140, 135, 0, 0, 0, 0, 0, 0, 0, 0},
		{180, 157, 141, 134, 130, 0, 0, 0, 0, 0, 0, 0},
		{254, 254, 243, 230, 196, 177, 153, 140, 133, 130, 129, 0},
	}
	// The zigzag order is:
	//	0  1  5  6
	//	2  4  7 12
	//	3  8 11 13
	//	9 10 14 15
	zigzag = [16]uint8{0, 1, 4, 8, 5, 2, 3, 6, 9, 12, 13, 10, 7, 11, 14, 15}
)

// parseResiduals4 parses a 4x4 region of residual coefficients, as specified
// in section 13.3, and returns a 0/1 value indicating whether there was at
// least one non-zero coefficient.
// r is the partition to read bits from.
// plane and context describe which token probability table to use. context is
// either 0, 1 or 2, and equals how many of the macroblock left and macroblock
// above have non-zero coefficients.
// quant are the DC/AC quantization factors.
// skipFirstCoeff is whether the DC coefficient has already been parsed.
// coeffBase is the base index of d.coeff to write to.
func ( *Decoder) ( *partition,  int,  uint8,  [2]uint16,  bool,  int) uint8 {
	,  := &.tokenProb[], 0
	if  {
		 = 1
	}
	 := [bands[]][]
	if !.readBit([0]) {
		return 0
	}
	for  != 16 {
		++
		if !.readBit([1]) {
			 = [bands[]][0]
			continue
		}
		var  uint32
		if !.readBit([2]) {
			 = 1
			 = [bands[]][1]
		} else {
			if !.readBit([3]) {
				if !.readBit([4]) {
					 = 2
				} else {
					 = 3 + .readUint([5], 1)
				}
			} else if !.readBit([6]) {
				if !.readBit([7]) {
					// Category 1.
					 = 5 + .readUint(159, 1)
				} else {
					// Category 2.
					 = 7 + 2*.readUint(165, 1) + .readUint(145, 1)
				}
			} else {
				// Categories 3, 4, 5 or 6.
				 := .readUint([8], 1)
				 := .readUint([9+], 1)
				 := 2* + 
				 := &cat3456[]
				 = 0
				for  := 0; [] != 0; ++ {
					 *= 2
					 += .readUint([], 1)
				}
				 += 3 + (8 << )
			}
			 = [bands[]][2]
		}
		 := zigzag[-1]
		 := int32() * int32([btou( > 0)])
		if .readBit(uniformProb) {
			 = -
		}
		.coeff[+int()] = int16()
		if  == 16 || !.readBit([0]) {
			return 1
		}
	}
	return 1
}

// parseResiduals parses the residuals and returns whether inner loop filtering
// should be skipped for this macroblock.
func ( *Decoder) (,  int) ( bool) {
	 := &.op[&(.nOP-1)]
	 := planeY1SansY2
	 := &.quant[.segment]

	// Parse the DC coefficient of each 4x4 luma region.
	if .usePredY16 {
		 := .parseResiduals4(, planeY2, .leftMB.nzY16+.upMB[].nzY16, .y2, false, whtCoeffBase)
		.leftMB.nzY16 = 
		.upMB[].nzY16 = 
		.inverseWHT16()
		 = planeY1WithY2
	}

	var (
		,          [4]uint8
		,  uint32
		          int
	)

	// Parse the luma coefficients.
	 := unpack[.leftMB.nzMask&0x0f]
	 := unpack[.upMB[].nzMask&0x0f]
	for  := 0;  < 4; ++ {
		 := []
		for  := 0;  < 4; ++ {
			 = .parseResiduals4(, , +[], .y1, .usePredY16, )
			[] = 
			[] = 
			[] = btou(.coeff[] != 0)
			 += 16
		}
		[] = 
		 |= pack(, *4)
		 |= pack(, *4)
	}
	 := pack(, 0)
	 := pack(, 0)

	// Parse the chroma coefficients.
	 = unpack[.leftMB.nzMask>>4]
	 = unpack[.upMB[].nzMask>>4]
	for  := 0;  < 4;  += 2 {
		for  := 0;  < 2; ++ {
			 := [+]
			for  := 0;  < 2; ++ {
				 = .parseResiduals4(, planeUV, +[+], .uv, false, )
				[+] = 
				[*2+] = 
				[*2+] = btou(.coeff[] != 0)
				 += 16
			}
			[+] = 
		}
		 |= pack(, 16+*2)
		 |= pack(, 16+*2)
	}
	 |= pack(, 4)
	 |= pack(, 4)

	// Save decoder state.
	.leftMB.nzMask = uint8()
	.upMB[].nzMask = uint8()
	.nzDCMask = 
	.nzACMask = 

	// Section 15.1 of the spec says that "Steps 2 and 4 [of the loop filter]
	// are skipped... [if] there is no DCT coefficient coded for the whole
	// macroblock."
	return  == 0 &&  == 0
}

// reconstructMacroblock applies the predictor functions and adds the inverse-
// DCT transformed residuals to recover the YCbCr data.
func ( *Decoder) (,  int) {
	if .usePredY16 {
		 := checkTopLeftPred(, , .predY16)
		predFunc16[](, 1, 8)
		for  := 0;  < 4; ++ {
			for  := 0;  < 4; ++ {
				 := 4* + 
				 := 4* + 1
				 := 4* + 8
				 := uint32(1) << uint()
				if .nzACMask& != 0 {
					.inverseDCT4(, , 16*)
				} else if .nzDCMask& != 0 {
					.inverseDCT4DCOnly(, , 16*)
				}
			}
		}
	} else {
		for  := 0;  < 4; ++ {
			for  := 0;  < 4; ++ {
				 := 4* + 
				 := 4* + 1
				 := 4* + 8
				predFunc4[.predY4[][]](, , )
				 := uint32(1) << uint()
				if .nzACMask& != 0 {
					.inverseDCT4(, , 16*)
				} else if .nzDCMask& != 0 {
					.inverseDCT4DCOnly(, , 16*)
				}
			}
		}
	}
	 := checkTopLeftPred(, , .predC8)
	predFunc8[](, ybrBY, ybrBX)
	if .nzACMask&0x0f0000 != 0 {
		.inverseDCT8(ybrBY, ybrBX, bCoeffBase)
	} else if .nzDCMask&0x0f0000 != 0 {
		.inverseDCT8DCOnly(ybrBY, ybrBX, bCoeffBase)
	}
	predFunc8[](, ybrRY, ybrRX)
	if .nzACMask&0xf00000 != 0 {
		.inverseDCT8(ybrRY, ybrRX, rCoeffBase)
	} else if .nzDCMask&0xf00000 != 0 {
		.inverseDCT8DCOnly(ybrRY, ybrRX, rCoeffBase)
	}
}

// reconstruct reconstructs one macroblock and returns whether inner loop
// filtering should be skipped for it.
func ( *Decoder) (,  int) ( bool) {
	if .segmentHeader.updateMap {
		if !.fp.readBit(.segmentHeader.prob[0]) {
			.segment = int(.fp.readUint(.segmentHeader.prob[1], 1))
		} else {
			.segment = int(.fp.readUint(.segmentHeader.prob[2], 1)) + 2
		}
	}
	if .useSkipProb {
		 = .fp.readBit(.skipProb)
	}
	// Prepare the workspace.
	for  := range .coeff {
		.coeff[] = 0
	}
	.prepareYBR(, )
	// Parse the predictor modes.
	.usePredY16 = .fp.readBit(145)
	if .usePredY16 {
		.parsePredModeY16()
	} else {
		.parsePredModeY4()
	}
	.parsePredModeC8()
	// Parse the residuals.
	if ! {
		 = .parseResiduals(, )
	} else {
		if .usePredY16 {
			.leftMB.nzY16 = 0
			.upMB[].nzY16 = 0
		}
		.leftMB.nzMask = 0
		.upMB[].nzMask = 0
		.nzDCMask = 0
		.nzACMask = 0
	}
	// Reconstruct the YCbCr data and copy it to the image.
	.reconstructMacroblock(, )
	for ,  := (*.img.YStride+)*16, 0;  < 16; ,  = +.img.YStride, +1 {
		copy(.img.Y[:+16], .ybr[ybrYY+][ybrYX:ybrYX+16])
	}
	for ,  := (*.img.CStride+)*8, 0;  < 8; ,  = +.img.CStride, +1 {
		copy(.img.Cb[:+8], .ybr[ybrBY+][ybrBX:ybrBX+8])
		copy(.img.Cr[:+8], .ybr[ybrRY+][ybrRX:ybrRX+8])
	}
	return 
}