mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-10-30 22:52:25 -05:00 
			
		
		
		
	
		
			
	
	
		
			404 lines
		
	
	
	
		
			12 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
		
		
			
		
	
	
			404 lines
		
	
	
	
		
			12 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
|  | // 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 implements a decoder for the VP8 lossy image format. | ||
|  | // | ||
|  | // The VP8 specification is RFC 6386. | ||
|  | package vp8 // import "golang.org/x/image/vp8" | ||
|  | 
 | ||
|  | // This file implements the top-level decoding algorithm. | ||
|  | 
 | ||
|  | import ( | ||
|  | 	"errors" | ||
|  | 	"image" | ||
|  | 	"io" | ||
|  | ) | ||
|  | 
 | ||
|  | // limitReader wraps an io.Reader to read at most n bytes from it. | ||
|  | type limitReader struct { | ||
|  | 	r io.Reader | ||
|  | 	n int | ||
|  | } | ||
|  | 
 | ||
|  | // ReadFull reads exactly len(p) bytes into p. | ||
|  | func (r *limitReader) ReadFull(p []byte) error { | ||
|  | 	if len(p) > r.n { | ||
|  | 		return io.ErrUnexpectedEOF | ||
|  | 	} | ||
|  | 	n, err := io.ReadFull(r.r, p) | ||
|  | 	r.n -= n | ||
|  | 	return err | ||
|  | } | ||
|  | 
 | ||
|  | // FrameHeader is a frame header, as specified in section 9.1. | ||
|  | type FrameHeader struct { | ||
|  | 	KeyFrame          bool | ||
|  | 	VersionNumber     uint8 | ||
|  | 	ShowFrame         bool | ||
|  | 	FirstPartitionLen uint32 | ||
|  | 	Width             int | ||
|  | 	Height            int | ||
|  | 	XScale            uint8 | ||
|  | 	YScale            uint8 | ||
|  | } | ||
|  | 
 | ||
|  | const ( | ||
|  | 	nSegment     = 4 | ||
|  | 	nSegmentProb = 3 | ||
|  | ) | ||
|  | 
 | ||
|  | // segmentHeader holds segment-related header information. | ||
|  | type segmentHeader struct { | ||
|  | 	useSegment     bool | ||
|  | 	updateMap      bool | ||
|  | 	relativeDelta  bool | ||
|  | 	quantizer      [nSegment]int8 | ||
|  | 	filterStrength [nSegment]int8 | ||
|  | 	prob           [nSegmentProb]uint8 | ||
|  | } | ||
|  | 
 | ||
|  | const ( | ||
|  | 	nRefLFDelta  = 4 | ||
|  | 	nModeLFDelta = 4 | ||
|  | ) | ||
|  | 
 | ||
|  | // filterHeader holds filter-related header information. | ||
|  | type filterHeader struct { | ||
|  | 	simple          bool | ||
|  | 	level           int8 | ||
|  | 	sharpness       uint8 | ||
|  | 	useLFDelta      bool | ||
|  | 	refLFDelta      [nRefLFDelta]int8 | ||
|  | 	modeLFDelta     [nModeLFDelta]int8 | ||
|  | 	perSegmentLevel [nSegment]int8 | ||
|  | } | ||
|  | 
 | ||
|  | // mb is the per-macroblock decode state. A decoder maintains mbw+1 of these | ||
|  | // as it is decoding macroblocks left-to-right and top-to-bottom: mbw for the | ||
|  | // macroblocks in the row above, and one for the macroblock to the left. | ||
|  | type mb struct { | ||
|  | 	// pred is the predictor mode for the 4 bottom or right 4x4 luma regions. | ||
|  | 	pred [4]uint8 | ||
|  | 	// nzMask is a mask of 8 bits: 4 for the bottom or right 4x4 luma regions, | ||
|  | 	// and 2 + 2 for the bottom or right 4x4 chroma regions. A 1 bit indicates | ||
|  | 	// that region has non-zero coefficients. | ||
|  | 	nzMask uint8 | ||
|  | 	// nzY16 is a 0/1 value that is 1 if the macroblock used Y16 prediction and | ||
|  | 	// had non-zero coefficients. | ||
|  | 	nzY16 uint8 | ||
|  | } | ||
|  | 
 | ||
