Help us shape the future of Go! Take the 2026 Go Developer Survey

vp9

package module
v0.2.2 Latest Latest
Warning

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

Go to latest
Published: Oct 31, 2026 License: BSD-3-Clause Imports: 2 Imported by: 0

README

vp9

Pure-Go (CGO=0) reader for the parts of a VP9 bitstream that are plain bit fields: the uncompressed frame header, and the superframe index that packs several frames into one sample.

frames, err := vp9.SplitSuperframe(packet)   // one sample may hold several
h, err := vp9.ParseHeader(frames[0])         // profile, size, show_frame, …

What it is not

It does not decode frames. There is no boolean arithmetic coder, no probability model, no residual, no prediction and no reconstruction — nothing here turns a bitstream into pixels.

ParseHeader stops at the frame size on purpose, and the reason is in the format: everything after it is either arithmetic-coded or of no use to a caller describing a track. Stopping there keeps this readable against the one part of VP9 that is plain bit fields.

The description on this repository used to say "bitstream reader and decoder". It was wrong, and that matters more than it looks: a description is what a search answers with, so a wrong one sends the next person to read the code before they find out. The arithmetic coder the format needs lives in go-avkit/boolcoder.

What is in it

SplitSuperframe the superframe index, so one sample yields its frames
ParseHeader, Header the uncompressed header: profile, show_existing_frame, frame type, show_frame, colour, and both the coded and the render size

Both the coded size and the render size are kept, because they differ: what a frame is coded at is not always what it should be displayed at.

Windows, macOS, Linux; six 64-bit architectures. 100% statement coverage, gated in CI.

Licence

BSD-3-Clause.

Documentation

Overview

Package vp9 reads a VP9 bitstream in pure Go, with no libvpx or ffmpeg linkage and no external binaries.

It begins with the uncompressed header, which is where VP9 states what a container does not: Matroska and MP4 carry no VP9 profile or level, so the frames are the only place either can be read from. That is why this exists before any decoding does -- a muxer needs the profile, the bit depth, the chroma subsampling and the frame size to write a usable vpcC record, and every one of them is in the first few dozen bits of a key frame.

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrNotVP9 means the frame does not begin with VP9's frame marker.
	ErrNotVP9 = errors.New("vp9: not a VP9 frame")
	// ErrSyncCode means a key frame's sync code is not the one VP9 states.
	ErrSyncCode = errors.New("vp9: wrong sync code")
	// ErrReserved means a bit the format reserves was set.
	ErrReserved = errors.New("vp9: reserved bit set")
	// ErrProfile means a profile and a colour description contradict each
	// other: 4:2:0 cannot be stated in profile 1 or 3, and 4:4:4 cannot be
	// stated in profile 0 or 2.
	ErrProfile = errors.New("vp9: colour description contradicts the profile")
)

Errors a header can be refused with.

View Source
var ErrShort = errors.New("vp9: bitstream ends inside a field")

ErrShort means the bitstream ended in the middle of a field.

View Source
var ErrSuperframe = errors.New("vp9: superframe index is inconsistent")

ErrSuperframe means a packet carries an index that describes itself wrongly.

Functions

func SplitSuperframe

func SplitSuperframe(packet []byte) ([][]byte, error)

SplitSuperframe returns the frames a VP9 packet holds.

A packet usually holds one frame and is handed back unchanged. It may instead be a superframe: several frames followed by an index that states how long each one is, which is how an encoder ships a frame nobody shows -- an alternate reference -- together with the frame that does show.

⛔ A packet whose last byte merely LOOKS like an index byte is handed back whole rather than refused. Three bits of pattern in one byte happen by chance, and an ordinary frame ending in such a byte is a frame, not a broken superframe: the index describes itself completely enough to say which it is, so the answer is taken from the arithmetic and not from the pattern. What the arithmetic requires is that the first and last bytes of the index agree and that the sizes account for exactly the bytes before it -- checked here, and the reason a coincidence cannot be mistaken for an index.

Types

type Header struct {
	Profile        uint8 // 0 to 3
	Key            bool  // A key frame states its own description.
	Show           bool  // The frame is shown rather than only decoded.
	ErrorResilient bool
	ShowExisting   bool  // The frame only repeats one already decoded.
	ExistingFrame  uint8 // Which one, when ShowExisting.
	BitDepth       uint8 // 8, 10 or 12
	ColorSpace     uint8 // 0 to 7, as ISO/IEC 23001-8 numbers them
	FullRange      bool
	SubsamplingX   uint8 // 1 means the chroma planes are half as wide
	SubsamplingY   uint8
	Width          uint16
	Height         uint16
	RenderWidth    uint16 // The size to display at, which may differ.
	RenderHeight   uint16
}

Header is what a VP9 frame's uncompressed header states.

Only a key frame states the whole of it: a later frame either refers to a frame already decoded or repeats one, and takes its description from there. So a caller that needs a track's description reads the FIRST key frame, and Key says whether it got one.

func ParseHeader

func ParseHeader(frame []byte) (Header, error)

ParseHeader reads the uncompressed header at the start of one VP9 frame.

It reads no further than it needs: everything after the frame size is either arithmetic-coded or of no use to a caller describing a track, and stopping here keeps this readable against the one part of the format that is plain bit fields.

Jump to

Keyboard shortcuts

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