image: Index | Examples | Files

package riff

import ""

Package riff implements the Resource Interchange File Format, used by media formats such as AVI, WAVE and WEBP.

A RIFF stream contains a sequence of chunks. Each chunk consists of an 8-byte header (containing a 4-byte chunk type and a 4-byte chunk length), the chunk data (presented as an io.Reader), and some padding bytes.

A detailed description of the format is at



Package Files



var LIST = FourCC{'L', 'I', 'S', 'T'}

LIST is the "LIST" FourCC.

func NewListReader Uses

func NewListReader(chunkLen uint32, chunkData io.Reader) (listType FourCC, data *Reader, err error)

NewListReader returns a LIST chunk's list type, such as "movi" or "wavl", and its chunks as a *Reader.

func NewReader Uses

func NewReader(r io.Reader) (formType FourCC, data *Reader, err error)

NewReader returns the RIFF stream's form type, such as "AVI " or "WAVE", and its chunks as a *Reader.

type FourCC Uses

type FourCC [4]byte

FourCC is a four character code.

type Reader Uses

type Reader struct {
    // contains filtered or unexported fields

Reader reads chunks from an underlying io.Reader.


package main

import (


func main() {
    formType, r, err := riff.NewReader(strings.NewReader(data))
    if err != nil {
    fmt.Printf("RIFF(%s)\n", formType)
    if err := dump(r, ".\t"); err != nil {

func dump(r *riff.Reader, indent string) error {
    for {
        chunkID, chunkLen, chunkData, err := r.Next()
        if err == io.EOF {
            return nil
        if err != nil {
            return err
        if chunkID == riff.LIST {
            listType, list, err := riff.NewListReader(chunkLen, chunkData)
            if err != nil {
                return err
            fmt.Printf("%sLIST(%s)\n", indent, listType)
            if err := dump(list, indent+".\t"); err != nil {
                return err
        b, err := ioutil.ReadAll(chunkData)
        if err != nil {
            return err
        fmt.Printf("%s%s %q\n", indent, chunkID, b)

func encodeU32(u uint32) string {
    return string([]byte{
        byte(u >> 0),
        byte(u >> 8),
        byte(u >> 16),
        byte(u >> 24),

func encode(chunkID, contents string) string {
    n := len(contents)
    if n&1 == 1 {
        contents += "\x00"
    return chunkID + encodeU32(uint32(n)) + contents

func encodeMulti(typ0, typ1 string, chunks ...string) string {
    n := 4
    for _, c := range chunks {
        n += len(c)
    s := typ0 + encodeU32(uint32(n)) + typ1
    for _, c := range chunks {
        s += c
    return s

var (
    d0   = encode("ZERO", "")
    d1   = encode("ONE ", "a")
    d2   = encode("TWO ", "bc")
    d3   = encode("THRE", "def")
    d4   = encode("FOUR", "ghij")
    d5   = encode("FIVE", "klmno")
    d6   = encode("SIX ", "pqrstu")
    l0   = encodeMulti("LIST", "GOOD", d1, d5)
    l1   = encodeMulti("LIST", "BAD ", d3)
    l2   = encodeMulti("LIST", "UGLY", d4, d6)
    l01  = encodeMulti("LIST", "META", l0, d0, l1)
    data = encodeMulti("RIFF", "ROOT", d0, d1, l01, d2, l2)

func (*Reader) Next Uses

func (z *Reader) Next() (chunkID FourCC, chunkLen uint32, chunkData io.Reader, err error)

Next returns the next chunk's ID, length and data. It returns io.EOF if there are no more chunks. The io.Reader returned becomes stale after the next Next call, and should no longer be used.

It is valid to call Next even if all of the previous chunk's data has not been read.

Package riff imports 4 packages (graph) and is imported by 7 packages. Updated 2020-12-09. Refresh now. Tools for package owners.