|  | // Decoder decodes VP8 bitstreams into frames. Decoding one frame consists of | ||
|  | // calling Init, DecodeFrameHeader and then DecodeFrame in that order. | ||
|  | // A Decoder can be re-used to decode multiple frames. | ||
|  | type Decoder struct { | ||
|  | 	// r is the input bitsream. | ||
|  | 	r limitReader | ||
|  | 	// scratch is a scratch buffer. | ||
|  | 	scratch [8]byte | ||
|  | 	// img is the YCbCr image to decode into. | ||
|  | 	img *image.YCbCr | ||
|  | 	// mbw and mbh are the number of 16x16 macroblocks wide and high the image is. | ||
|  | 	mbw, mbh int | ||
|  | 	// frameHeader is the frame header. When decoding multiple frames, | ||
|  | 	// frames that aren't key frames will inherit the Width, Height, | ||
|  | 	// XScale and YScale of the most recent key frame. | ||
|  | 	frameHeader FrameHeader | ||
|  | 	// Other headers. | ||
|  | 	segmentHeader segmentHeader | ||
|  | 	filterHeader  filterHeader | ||
|  | 	// The image data is divided into a number of independent partitions. | ||
|  | 	// There is 1 "first partition" and between 1 and 8 "other partitions" | ||
|  | 	// for coefficient data. | ||
|  | 	fp  partition | ||
|  | 	op  [8]partition | ||
|  | 	nOP int | ||
|  | 	// Quantization factors. | ||
|  | 	quant [nSegment]quant | ||
|  | 	// DCT/WHT coefficient decoding probabilities. | ||
|  | 	tokenProb   [nPlane][nBand][nContext][nProb]uint8 | ||
|  | 	useSkipProb bool | ||
|  | 	skipProb    uint8 | ||
|  | 	// Loop filter parameters. | ||
|  | 	filterParams      [nSegment][2]filterParam | ||
|  | 	perMBFilterParams []filterParam | ||
|  | 
 | ||
|  | 	// The eight fields below relate to the current macroblock being decoded. | ||
|  | 	// | ||
|  | 	// Segment-based adjustments. | ||
|  | 	segment int | ||
|  | 	// Per-macroblock state for the macroblock immediately left of and those | ||
|  | 	// macroblocks immediately above the current macroblock. | ||
|  | 	leftMB mb | ||
|  | 	upMB   []mb | ||
|  | 	// Bitmasks for which 4x4 regions of coeff contain non-zero coefficients. | ||
|  | 	nzDCMask, nzACMask uint32 | ||
|  | 	// Predictor modes. | ||
|  | 	usePredY16 bool // The libwebp C code calls this !is_i4x4_. | ||
|  | 	predY16    uint8 | ||
|  | 	predC8     uint8 | ||
|  | 	predY4     [4][4]uint8 | ||
|  | 
 | ||
|  | 	// The two fields below form a workspace for reconstructing a macroblock. | ||
|  | 	// Their specific sizes are documented in reconstruct.go. | ||
|  | 	coeff [1*16*16 + 2*8*8 + 1*4*4]int16 | ||
|  | 	ybr   [1 + 16 + 1 + 8][32]uint8 | ||
|  | } | ||
|  | 
 | ||
|  | // NewDecoder returns a new Decoder. | ||
|  | func NewDecoder() *Decoder { | ||
|  | 	return &Decoder{} | ||
|  | } | ||
|  | 
 | ||
|  | // Init initializes the decoder to read at most n bytes from r. | ||
|  | func (d *Decoder) Init(r io.Reader, n int) { | ||
|  | 	d.r = limitReader{r, n} | ||
|  | } | ||
|  | 
 | ||
|  | // DecodeFrameHeader decodes the frame header. | ||
|  | func (d *Decoder) DecodeFrameHeader() (fh FrameHeader, err error) { | ||
|  | 	// All frame headers are at least 3 bytes long. | ||
|  | 	b := d.scratch[:3] | ||
|  | 	if err = d.r.ReadFull(b); err != nil { | ||
|  | 		return | ||
|  | 	} | ||
|  | 	d.frameHeader.KeyFrame = (b[0] & 1) == 0 | ||
|  | 	d.frameHeader.VersionNumber = (b[0] >> 1) & 7 | ||
|  | 	d.frameHeader.ShowFrame = (b[0]>>4)&1 == 1 | ||
|  | 	d.frameHeader.FirstPartitionLen = uint32(b[0])>>5 | uint32(b[1])<<3 | uint32(b[2])<<11 | ||
|  | 	if !d.frameHeader.KeyFrame { | ||
|  | 		return d.frameHeader, nil | ||
|  | 	} | ||
|  | 	// Frame headers for key frames are an additional 7 bytes long. | ||
|  | 	b = d.scratch[:7] | ||
|  | 	if err = d.r.ReadFull(b); err != nil { | ||
|  | 		return | ||
|  | 	} | ||
|  | 	// Check the magic sync code. | ||
|  | 	if b[0] != 0x9d || b[1] != 0x01 || b[2] != 0x2a { | ||
|  | 		err = errors.New("vp8: invalid format") | ||
|  | 		return | ||
|  | 	} | ||
|  | 	d.frameHeader.Width = int(b[4]&0x3f)<<8 | int(b[3]) | ||
|  | 	d.frameHeader.Height = int(b[6]&0x3f)<<8 | int(b[5]) | ||
|  | 	d.frameHeader.XScale = b[4] >> 6 | ||
|  | 	d.frameHeader.YScale = b[6] >> 6 | ||
|  | 	d.mbw = (d.frameHeader.Width + 0x0f) >> 4 | ||
|  | 	d.mbh = (d.frameHeader.Height + 0x0f) >> 4 | ||
|  | 	d.segmentHeader = segmentHeader{ | ||
|  | 		prob: [3]uint8{0xff, 0xff, 0xff}, | ||
|  | 	} | ||
|  | 	d.tokenProb = defaultTokenProb | ||
|  | 	d.segment = 0 | ||
|  | 	return d.frameHeader, nil | ||
|  | } | ||
|  | 
 | ||
|  | // ensureImg ensures that d.img is large enough to hold the decoded frame. | ||
|  | func (d *Decoder) ensureImg() { | ||
|  | 	if d.img != nil { | ||
|  | 		p0, p1 := d.img.Rect.Min, d.img.Rect.Max | ||
|  | 		if p0.X == 0 && p0.Y == 0 && p1.X >= 16*d.mbw && p1.Y >= 16*d.mbh { | ||
|  | 			return | ||
|  | 		} | ||
|  | 	} | ||
|  | 	m := image.NewYCbCr(image.Rect(0, 0, 16*d.mbw, 16*d.mbh), image.YCbCrSubsampleRatio420) | ||
|  | 	d.img = m.SubImage(image.Rect(0, 0, d.frameHeader.Width, d.frameHeader.Height)).(*image.YCbCr) | ||
|  | 	d.perMBFilterParams = make([]filterParam, d.mbw*d.mbh) | ||
|  | 	d.upMB = make([]mb, d.mbw) | ||
|  | } | ||
|  | 
 | ||
|  | // parseSegmentHeader parses the segment header, as specified in section 9.3. | ||
|  | func (d *Decoder) parseSegmentHeader() { | ||
|  | 	d.segmentHeader.useSegment = d.fp.readBit(uniformProb) | ||
|  | 	if !d.segmentHeader.useSegment { | ||
|  | 		d.segmentHeader.updateMap = false | ||
|  | 		return | ||
|  | 	} | ||
|  | 	d.segmentHeader.updateMap = d.fp.readBit(uniformProb) | ||
|  | 	if d.fp.readBit(uniformProb) { | ||
|  | 		d.segmentHeader.relativeDelta = !d.fp.readBit(uniformProb) | ||
|  | 		for i := range d.segmentHeader.quantizer { | ||
|  | 			d.segmentHeader.quantizer[i] = int8(d.fp.readOptionalInt(uniformProb, 7)) | ||
|  | 		} | ||
|  | 		for i := range d.segmentHeader.filterStrength { | ||
|  | 			d.segmentHeader.filterStrength[i] = int8(d.fp.readOptionalInt(uniformProb, 6)) | ||
|  | 		} | ||
|  | 	} | ||
|  | 	if !d.segmentHeader.updateMap { | ||
|  | 		return | ||
|  | 	} | ||
|  | 	for i := range d.segmentHeader.prob { | ||
|  | 		if d.fp.readBit(uniformProb) { | ||
|  | 			d.segmentHeader.prob[i] = uint8(d.fp.readUint(uniformProb, 8)) | ||
|  | 		} else { | ||
|  | 			d.segmentHeader.prob[i] = 0xff | ||
|  | 		} | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | // parseFilterHeader parses the filter header, as specified in section 9.4. | ||
|  | func (d *Decoder) parseFilterHeader() { | ||
|  | 	d.filterHeader.simple = d.fp.readBit(uniformProb) | ||
|  | 	d.filterHeader.level = int8(d.fp.readUint(uniformProb, 6)) | ||
|  | 	d.filterHeader.sharpness = uint8(d.fp.readUint(uniformProb, 3)) | ||
|  | 	d.filterHeader.useLFDelta = d.fp.readBit(uniformProb) | ||
|  | 	if d.filterHeader.useLFDelta && d.fp.readBit(uniformProb) { | ||
|  | 		for i := range d.filterHeader.refLFDelta { | ||
|  | 			d.filterHeader.refLFDelta[i] = int8(d.fp.readOptionalInt(uniformProb, 6)) | ||
|  | 		} | ||
|  | 		for i := range d.filterHeader.modeLFDelta { | ||
|  | 			d.filterHeader.modeLFDelta[i] = int8(d.fp.readOptionalInt(uniformProb, 6)) | ||
|  | 		} | ||
|  | 	} | ||
|  | 	if d.filterHeader.level == 0 { | ||
|  | 		return | ||
|  | 	} | ||
|  | 	if d.segmentHeader.useSegment { | ||
|  | 		for i := range d.filterHeader.perSegmentLevel { | ||
|  | 			strength := d.segmentHeader.filterStrength[i] | ||
|  | 			if d.segmentHeader.relativeDelta { | ||
|  | 				strength += d.filterHeader.level | ||
|  | 			} | ||
|  | 			d.filterHeader.perSegmentLevel[i] = strength | ||
|  | 		} | ||
|  | 	} else { | ||
|  | 		d.filterHeader.perSegmentLevel[0] = d.filterHeader.level | ||
|  | 	} | ||
|  | 	d.computeFilterParams() | ||
|  | } | ||
|  | 
 | ||
|  | // parseOtherPartitions parses the other partitions, as specified in section 9.5. | ||
|  | func (d *Decoder) parseOtherPartitions() error { | ||
|  | 	const maxNOP = 1 << 3 | ||
|  | 	var partLens [maxNOP]int | ||
|  | 	d.nOP = 1 << d.fp.readUint(uniformProb, 2) | ||
|  | 
 | ||
|  | 	// The final partition length is implied by the remaining chunk data | ||
|  | 	// (d.r.n) and the other d.nOP-1 partition lengths. Those d.nOP-1 partition | ||
|  | 	// lengths are stored as 24-bit uints, i.e. up to 16 MiB per partition. | ||
|  | 	n := 3 * (d.nOP - 1) | ||
|  | 	partLens[d.nOP-1] = d.r.n - n | ||
|  | 	if partLens[d.nOP-1] < 0 { | ||
|  | 		return io.ErrUnexpectedEOF | ||
|  | 	} | ||
|  | 	if n > 0 { | ||
|  | 		buf := make([]byte, n) | ||
|  | 		if err := d.r.ReadFull(buf); err != nil { | ||
|  | 			return err | ||
|  | 		} | ||
|  | 		for i := 0; i < d.nOP-1; i++ { | ||
|  | 			pl := int(buf[3*i+0]) | int(buf[3*i+1])<<8 | int(buf[3*i+2])<<16 | ||
|  | 			if pl > partLens[d.nOP-1] { | ||
|  | 				return io.ErrUnexpectedEOF | ||
|  | 			} | ||
|  | 			partLens[i] = pl | ||
|  | 			partLens[d.nOP-1] -= pl | ||
|  | 		} | ||
|  | 	} | ||
|  | 
 | ||
|  | 	// We check if the final partition length can also fit into a 24-bit uint. | ||
|  | 	// Strictly speaking, this isn't part of the spec, but it guards against a | ||
|  | 	// malicious WEBP image that is too large to ReadFull the encoded DCT | ||
|  | 	// coefficients into memory, whether that's because the actual WEBP file is | ||
|  | 	// too large, or whether its RIFF metadata lists too large a chunk. | ||
|  | 	if 1<<24 <= partLens[d.nOP-1] { | ||
|  | 		return errors.New("vp8: too much data to decode") | ||
|  | 	} | ||
|  | 
 | ||
|  | 	buf := make([]byte, d.r.n) | ||
|  | 	if err := d.r.ReadFull(buf); err != nil { | ||
|  | 		return err | ||
|  | 	} | ||
|  | 	for i, pl := range partLens { | ||
|  | 		if i == d.nOP { | ||
|  | 			break | ||
|  | 		} | ||
|  | 		d.op[i].init(buf[:pl]) | ||
|  | 		buf = buf[pl:] | ||
|  | 	} | ||
|  | 	return nil | ||
|  | } | ||
|  | 
 | ||
|  | // parseOtherHeaders parses header information other than the frame header. | ||
|  | func (d *Decoder) parseOtherHeaders() error { | ||
|  | 	// Initialize and parse the first partition. | ||
|  | 	firstPartition := make([]byte, d.frameHeader.FirstPartitionLen) | ||
|  | 	if err := d.r.ReadFull(firstPartition); err != nil { | ||
|  | 		return err | ||
|  | 	} | ||
|  | 	d.fp.init(firstPartition) | ||
|  | 	if d.frameHeader.KeyFrame { | ||
|  | 		// Read and ignore the color space and pixel clamp values. They are | ||
|  | 		// specified in section 9.2, but are unimplemented. | ||
|  | 		d.fp.readBit(uniformProb) | ||
|  | 		d.fp.readBit(uniformProb) | ||
|  | 	} | ||
|  | 	d.parseSegmentHeader() | ||
|  | 	d.parseFilterHeader() | ||
|  | 	if err := d.parseOtherPartitions(); err != nil { | ||
|  | 		return err | ||
|  | 	} | ||
|  | 	d.parseQuant() | ||
|  | 	if !d.frameHeader.KeyFrame { | ||
|  | 		// Golden and AltRef frames are specified in section 9.7. | ||
|  | 		// TODO(nigeltao): implement. Note that they are only used for video, not still images. | ||
|  | 		return errors.New("vp8: Golden / AltRef frames are not implemented") | ||
|  | 	} | ||
|  | 	// Read and ignore the refreshLastFrameBuffer bit, specified in section 9.8. | ||
|  | 	// It applies only to video, and not still images. | ||
|  | 	d.fp.readBit(uniformProb) | ||
|  | 	d.parseTokenProb() | ||
|  | 	d.useSkipProb = d.fp.readBit(uniformProb) | ||
|  | 	if d.useSkipProb { | ||
|  | 		d.skipProb = uint8(d.fp.readUint(uniformProb, 8)) | ||
|  | 	} | ||
|  | 	if d.fp.unexpectedEOF { | ||
|  | 		return io.ErrUnexpectedEOF | ||
|  | 	} | ||
|  | 	return nil | ||
|  | } | ||
|  | 
 | ||
|  | // DecodeFrame decodes the frame and returns it as an YCbCr image. | ||
|  | // The image's contents are valid up until the next call to Decoder.Init. | ||
|  | func (d *Decoder) DecodeFrame() (*image.YCbCr, error) { | ||
|  | 	d.ensureImg() | ||
|  | 	if err := d.parseOtherHeaders(); err != nil { | ||
|  | 		return nil, err | ||
|  | 	} | ||
|  | 	// Reconstruct the rows. | ||
|  | 	for mbx := 0; mbx < d.mbw; mbx++ { | ||
|  | 		d.upMB[mbx] = mb{} | ||
|  | 	} | ||
|  | 	for mby := 0; mby < d.mbh; mby++ { | ||
|  | 		d.leftMB = mb{} | ||
|  | 		for mbx := 0; mbx < d.mbw; mbx++ { | ||
|  | 			skip := d.reconstruct(mbx, mby) | ||
|  | 			fs := d.filterParams[d.segment][btou(!d.usePredY16)] | ||
|  | 			fs.inner = fs.inner || !skip | ||
|  | 			d.perMBFilterParams[d.mbw*mby+mbx] = fs | ||
|  | 		} | ||
|  | 	} | ||
|  | 	if d.fp.unexpectedEOF { | ||
|  | 		return nil, io.ErrUnexpectedEOF | ||
|  | 	} | ||
|  | 	for i := 0; i < d.nOP; i++ { | ||
|  | 		if d.op[i].unexpectedEOF { | ||
|  | 			return nil, io.ErrUnexpectedEOF | ||
|  | 		} | ||
|  | 	} | ||
|  | 	// Apply the loop filter. | ||
|  | 	// | ||
|  | 	// Even if we are using per-segment levels, section 15 says that "loop | ||
|  | 	// filtering must be skipped entirely if loop_filter_level at either the | ||
|  | 	// frame header level or macroblock override level is 0". | ||
|  | 	if d.filterHeader.level != 0 { | ||
|  | 		if d.filterHeader.simple { | ||
|  | 			d.simpleFilter() | ||
|  | 		} else { | ||
|  | 			d.normalFilter() | ||
|  | 		} | ||
|  | 	} | ||
|  | 	return d.img, nil | ||
|  | } |